diff --git a/etemplate/inc/class.etemplate_new.inc.php b/etemplate/inc/class.etemplate_new.inc.php
index 32610a4069..c524ecb874 100644
--- a/etemplate/inc/class.etemplate_new.inc.php
+++ b/etemplate/inc/class.etemplate_new.inc.php
@@ -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
* 2 = echo without navbar (eg. for popups)
* 3 = return eGW independent html site
+ * 4 = json response
* @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
* @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 ($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->content = self::$cont = $content;
self::$request->changes = $changes;
diff --git a/etemplate/inc/class.etemplate_widget.inc.php b/etemplate/inc/class.etemplate_widget.inc.php
index f7e0491df9..a2e5e2178e 100644
--- a/etemplate/inc/class.etemplate_widget.inc.php
+++ b/etemplate/inc/class.etemplate_widget.inc.php
@@ -717,6 +717,22 @@ class etemplate_widget
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:
* - readonly attribute set
diff --git a/etemplate/inc/class.etemplate_widget_checkbox.inc.php b/etemplate/inc/class.etemplate_widget_checkbox.inc.php
index 919130a9e2..b15073d016 100644
--- a/etemplate/inc/class.etemplate_widget_checkbox.inc.php
+++ b/etemplate/inc/class.etemplate_widget_checkbox.inc.php
@@ -52,6 +52,7 @@ class etemplate_widget_checkbox extends etemplate_widget
if (!$this->is_readonly($cname, $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);
if (!$value && $this->attrs['needed'])
diff --git a/etemplate/inc/class.etemplate_widget_menupopup.inc.php b/etemplate/inc/class.etemplate_widget_menupopup.inc.php
index 1c5eb43727..584bc023b6 100644
--- a/etemplate/inc/class.etemplate_widget_menupopup.inc.php
+++ b/etemplate/inc/class.etemplate_widget_menupopup.inc.php
@@ -174,9 +174,11 @@ class etemplate_widget_menupopup extends etemplate_widget
}
}
}
- $valid =& self::get_array($validated, $form_name, true);
- if (true) $valid = $value;
- //error_log(__METHOD__."() $form_name: ".array2string($value_in).' --> '.array2string($value).', allowed='.array2string($allowed));
+ if (isset($value))
+ {
+ self::set_array($validated, $form_name, $value);
+ //error_log(__METHOD__."() $form_name: ".array2string($value_in).' --> '.array2string($value).', allowed='.array2string($allowed));
+ }
}
else
{
diff --git a/etemplate/inc/class.etemplate_widget_textbox.inc.php b/etemplate/inc/class.etemplate_widget_textbox.inc.php
index 6cf901eaa4..f90cf90da0 100644
--- a/etemplate/inc/class.etemplate_widget_textbox.inc.php
+++ b/etemplate/inc/class.etemplate_widget_textbox.inc.php
@@ -131,7 +131,6 @@ class etemplate_widget_textbox extends etemplate_widget
}
$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)
// therefore we need to replace it again with preserved value
@@ -185,8 +184,11 @@ class etemplate_widget_textbox extends etemplate_widget
}
}
}
- if (true) $valid = $value;
- //error_log(__METHOD__."() $form_name: ".array2string($value_in).' --> '.array2string($value));
+ if (isset($value))
+ {
+ self::set_array($validated, $form_name, $value);
+ //error_log(__METHOD__."() $form_name: ".array2string($value_in).' --> '.array2string($value));
+ }
}
}
}
diff --git a/etemplate/js/et2_widget_grid.js b/etemplate/js/et2_widget_grid.js
index 23dc1423db..cc008aed97 100644
--- a/etemplate/js/et2_widget_grid.js
+++ b/etemplate/js/et2_widget_grid.js
@@ -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"]);
\ No newline at end of file
diff --git a/etemplate/js/etemplate2.js b/etemplate/js/etemplate2.js
index 21e09eb1c9..e376ad2e6d 100644
--- a/etemplate/js/etemplate2.js
+++ b/etemplate/js/etemplate2.js
@@ -498,7 +498,7 @@ etemplate2.prototype.load = function(_name, _url, _data, _callback)
$this = $j(this);
return !$this.attr('tabindex') || $this.attr('tabIndex')>=0;
}).first();
-
+
// mobile device, focus only if the field is empty (usually means new entry)
// should focus always for non-mobile one
if (egwIsMobile() && $input.val() == "" || !egwIsMobile()) $input.focus();
@@ -616,23 +616,25 @@ etemplate2.prototype.autocomplete_fixer = function ()
* @param {(et2_button|string)} button button widget or string with id
* @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 {et2_widget|undefined} _container container to submit, default whole template
* @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')
{
no_validation = false;
}
+ var container = _container || this.widgetContainer;
// Get the form values
- var values = this.getValues(this.widgetContainer);
+ var values = this.getValues(container);
// Trigger the submit event
var canSubmit = true;
if(!no_validation)
{
- this.widgetContainer.iterateOver(function(_widget) {
+ container.iterateOver(function(_widget) {
if (_widget.submit(values) === false)
{
canSubmit = false;
diff --git a/etemplate/templates/default/table_test.xet b/etemplate/templates/default/table_test.xet
index 0c6fcc14c7..6ee46c27aa 100644
--- a/etemplate/templates/default/table_test.xet
+++ b/etemplate/templates/default/table_test.xet
@@ -13,15 +13,15 @@
-
-
-
-
-
+
+
+
+
+