mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-29 11:23:54 +01:00
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
This commit is contained in:
parent
21aa3eb325
commit
63a7af621d
@ -95,6 +95,7 @@ class etemplate_new extends etemplate_widget_template
|
|||||||
* -1 = first time return html, after use 0 (echo html incl. navbar), eg. for home
|
* -1 = first time return html, after use 0 (echo html incl. navbar), eg. for home
|
||||||
* 2 = echo without navbar (eg. for popups)
|
* 2 = echo without navbar (eg. for popups)
|
||||||
* 3 = return eGW independent html site
|
* 3 = return eGW independent html site
|
||||||
|
* 4 = json response
|
||||||
* @param string $ignore_validation if not empty regular expression for validation-errors to ignore
|
* @param string $ignore_validation if not empty regular expression for validation-errors to ignore
|
||||||
* @param array $changes change made in the last call if looping, only used internaly by process_exec
|
* @param array $changes change made in the last call if looping, only used internaly by process_exec
|
||||||
* @return string html for $output_mode == 1, else nothing
|
* @return string html for $output_mode == 1, else nothing
|
||||||
@ -106,6 +107,11 @@ class etemplate_new extends etemplate_widget_template
|
|||||||
|
|
||||||
if (!$this->rel_path) throw new egw_exception_assertion_failed("No (valid) template '$this->name' found!");
|
if (!$this->rel_path) throw new egw_exception_assertion_failed("No (valid) template '$this->name' found!");
|
||||||
|
|
||||||
|
if ($output_mode == 4)
|
||||||
|
{
|
||||||
|
$output_mode = 0;
|
||||||
|
self::$response = egw_json_response::get();
|
||||||
|
}
|
||||||
self::$request->output_mode = $output_mode; // let extensions "know" they are run eg. in a popup
|
self::$request->output_mode = $output_mode; // let extensions "know" they are run eg. in a popup
|
||||||
self::$request->content = self::$cont = $content;
|
self::$request->content = self::$cont = $content;
|
||||||
self::$request->changes = $changes;
|
self::$request->changes = $changes;
|
||||||
|
@ -717,6 +717,22 @@ class etemplate_widget
|
|||||||
return $pos;
|
return $pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return a reference to $arr[$idx]
|
||||||
|
*
|
||||||
|
* This works for non-trival indexes like 'a[b][c]' too: it returns &$arr[a][b][c]
|
||||||
|
* $sub = get_array($arr,'a[b]'); $sub = 'c'; is equivalent to $arr['a']['b'] = 'c';
|
||||||
|
*
|
||||||
|
* @param array& $_arr the array to search, referenz as a referenz gets returned
|
||||||
|
* @param string $_idx the index, may contain sub-indices like a[b], see example below
|
||||||
|
* @param mixed $_value value to set
|
||||||
|
*/
|
||||||
|
static function set_array(&$_arr, $_idx, $_value)
|
||||||
|
{
|
||||||
|
$ref =& self::get_array($_arr, $_idx, true);
|
||||||
|
if (true) $ref = $_value;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a widget is readonly:
|
* Checks if a widget is readonly:
|
||||||
* - readonly attribute set
|
* - readonly attribute set
|
||||||
|
@ -52,6 +52,7 @@ class etemplate_widget_checkbox extends etemplate_widget
|
|||||||
if (!$this->is_readonly($cname, $form_name))
|
if (!$this->is_readonly($cname, $form_name))
|
||||||
{
|
{
|
||||||
$value = self::get_array($content, $form_name);
|
$value = self::get_array($content, $form_name);
|
||||||
|
if (!isset($value)) return; // value not transmitted --> nothing to validate
|
||||||
$valid =& self::get_array($validated, $form_name, true);
|
$valid =& self::get_array($validated, $form_name, true);
|
||||||
|
|
||||||
if (!$value && $this->attrs['needed'])
|
if (!$value && $this->attrs['needed'])
|
||||||
|
@ -174,10 +174,12 @@ class etemplate_widget_menupopup extends etemplate_widget
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$valid =& self::get_array($validated, $form_name, true);
|
if (isset($value))
|
||||||
if (true) $valid = $value;
|
{
|
||||||
|
self::set_array($validated, $form_name, $value);
|
||||||
//error_log(__METHOD__."() $form_name: ".array2string($value_in).' --> '.array2string($value).', allowed='.array2string($allowed));
|
//error_log(__METHOD__."() $form_name: ".array2string($value_in).' --> '.array2string($value).', allowed='.array2string($allowed));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//error_log($this . "($form_name) is read-only, skipping validate");
|
//error_log($this . "($form_name) is read-only, skipping validate");
|
||||||
|
@ -131,7 +131,6 @@ class etemplate_widget_textbox extends etemplate_widget
|
|||||||
}
|
}
|
||||||
|
|
||||||
$value = $value_in = self::get_array($content, $form_name);
|
$value = $value_in = self::get_array($content, $form_name);
|
||||||
$valid =& self::get_array($validated, $form_name, true);
|
|
||||||
|
|
||||||
// passwords are not transmitted back to client (just asterisks)
|
// passwords are not transmitted back to client (just asterisks)
|
||||||
// therefore we need to replace it again with preserved value
|
// therefore we need to replace it again with preserved value
|
||||||
@ -185,9 +184,12 @@ class etemplate_widget_textbox extends etemplate_widget
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (true) $valid = $value;
|
if (isset($value))
|
||||||
|
{
|
||||||
|
self::set_array($validated, $form_name, $value);
|
||||||
//error_log(__METHOD__."() $form_name: ".array2string($value_in).' --> '.array2string($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'));
|
etemplate_widget::registerWidget('etemplate_widget_textbox', array('textbox','text','int','integer','float','passwd','hidden','colorpicker','hidden'));
|
||||||
|
@ -1027,6 +1027,47 @@ var et2_grid = et2_DOMWidget.extend([et2_IDetachedDOM, et2_IAligned, et2_IResize
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a dummy row object containing all widget of a row
|
||||||
|
*
|
||||||
|
* This is only a temp. solution until rows are implemented as eT2 containers and
|
||||||
|
* _sender.getParent() will return a real row container.
|
||||||
|
*
|
||||||
|
* @param {et2_widget} _sender
|
||||||
|
* @returns {Array|undefined}
|
||||||
|
*/
|
||||||
|
getRow: function(_sender)
|
||||||
|
{
|
||||||
|
if (!_sender || !this.cells) return;
|
||||||
|
|
||||||
|
for(var r=0; r < this.cells.length; ++r)
|
||||||
|
{
|
||||||
|
var row = this.cells[r];
|
||||||
|
for(var c=0; c < row.length; ++c)
|
||||||
|
{
|
||||||
|
if (!row[c].widget) continue;
|
||||||
|
|
||||||
|
var found = row[c].widget === _sender;
|
||||||
|
if (!found) row[c].widget.iterateOver(function(_widget) {if (_widget === _sender) found = true;});
|
||||||
|
if (found)
|
||||||
|
{
|
||||||
|
// return a fake row object allowing to iterate over it's children
|
||||||
|
var row_obj = new et2_widget(this, {});
|
||||||
|
for(var c=0; c < row.length; ++c)
|
||||||
|
{
|
||||||
|
if (row[c].widget) row_obj._children.push(row[c].widget);
|
||||||
|
}
|
||||||
|
row_obj.isInTree = jQuery.proxy(this.isInTree, this);
|
||||||
|
// we must not free the children!
|
||||||
|
row_obj.destroy = function(){
|
||||||
|
delete row_obj._children;
|
||||||
|
};
|
||||||
|
return row_obj;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
et2_register_widget(et2_grid, ["grid"]);
|
et2_register_widget(et2_grid, ["grid"]);
|
@ -616,23 +616,25 @@ etemplate2.prototype.autocomplete_fixer = function ()
|
|||||||
* @param {(et2_button|string)} button button widget or string with id
|
* @param {(et2_button|string)} button button widget or string with id
|
||||||
* @param {boolean} async true: do an asynchronious submit, default is synchronious
|
* @param {boolean} async true: do an asynchronious submit, default is synchronious
|
||||||
* @param {boolean} no_validation - Do not do individual widget validation, just submit their current values
|
* @param {boolean} no_validation - Do not do individual widget validation, just submit their current values
|
||||||
|
* @param {et2_widget|undefined} _container container to submit, default whole template
|
||||||
* @return {boolean} true if submit was send, false if eg. validation stoped submit
|
* @return {boolean} true if submit was send, false if eg. validation stoped submit
|
||||||
*/
|
*/
|
||||||
etemplate2.prototype.submit = function(button, async, no_validation)
|
etemplate2.prototype.submit = function(button, async, no_validation, _container)
|
||||||
{
|
{
|
||||||
if(typeof no_validation == 'undefined')
|
if(typeof no_validation == 'undefined')
|
||||||
{
|
{
|
||||||
no_validation = false;
|
no_validation = false;
|
||||||
}
|
}
|
||||||
|
var container = _container || this.widgetContainer;
|
||||||
|
|
||||||
// Get the form values
|
// Get the form values
|
||||||
var values = this.getValues(this.widgetContainer);
|
var values = this.getValues(container);
|
||||||
|
|
||||||
// Trigger the submit event
|
// Trigger the submit event
|
||||||
var canSubmit = true;
|
var canSubmit = true;
|
||||||
if(!no_validation)
|
if(!no_validation)
|
||||||
{
|
{
|
||||||
this.widgetContainer.iterateOver(function(_widget) {
|
container.iterateOver(function(_widget) {
|
||||||
if (_widget.submit(values) === false)
|
if (_widget.submit(values) === false)
|
||||||
{
|
{
|
||||||
canSubmit = false;
|
canSubmit = false;
|
||||||
|
@ -13,15 +13,15 @@
|
|||||||
<description value="Header" span="all"/>
|
<description value="Header" span="all"/>
|
||||||
<description/>
|
<description/>
|
||||||
</row>
|
</row>
|
||||||
<row part="footer">
|
<row class="th" part="header">
|
||||||
<description value="Footer" span="all"/>
|
|
||||||
<description/>
|
|
||||||
</row>
|
|
||||||
<row class="th">
|
|
||||||
<grid-sortheader label="Col 1 Header" id="first" custom-sort="app.method"/>
|
<grid-sortheader label="Col 1 Header" id="first" custom-sort="app.method"/>
|
||||||
<grid-sortheader label="Col 2 Header" id="second"/>
|
<grid-sortheader label="Col 2 Header" id="second"/>
|
||||||
<description value="Col 3 Header"/>
|
<description value="Col 3 Header"/>
|
||||||
</row>
|
</row>
|
||||||
|
<row part="footer">
|
||||||
|
<description value="Footer" span="all"/>
|
||||||
|
<description/>
|
||||||
|
</row>
|
||||||
<row class="row">
|
<row class="row">
|
||||||
<description id="${row}[first]"/>
|
<description id="${row}[first]"/>
|
||||||
<description id="${row}[second]"/>
|
<description id="${row}[second]"/>
|
||||||
|
Loading…
Reference in New Issue
Block a user