mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-12-26 08:38:54 +01:00
fixed server-side valdation of autorepeated rows/columns
had to change signature of validate function to get information for autorepeating through removed entity-encoding of square brackets, as they mess up validiation (havnt found any negative effects so far)
This commit is contained in:
parent
a4b71c7d3a
commit
0d66dd98b7
@ -215,7 +215,10 @@ class etemplate_new extends etemplate_widget_template
|
||||
throw new egw_exception_wrong_parameter('Can NOT read template '.array2string(self::$request->template));
|
||||
}
|
||||
$validated = array();
|
||||
$template->run('validate', array('', $content, &$validated), true); // $respect_disabled=true: do NOT validate disabled widgets and children
|
||||
$expand = array(
|
||||
'cont' => &self::$request->content,
|
||||
);
|
||||
$template->run('validate', array('', $expand, $content, &$validated), true); // $respect_disabled=true: do NOT validate disabled widgets and children
|
||||
|
||||
if (self::validation_errors(self::$request->ignore_validation))
|
||||
{
|
||||
@ -251,7 +254,10 @@ class etemplate_new extends etemplate_widget_template
|
||||
translation::add_app($GLOBALS['egw_info']['flags']['currentapp']);
|
||||
|
||||
$validated = array();
|
||||
$template->run('validate', array('', $content, &$validated), true); // $respect_disabled=true: do NOT validate disabled widgets and children
|
||||
$expand = array(
|
||||
'cont' => &self::$request->content,
|
||||
);
|
||||
$template->run('validate', array('', $expand, $content, &$validated), true); // $respect_disabled=true: do NOT validate disabled widgets and children
|
||||
if (self::validation_errors(self::$request->ignore_validation))
|
||||
{
|
||||
error_log(__METHOD__."(,".array2string($content).') validation_errors='.array2string(self::$validation_errors));
|
||||
|
@ -155,7 +155,11 @@ class etemplate_widget
|
||||
{
|
||||
if ($reader->name != 'id' && $template->attr[$reader->name] != $reader->value)
|
||||
{
|
||||
if (!$cloned) $template = clone($this);
|
||||
if (!$cloned)
|
||||
{
|
||||
$template = clone($this);
|
||||
$cloned = true; // only clone it once, otherwise we loose attributes!
|
||||
}
|
||||
$template->attrs[$reader->name] = $reader->value;
|
||||
|
||||
// split legacy options
|
||||
@ -326,16 +330,23 @@ class etemplate_widget
|
||||
* Default implementation only calls method on itself and run on all children
|
||||
*
|
||||
* @param string $method_name
|
||||
* @param array $params=array('') parameter(s) first parameter has to be the cname!
|
||||
* @param array $params=array('') parameter(s) first parameter has to be the cname, second $expand!
|
||||
* @param boolean $respect_disabled=false false (default): ignore disabled, true: method is NOT run for disabled widgets AND their children
|
||||
*/
|
||||
public function run($method_name, $params=array(''), $respect_disabled=false)
|
||||
{
|
||||
// maintain $expand array name-expansion
|
||||
$cname = $params[0];
|
||||
$expand =& $params[1];
|
||||
if ($expand['cname'] !== $cname)
|
||||
{
|
||||
$expand['cont'] =& self::get_array(self::$request->content, $cname);
|
||||
$expand['cname'] = $cname;
|
||||
}
|
||||
if ($respect_disabled && ($disabled = $this->attrs['disabled']))
|
||||
{
|
||||
// check if disabled contains @ or !
|
||||
$cname = $params[0];
|
||||
$disabled = self::check_disabled($disabled, $cname ? self::get_array(self::$request->content, $cname) : self::$request->content);
|
||||
$disabled = self::check_disabled($disabled, $expand);
|
||||
if ($disabled)
|
||||
{
|
||||
error_log(__METHOD__."('$method_name', ".array2string($params).', '.array2string($respect_disabled).") $this disabled='{$this->attrs['disabled']}'='$disabled': NOT running");
|
||||
@ -360,12 +371,10 @@ class etemplate_widget
|
||||
* if no =check is given all set non-empty and non-zero strings are true (standard php behavior)
|
||||
*
|
||||
* @param string $disabled expression to check, eg. "!@var" for !$content['var']
|
||||
* @param array $content the content-array in the context of the grid
|
||||
* @param int $row=null to be able to use $row or $row_content in value of checks
|
||||
* @param int $c=null to be able to use $row or $row_content in value of checks
|
||||
* @param array $expand values for keys 'c', 'row', 'c_', 'row_', 'cont'
|
||||
* @return boolean true if the row/col is disabled or false if not
|
||||
*/
|
||||
protected static function check_disabled($disabled,$content,$row=null,$c=null)
|
||||
protected static function check_disabled($disabled, array $expland)
|
||||
{
|
||||
if ($not = $disabled[0] == '!')
|
||||
{
|
||||
@ -374,8 +383,8 @@ class etemplate_widget
|
||||
list($val,$check_val) = $vals = explode('=',$disabled);
|
||||
|
||||
// use expand_name to be able to use @ or $
|
||||
$val = self::expand_name($val,$c,$row,'','',$content);
|
||||
$check_val = self::expand_name($check_val,$c,$row,'','',$content);
|
||||
$val = self::expand_name($val,$expand['c'], $expand['row'], $expand['c_'], $expand['row_'], $expand['cont']);
|
||||
$check_val = self::expand_name($check_val,$expand['c'], $expand['row'], $expand['c_'], $expand['row_'], $expand['cont']);
|
||||
$result = count($vals) == 1 ? $val != '' : ($check_val[0] == '/' ? preg_match($check_val,$val) : $val == $check_val);
|
||||
if ($not) $result = !$result;
|
||||
|
||||
@ -428,11 +437,13 @@ class etemplate_widget
|
||||
$cont = array();
|
||||
}
|
||||
if (!is_numeric($c)) $c = boetemplate::chrs2num($c);
|
||||
$col = boetemplate::num2chrs($c-1); // $c-1 to get: 0:'@', 1:'A', ...
|
||||
$col_ = boetemplate::num2chrs($c_-1);
|
||||
$col = self::num2chrs($c-1); // $c-1 to get: 0:'@', 1:'A', ...
|
||||
$col_ = self::num2chrs($c_-1);
|
||||
$row_cont = $cont[$row];
|
||||
$col_row_cont = $cont[$col.$row];
|
||||
|
||||
/* RB: dont think any of this is needed in eTemplate2, as this escaping probably needs to be done on clientside anyway
|
||||
|
||||
// check if name is enclosed in single quotes as argument eg. to an event handler or
|
||||
// variable name is contained in quotes and curly brackets, eg. "'{$cont[nm][path]}'" or
|
||||
// used as name for a button like "delete[$row_cont[something]]" --> quote contained quotes (' or ")
|
||||
@ -471,7 +482,7 @@ class etemplate_widget
|
||||
$value = str_replace('&',urlencode('&'),$value);
|
||||
$name = str_replace($matches[3],$value,$name);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
eval('$name = "'.str_replace('"','\\"',$name).'";');
|
||||
}
|
||||
if ($is_index_in_content)
|
||||
@ -485,10 +496,30 @@ class etemplate_widget
|
||||
$name = self::get_array($cont,substr($name,1));
|
||||
}
|
||||
}
|
||||
$name = str_replace(array('[',']'),array('[',']'),$name);
|
||||
// RB: not sure why this business with entity encoding for square brakets, it messes up validation
|
||||
//$name = str_replace(array('[',']'),array('[',']'),$name);
|
||||
return $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* generates column-names from index: 'A', 'B', ..., 'AA', 'AB', ..., 'ZZ' (not more!)
|
||||
*
|
||||
* @param int $num numerical index to generate name from 1 => 'A'
|
||||
* @return string the name
|
||||
*/
|
||||
static function num2chrs($num)
|
||||
{
|
||||
$min = ord('A');
|
||||
$max = ord('Z') - $min + 1;
|
||||
if ($num >= $max)
|
||||
{
|
||||
$chrs = chr(($num / $max) + $min - 1);
|
||||
}
|
||||
$chrs .= chr(($num % $max) + $min);
|
||||
|
||||
return $chrs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert object to string
|
||||
*
|
||||
@ -543,10 +574,15 @@ class etemplate_widget
|
||||
*
|
||||
* @param string $cname basename
|
||||
* @param string $name name
|
||||
* @param array $expand=null values for keys 'c', 'row', 'c_', 'row_', 'cont'
|
||||
* @return string complete form-name
|
||||
*/
|
||||
static function form_name($cname,$name)
|
||||
static function form_name($cname,$name,array $expand=null)
|
||||
{
|
||||
if ($expand && !empty($name))
|
||||
{
|
||||
$name = self::expand_name($name, $expand['c'], $expand['row'], $expand['c_'], $expand['row_'], $expand['cont']);
|
||||
}
|
||||
if (count($name_parts = explode('[', $name, 2)) > 1)
|
||||
{
|
||||
$name_parts = array_merge(array($name_parts[0]), explode('][', substr($name_parts[1],0,-1)));
|
||||
@ -558,7 +594,9 @@ class etemplate_widget
|
||||
$form_name = array_shift($name_parts);
|
||||
if (count($name_parts))
|
||||
{
|
||||
$form_name .= '['.implode('][',$name_parts).']';
|
||||
// RB: not sure why this business with entity encoding for square brakets, it messes up validation
|
||||
//$form_name .= '['.implode('][',$name_parts).']';
|
||||
$form_name .= '['.implode('][',$name_parts).']';
|
||||
}
|
||||
return $form_name;
|
||||
}
|
||||
@ -615,12 +653,19 @@ class etemplate_widget
|
||||
* - $readonlys[__ALL__] set and $readonlys[$form_name] !== false
|
||||
* - $readonlys[$form_name] evaluates to true
|
||||
*
|
||||
* @param string $cname=''
|
||||
* @param string $form_name=null form_name, to not calculate him again
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_readonly($cname='')
|
||||
public function is_readonly($cname='', $form_name=null)
|
||||
{
|
||||
$form_name = self::form_name($cname, $this->id);
|
||||
|
||||
if (!isset($form_name))
|
||||
{
|
||||
$expand = array(
|
||||
'cont' => self::get_array(self::$request->content, $cname),
|
||||
);
|
||||
$form_name = self::form_name($cname, $this->id, $expand);
|
||||
}
|
||||
$readonly = $this->attrs['readonly'] || self::$request->readonlys[$form_name] ||
|
||||
isset(self::$request->readonlys['__ALL__']) && self::$request->readonlys[$form_name] !== false;
|
||||
|
||||
@ -767,7 +812,7 @@ class etemplate_widget_box extends etemplate_widget
|
||||
{
|
||||
$cname =& $params[0];
|
||||
$old_cname = $params[0];
|
||||
if ($this->id) $cname = self::form_name($cname, $this->id);
|
||||
if ($this->id) $cname = self::form_name($cname, $this->id, $params[1]);
|
||||
|
||||
parent::run($method_name, $params, $respect_disabled);
|
||||
$params[0] = $old_cname;
|
||||
|
@ -17,20 +17,23 @@
|
||||
class etemplate_widget_button extends etemplate_widget
|
||||
{
|
||||
/**
|
||||
* Validate input
|
||||
* Validate buttons
|
||||
*
|
||||
* Readonly buttons can NOT be pressed
|
||||
* Readonly buttons can NOT be pressed!
|
||||
*
|
||||
* @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
|
||||
* @return boolean true if no validation error, false otherwise
|
||||
*/
|
||||
public function validate($cname, array $content, &$validated=array())
|
||||
public function validate($cname, array $expand, array $content, &$validated=array())
|
||||
{
|
||||
$form_name = self::form_name($cname, $this->id);
|
||||
$form_name = self::form_name($cname, $this->id, $expand);
|
||||
//error_log(__METHOD__."('$cname', ".array2string($expand).", ...) $this: get_array(\$content, '$form_name')=".array2string(self::get_array($content, $form_name)));
|
||||
|
||||
if (self::get_array($content, $form_name) && !$this->is_readonly($cname))
|
||||
// need to check === true, as get_array() ignores a "[]" postfix and returns array() eg. for a not existing $row_cont[id] in "delete[$row_cont[id]]"
|
||||
if (!$this->is_readonly($cname, $form_name) && self::get_array($content, $form_name) === true)
|
||||
{
|
||||
$valid =& self::get_array($validated, $form_name, true);
|
||||
$valid = 'pressed'; // that's what it was in old etemplate
|
||||
|
@ -35,20 +35,21 @@ class etemplate_widget_checkbox extends etemplate_widget
|
||||
* Same is true for the radio buttons of a radio-group sharing the same name.
|
||||
*
|
||||
* @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
|
||||
* @return boolean true if no validation error, false otherwise
|
||||
*/
|
||||
public function validate($cname, array $content, &$validated=array())
|
||||
public function validate($cname, array $expand, array $content, &$validated=array())
|
||||
{
|
||||
$form_name = self::form_name($cname, $this->id);
|
||||
$form_name = self::form_name($cname, $this->id, $expand);
|
||||
|
||||
if (($multiple = substr($form_name, -2) == '[]') && $this->type == 'checkbox')
|
||||
{
|
||||
$form_name = substr($form_name, 0, -2);
|
||||
}
|
||||
|
||||
if (!$this->is_readonly($cname))
|
||||
if (!$this->is_readonly($cname, $form_name))
|
||||
{
|
||||
$value = self::get_array($content, $form_name);
|
||||
$valid =& self::get_array($validated, $form_name, true);
|
||||
|
@ -50,7 +50,7 @@ class etemplate_widget_customfields extends etemplate_widget_transformer
|
||||
* @var $prefix string Prefix for every custiomfield name returned in $content (# for general (admin) customfields)
|
||||
*/
|
||||
protected static $prefix = '#';
|
||||
|
||||
|
||||
// Make settings available globally
|
||||
const GLOBAL_VALS = '~custom_fields~';
|
||||
|
||||
@ -210,24 +210,26 @@ class etemplate_widget_customfields extends etemplate_widget_transformer
|
||||
* - 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
|
||||
*/
|
||||
public function validate($cname, array $content, &$validated=array())
|
||||
public function validate($cname, array $expand, array $content, &$validated=array())
|
||||
{
|
||||
if (!$this->is_readonly($cname))
|
||||
if ($this->id)
|
||||
{
|
||||
if($this->id)
|
||||
{
|
||||
$form_name = self::form_name($cname, $this->id);
|
||||
}
|
||||
else
|
||||
{
|
||||
$form_name = self::GLOBAL_ID;
|
||||
}
|
||||
$form_name = self::form_name($cname, $this->id, $expand);
|
||||
}
|
||||
else
|
||||
{
|
||||
$form_name = self::GLOBAL_ID;
|
||||
}
|
||||
|
||||
if (!$this->is_readonly($cname, $form_name))
|
||||
{
|
||||
$value_in = self::get_array($content, $form_name);
|
||||
if(is_array($value_in)) {
|
||||
if(is_array($value_in))
|
||||
{
|
||||
foreach($value_in as $field => $value)
|
||||
{
|
||||
if ((string)$value === '' && $this->attrs['needed'])
|
||||
@ -235,7 +237,7 @@ class etemplate_widget_customfields extends etemplate_widget_transformer
|
||||
self::set_validation_error($form_name,lang('Field must not be empty !!!'),'');
|
||||
}
|
||||
$valid =& self::get_array($validated, $this->id ? $form_name : $field, true);
|
||||
|
||||
|
||||
$valid = is_array($value) ? implode(',',$value) : $value;
|
||||
error_log(__METHOD__."() $form_name $field: ".array2string($value).' --> '.array2string($value));
|
||||
}
|
||||
|
@ -47,16 +47,17 @@ class etemplate_widget_date extends etemplate_widget_transformer
|
||||
* Validate input
|
||||
*
|
||||
* @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
|
||||
* @return boolean true if no validation error, false otherwise
|
||||
*/
|
||||
public function validate($cname, array $content, &$validated=array())
|
||||
public function validate($cname, array $expand, array $content, &$validated=array())
|
||||
{
|
||||
if (!$this->is_readonly($cname) && $this->type != 'date-since') // date-since is always readonly
|
||||
{
|
||||
$form_name = self::form_name($cname, $this->id);
|
||||
$form_name = self::form_name($cname, $this->id, $expand);
|
||||
|
||||
if (!$this->is_readonly($cname, $form_name) && $this->type != 'date-since') // date-since is always readonly
|
||||
{
|
||||
$value = self::get_array($content, $form_name);
|
||||
$valid =& self::get_array($validated, $form_name, true);
|
||||
|
||||
|
@ -17,8 +17,13 @@
|
||||
*/
|
||||
class etemplate_widget_file extends etemplate_widget
|
||||
{
|
||||
|
||||
public function __construct($xml='') {
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $xml
|
||||
*/
|
||||
public function __construct($xml='')
|
||||
{
|
||||
if($xml) parent::__construct($xml);
|
||||
|
||||
// Legacy multiple - id ends in []
|
||||
@ -29,15 +34,15 @@ class etemplate_widget_file extends etemplate_widget
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax callback to receive an incoming file
|
||||
*
|
||||
* The incoming file is moved from its temporary location (otherwise server will delete it) and
|
||||
* the file information is stored into the widget's value. When the form is submitted, the information for all
|
||||
* files uploaded is available in the returned $content array. Because files are uploaded asynchronously,
|
||||
* submission should be quick.
|
||||
*
|
||||
* @note Currently, no attempt is made to clean up files automatically.
|
||||
*/
|
||||
* Ajax callback to receive an incoming file
|
||||
*
|
||||
* The incoming file is moved from its temporary location (otherwise server will delete it) and
|
||||
* the file information is stored into the widget's value. When the form is submitted, the information for all
|
||||
* files uploaded is available in the returned $content array. Because files are uploaded asynchronously,
|
||||
* submission should be quick.
|
||||
*
|
||||
* @note Currently, no attempt is made to clean up files automatically.
|
||||
*/
|
||||
public static function ajax_upload() {
|
||||
$response = egw_json_response::get();
|
||||
$request_id = str_replace(' ', '+', rawurldecode($_REQUEST['request_id']));
|
||||
@ -48,11 +53,11 @@ class etemplate_widget_file extends etemplate_widget
|
||||
}
|
||||
|
||||
if (!($template = etemplate_widget_template::instance(self::$request->template['name'], self::$request->template['template_set'],
|
||||
self::$request->template['version'], self::$request->template['load_via'])))
|
||||
{
|
||||
self::$request->template['version'], self::$request->template['load_via'])))
|
||||
{
|
||||
// Can't use callback
|
||||
error_log("Could not get template for file upload, callback skipped");
|
||||
}
|
||||
}
|
||||
|
||||
$file_data = array();
|
||||
|
||||
@ -146,42 +151,47 @@ class etemplate_widget_file extends etemplate_widget
|
||||
* Merge any already uploaded files into the content array
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
public function validate($cname, array $content, &$validated=array())
|
||||
public function validate($cname, array $expand, array $content, &$validated=array())
|
||||
{
|
||||
$form_name = self::form_name($cname, $this->id);
|
||||
$value = $value_in = self::get_array($content, $form_name);
|
||||
$valid =& self::get_array($validated, $form_name, true);
|
||||
$form_name = self::form_name($cname, $this->id, $expand);
|
||||
|
||||
if(!is_array($value)) $value = array();
|
||||
|
||||
// Incoming values indexed by temp name
|
||||
if($value[0]) $value = $value[0];
|
||||
|
||||
foreach($value as $tmp => $file)
|
||||
if (!$this->is_readonly($cname, $form_name))
|
||||
{
|
||||
if (is_dir($GLOBALS['egw_info']['server']['temp_dir']) && is_writable($GLOBALS['egw_info']['server']['temp_dir']))
|
||||
{
|
||||
$path = $GLOBALS['egw_info']['server']['temp_dir'].'/'.$tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
$path = $tmp.'+';
|
||||
}
|
||||
$stat = stat($path);
|
||||
$valid[] = array(
|
||||
'name' => $file['name'],
|
||||
'type' => $file['type'],
|
||||
'tmp_name' => $path,
|
||||
'error' => UPLOAD_ERR_OK, // Always OK if we get this far
|
||||
'size' => $stat['size'],
|
||||
'ip' => $_SERVER['REMOTE_ADDR'], // Assume it's the same as for when it was uploaded...
|
||||
);
|
||||
}
|
||||
$value = $value_in = self::get_array($content, $form_name);
|
||||
$valid =& self::get_array($validated, $form_name, true);
|
||||
|
||||
if($valid && !$this->attrs['multiple']) $valid = $valid[0];
|
||||
if(!is_array($value)) $value = array();
|
||||
|
||||
// Incoming values indexed by temp name
|
||||
if($value[0]) $value = $value[0];
|
||||
|
||||
foreach($value as $tmp => $file)
|
||||
{
|
||||
if (is_dir($GLOBALS['egw_info']['server']['temp_dir']) && is_writable($GLOBALS['egw_info']['server']['temp_dir']))
|
||||
{
|
||||
$path = $GLOBALS['egw_info']['server']['temp_dir'].'/'.$tmp;
|
||||
}
|
||||
else
|
||||
{
|
||||
$path = $tmp.'+';
|
||||
}
|
||||
$stat = stat($path);
|
||||
$valid[] = array(
|
||||
'name' => $file['name'],
|
||||
'type' => $file['type'],
|
||||
'tmp_name' => $path,
|
||||
'error' => UPLOAD_ERR_OK, // Always OK if we get this far
|
||||
'size' => $stat['size'],
|
||||
'ip' => $_SERVER['REMOTE_ADDR'], // Assume it's the same as for when it was uploaded...
|
||||
);
|
||||
}
|
||||
|
||||
if($valid && !$this->attrs['multiple']) $valid = $valid[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
etemplate_widget::registerWidget('etemplate_widget_file', array('file'));
|
||||
|
@ -13,6 +13,28 @@
|
||||
|
||||
/**
|
||||
* eTemplate grid widget incl. row(s) and column(s)
|
||||
*
|
||||
* Example of a grid containing 3 columns and 2 rows (last one autorepeated)
|
||||
*
|
||||
* <grid>
|
||||
* <columns>
|
||||
* <column>
|
||||
* <column width="75%">
|
||||
* <column disabled="@no_actions">
|
||||
* </columns>
|
||||
* <rows>
|
||||
* <row>
|
||||
* <description value="ID" />
|
||||
* <description value="Text" />
|
||||
* <description value="Action" />
|
||||
* <row>
|
||||
* <row>
|
||||
* <description id="${row}[id]" />
|
||||
* <textbox id="${row}[text]" />
|
||||
* <button id="delete[$row_cont[id]]" value="Delete" />
|
||||
* </row>
|
||||
* </rows>
|
||||
* </grid>
|
||||
*/
|
||||
class etemplate_widget_grid extends etemplate_widget_box
|
||||
{
|
||||
@ -29,29 +51,39 @@ class etemplate_widget_grid extends etemplate_widget_box
|
||||
* Run a given method on all children
|
||||
*
|
||||
* Reimplemented to implement column based disabling:
|
||||
* - added 4th var-parameter to hold key of disabled column
|
||||
* - added 5th var-parameter to hold key of disabled column
|
||||
* - if a column is disabled run returns false and key get added by columns run to $columns_disabled
|
||||
* - row run method checks now for each child (arbitrary widget) if it the column's key is included in $columns_disabled
|
||||
* - as a grid can contain other grid's as direct child, we have to backup and initialise $columns_disabled in grid run!
|
||||
*
|
||||
* @param string $method_name
|
||||
* @param array $params=array('') parameter(s) first parameter has to be the cname!
|
||||
* @param array $params=array('') parameter(s) first parameter has to be the cname, second $expand!
|
||||
* @param boolean $respect_disabled=false false (default): ignore disabled, true: method is NOT run for disabled widgets AND their children
|
||||
* @param array $columns_disabled=array() disabled columns
|
||||
*/
|
||||
public function run($method_name, $params=array(''), $respect_disabled=false, &$columns_disabled=array())
|
||||
{
|
||||
// maintain $expand array name-expansion
|
||||
$cname =& $params[0];
|
||||
$expand =& $params[1];
|
||||
$old_cname = $params[0];
|
||||
if ($this->id) $cname = self::form_name($cname, $this->id, $expand);
|
||||
if ($expand['cname'] !== $cname)
|
||||
{
|
||||
$expand['cont'] =& self::get_array(self::$request->content, $cname);
|
||||
$expand['cname'] = $cname;
|
||||
}
|
||||
// as a grid can contain other grid's as direct child, we have to backup and initialise $columns_disabled
|
||||
if ($this->type == 'grid')
|
||||
{
|
||||
$backup_columns_disabled = $columns_disabled;
|
||||
$columns_disabled = array();
|
||||
}
|
||||
|
||||
if ($respect_disabled && ($disabled = $this->attrs['disabled']))
|
||||
{
|
||||
// check if disabled contains @ or !
|
||||
$cname = $params[0];
|
||||
$disabled = self::check_disabled($disabled, $cname ? self::get_array(self::$request->content, $cname) : self::$request->content);
|
||||
$disabled = self::check_disabled($disabled, $expand);
|
||||
if ($disabled)
|
||||
{
|
||||
error_log(__METHOD__."('$method_name', ".array2string($params).', '.array2string($respect_disabled).") $this disabled='{$this->attrs['disabled']}'='$disabled': NOT running");
|
||||
@ -62,8 +94,32 @@ class etemplate_widget_grid extends etemplate_widget_box
|
||||
{
|
||||
call_user_func_array(array($this, $method_name), $params);
|
||||
}
|
||||
foreach($this->children as $n => $child)
|
||||
//foreach($this->children as $n => $child)
|
||||
for($n = 0; ; ++$n)
|
||||
{
|
||||
// maintain $expand array name-expansion
|
||||
switch($this->type)
|
||||
{
|
||||
case 'rows':
|
||||
$expand['row'] = $n;
|
||||
break;
|
||||
case 'columns':
|
||||
$expand['c'] = $n;
|
||||
break;
|
||||
}
|
||||
if (isset($this->children[$n]))
|
||||
{
|
||||
$child = $this->children[$n];
|
||||
}
|
||||
// check if we need to autorepeat last row ($child)
|
||||
elseif (isset($child) && ($this->type == 'rows' || $this->type == 'columns') && $child->need_autorepeat($cname, $expand))
|
||||
{
|
||||
// not breaking repeats last row/column ($child)
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
if ($this->type == 'row')
|
||||
{
|
||||
if (in_array($n, $columns_disabled))
|
||||
@ -83,7 +139,53 @@ class etemplate_widget_grid extends etemplate_widget_box
|
||||
{
|
||||
$columns_disabled = $backup_columns_disabled;
|
||||
}
|
||||
$params[0] = $old_cname;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a row or column needs autorepeating, because still content left
|
||||
*
|
||||
* We only check direct children and grandchildren of first child (eg. box in first column)!
|
||||
*
|
||||
* @param string $cname
|
||||
* @param array $expand
|
||||
*/
|
||||
private function need_autorepeat($cname, array $expand)
|
||||
{
|
||||
// check id's of children
|
||||
foreach($this->children as $n => $direct_child)
|
||||
{
|
||||
foreach(array_merge(array($direct_child), $n ? array() : $direct_child->children) as $child)
|
||||
{
|
||||
$pat = $child->id;
|
||||
while(($pat = strstr($pat, '$')))
|
||||
{
|
||||
$pat = substr($pat,$pat[1] == '{' ? 2 : 1);
|
||||
|
||||
switch ($this->type)
|
||||
{
|
||||
case 'column':
|
||||
$Ok = $pat[0] == 'c' && !(substr($pat,0,4) == 'cont' || substr($pat,0,2) == 'c_' ||
|
||||
substr($pat,0,4) == 'col_');
|
||||
break;
|
||||
case 'row':
|
||||
$Ok = $pat[0] == 'r' && !(substr($pat,0,2) == 'r_' || substr($pat,0,4) == 'row_');
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
if ($Ok && ($value = self::get_array(self::$request->content,
|
||||
$fname=self::form_name($cname, $child->id, $expand))) !== false && isset($value))
|
||||
{
|
||||
//error_log(__METHOD__."('$method_name', ) $this autorepeating row $expand[row] because of $child->id = '$fname' is ".array2string($value));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
etemplate_widget::registerWidget('etemplate_widget_grid', array('grid', 'rows', 'row', 'columns', 'column'));
|
||||
|
@ -22,15 +22,16 @@ class etemplate_widget_htmlarea extends etemplate_widget
|
||||
* Input is run throught HTMLpurifier, to make sure users can NOT enter javascript or other nasty stuff (XSS!).
|
||||
*
|
||||
* @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
|
||||
* @return boolean true if no validation error, false otherwise
|
||||
*/
|
||||
public function validate($cname, array $content, &$validated=array())
|
||||
public function validate($cname, array $expand, array $content, &$validated=array())
|
||||
{
|
||||
$form_name = self::form_name($cname, $this->id);
|
||||
$form_name = self::form_name($cname, $this->id, $expand);
|
||||
|
||||
if (!$this->is_readonly($cname))
|
||||
if (!$this->is_readonly($cname, $form_name))
|
||||
{
|
||||
$value = self::get_array($content, $form_name);
|
||||
$valid =& self::get_array($validated, $form_name, true);
|
||||
|
@ -179,7 +179,7 @@ class etemplate_widget_link extends etemplate_widget
|
||||
$link['help'] = lang('Remove this link (not the entry itself)');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$response = egw_json_response::get();
|
||||
// Strip keys, unneeded and cause index problems on the client side
|
||||
$response->data(array_values($links));
|
||||
@ -201,15 +201,16 @@ class etemplate_widget_link extends etemplate_widget
|
||||
* - 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
|
||||
*/
|
||||
public function validate($cname, array $content, &$validated=array())
|
||||
public function validate($cname, array $expand, array $content, &$validated=array())
|
||||
{
|
||||
if (!$this->is_readonly($cname))
|
||||
{
|
||||
$form_name = self::form_name($cname, $this->id);
|
||||
$form_name = self::form_name($cname, $this->id, $expand);
|
||||
|
||||
if (!$this->is_readonly($cname, $form_name))
|
||||
{
|
||||
$value = $value_in =& self::get_array($content, $form_name);
|
||||
|
||||
// Look for files
|
||||
|
@ -65,15 +65,16 @@ class etemplate_widget_menupopup extends etemplate_widget
|
||||
* Validate input
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
public function validate($cname, array $content, &$validated=array())
|
||||
public function validate($cname, array $expand, array $content, &$validated=array())
|
||||
{
|
||||
$form_name = self::form_name($cname, $this->id);
|
||||
$form_name = self::form_name($cname, $this->id, $expand);
|
||||
|
||||
$ok = true;
|
||||
if (!$this->is_readonly($cname))
|
||||
if (!$this->is_readonly($cname, $form_name))
|
||||
{
|
||||
$value = $value_in = self::get_array($content, $form_name);
|
||||
|
||||
@ -131,7 +132,7 @@ class etemplate_widget_menupopup extends etemplate_widget
|
||||
self::setElementAttribute($form_name, 'no_lang', $no_lang);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Make sure s, etc. are properly encoded when sent, and not double-encoded
|
||||
foreach(self::$request->sel_options[$form_name] as &$label)
|
||||
{
|
||||
|
@ -677,12 +677,13 @@ class etemplate_widget_nextmatch extends etemplate_widget
|
||||
* - 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
|
||||
*/
|
||||
public function validate($cname, array $content, &$validated=array())
|
||||
public function validate($cname, array $expand, array $content, &$validated=array())
|
||||
{
|
||||
$form_name = self::form_name($cname, $this->id);
|
||||
$form_name = self::form_name($cname, $this->id, $expand);
|
||||
$value = self::get_array($content, $form_name);
|
||||
|
||||
// On client, rows does not get its own namespace, but all apps are expecting it
|
||||
@ -720,7 +721,7 @@ class etemplate_widget_nextmatch extends etemplate_widget
|
||||
* Reimplemented to add namespace, and make sure row template gets included
|
||||
*
|
||||
* @param string $method_name
|
||||
* @param array $params=array('') parameter(s) first parameter has to be cname!
|
||||
* @param array $params=array('') parameter(s) first parameter has to be cname, second $expand!
|
||||
* @param boolean $respect_disabled=false false (default): ignore disabled, true: method is NOT run for disabled widgets AND their children
|
||||
*/
|
||||
public function run($method_name, $params=array(''), $respect_disabled=false)
|
||||
@ -728,10 +729,12 @@ class etemplate_widget_nextmatch extends etemplate_widget
|
||||
$old_param0 = $params[0];
|
||||
$cname =& $params[0];
|
||||
// Need this check or the headers will get involved too
|
||||
if($this->type == 'nextmatch') {
|
||||
if($this->type == 'nextmatch')
|
||||
{
|
||||
if ($this->id) $cname = self::form_name($cname, $this->id, $params[1]);
|
||||
parent::run($method_name, $params, $respect_disabled);
|
||||
if ($this->id) $cname = self::form_name($cname, $this->id);
|
||||
if($this->attrs['template'])
|
||||
|
||||
if ($this->attrs['template'])
|
||||
{
|
||||
$row_template = etemplate_widget_template::instance($this->attrs['template']);
|
||||
$row_template->run($method_name, $params, $respect_disabled);
|
||||
|
@ -72,10 +72,11 @@ class etemplate_widget_projectmanager extends etemplate_widget_transformer
|
||||
* @todo
|
||||
* @param string $cname current namespace
|
||||
* @param array $content
|
||||
* @param array $expand values for keys 'c', 'row', 'c_', 'row_', 'cont'
|
||||
* @param array &$validated=array() validated content
|
||||
* @return boolean true if no validation error, false otherwise
|
||||
*/
|
||||
public function validate($cname, array $content, &$validated=array())
|
||||
public function validate($cname, array $expand, array $content, &$validated=array())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -122,17 +122,14 @@ class etemplate_widget_template extends etemplate_widget
|
||||
*
|
||||
* Reimplemented because templates can have an own namespace specified in attrs[content], NOT id!
|
||||
*
|
||||
* @param array $content
|
||||
* @param array &$validated=array() validated content
|
||||
* @param string $cname='' current namespace
|
||||
* @param string $method_name
|
||||
* @param array $params=array('') parameter(s) first parameter has to be cname, second $expand!
|
||||
* @param boolean $respect_disabled=false false (default): ignore disabled, true: method is NOT run for disabled widgets AND their children
|
||||
* @todo handle template references containing content in id, eg. id="edit.$cont[something]"
|
||||
*/
|
||||
public function run($method_name, $params=array(''), $respect_disabled=false)
|
||||
{
|
||||
$cname =& $params[0];
|
||||
if ($this->attrs['content']) $cname = self::form_name($cname, $this->attrs['content']);
|
||||
|
||||
if ($this->attrs['content']) $cname = self::form_name($cname, $this->attrs['content'], $params[1]);
|
||||
parent::run($method_name, $params, $respect_disabled);
|
||||
}
|
||||
}
|
||||
|
@ -53,12 +53,16 @@ class etemplate_widget_textbox extends etemplate_widget
|
||||
* - 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 $content, &$validated=array())
|
||||
public function validate($cname, array $expand, array $content, &$validated=array())
|
||||
{
|
||||
if (!$this->is_readonly($cname))
|
||||
$form_name = self::form_name($cname, $this->id, $expand);
|
||||
|
||||
if (!$this->is_readonly($cname, $form_name))
|
||||
{
|
||||
if (!isset($this->attrs['preg']))
|
||||
{
|
||||
@ -75,7 +79,6 @@ class etemplate_widget_textbox extends etemplate_widget
|
||||
break;
|
||||
}
|
||||
}
|
||||
$form_name = self::form_name($cname, $this->id);
|
||||
|
||||
$value = $value_in = self::get_array($content, $form_name);
|
||||
$valid =& self::get_array($validated, $form_name, true);
|
||||
|
@ -46,15 +46,16 @@ class etemplate_widget_tree extends etemplate_widget
|
||||
* Validate input
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
public function validate($cname, array $content, &$validated=array())
|
||||
public function validate($cname, array $expand, array $content, &$validated=array())
|
||||
{
|
||||
$form_name = self::form_name($cname, $this->id);
|
||||
$form_name = self::form_name($cname, $this->id, $expand);
|
||||
|
||||
$ok = true;
|
||||
if (!$this->is_readonly($cname))
|
||||
if (!$this->is_readonly($cname, $form_name))
|
||||
{
|
||||
$value = $value_in = self::get_array($content, $form_name);
|
||||
|
||||
@ -101,7 +102,7 @@ class etemplate_widget_tree extends etemplate_widget
|
||||
self::setElementAttribute($form_name, 'no_lang', $no_lang);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Make sure s, etc. are properly encoded when sent, and not double-encoded
|
||||
foreach(self::$request->sel_options[$form_name] as &$label)
|
||||
{
|
||||
@ -161,7 +162,7 @@ class etemplate_widget_tree extends etemplate_widget
|
||||
* @param string $widget_type
|
||||
* @param string $legacy_options options string of widget
|
||||
* @param boolean $no_lang=false initial value of no_lang attribute (some types set it to true)
|
||||
* @param boolean $readonly=false
|
||||
* @param boolean $readonly=false
|
||||
* @param mixed $value=null value for readonly
|
||||
* @return array with value => label pairs
|
||||
*/
|
||||
|
@ -30,13 +30,13 @@ class etemplate_widget_vfs extends etemplate_widget_file
|
||||
self::store_file($field, $file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ajax callback to receive an incoming file
|
||||
*
|
||||
* The incoming file is automatically placed into the appropriate VFS location.
|
||||
* If the entry is not yet created, the file information is stored into the widget's value.
|
||||
* When the form is submitted, the information for all files uploaded is available in the returned
|
||||
* If the entry is not yet created, the file information is stored into the widget's value.
|
||||
* When the form is submitted, the information for all files uploaded is available in the returned
|
||||
* $content array and the application should deal with the file.
|
||||
*/
|
||||
public static function store_file($path, $file) {
|
||||
@ -91,12 +91,13 @@ error_log(lang('Error copying uploaded file to vfs!'));
|
||||
* Merge any already uploaded files into the content array
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
public function validate($cname, array $content, &$validated=array())
|
||||
public function validate($cname, array $expand, array $content, &$validated=array())
|
||||
{
|
||||
$form_name = self::form_name($cname, $this->id);
|
||||
$form_name = self::form_name($cname, $this->id, $expand);
|
||||
$value = $value_in = self::get_array($content, $form_name);
|
||||
$valid =& self::get_array($validated, $form_name, true);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user