diff --git a/etemplate/inc/class.etemplate_new.inc.php b/etemplate/inc/class.etemplate_new.inc.php index 9cc7f96383..d63878b01d 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 68ad73e054..76f3492aab 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 10447ceefe..874cabef91 100644 --- a/etemplate/js/et2_widget_grid.js +++ b/etemplate/js/et2_widget_grid.js @@ -1026,6 +1026,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 b93485c62a..e72ba72f3f 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 @@ - - - - - + + + + +