From 5e8de7f972102a772641c7b3d96a00e207c4e4f5 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Fri, 25 Jul 2014 07:53:30 +0000 Subject: [PATCH 01/94] Get the socialMedia icons out of table and append it to form if it is pixelegg template --- phpgwapi/js/login.js | 19 ++----------------- phpgwapi/templates/default/login.tpl | 2 +- phpgwapi/templates/idots/css/traditional.css | 2 +- 3 files changed, 4 insertions(+), 19 deletions(-) diff --git a/phpgwapi/js/login.js b/phpgwapi/js/login.js index 7d8cc4d366..0fff07bc79 100644 --- a/phpgwapi/js/login.js +++ b/phpgwapi/js/login.js @@ -14,12 +14,13 @@ egw_LAB.wait(function() { }).done(function(_data) { $j(document).ready(function() { + var isPixelegg = $j('link[href*="pixelegg.css"]')[0]; var social = $j(document.createElement('div')) .attr({ id: "socialMedia", class: "socialMedia" }) - .appendTo($j('#socialBox')); + .appendTo($j( isPixelegg? 'form' : '#socialBox')); for(var i=0; i < _data.length; ++i) { @@ -36,19 +37,3 @@ egw_LAB.wait(function() { }); }); }); - -// $j('img.bgfade').hide(); -//// var dg_H = $j(window).height(); -//// var dg_W = $j(window).width(); -//// $j('#wrap').css({'height':dg_H,'width':dg_W}); -// -// function anim() { -// $j("#wrap img.bgfade").first().appendTo('#wrap').fadeOut(3500); -// $j("#wrap img").first().fadeIn(3500); -// setTimeout(anim, 7000); -// } -//anim(); -//$j(window).resize(function(){window.location.href=window.location.href}); -// }); -// -//}); diff --git a/phpgwapi/templates/default/login.tpl b/phpgwapi/templates/default/login.tpl index 038a446323..3b40c26d41 100644 --- a/phpgwapi/templates/default/login.tpl +++ b/phpgwapi/templates/default/login.tpl @@ -62,7 +62,7 @@ - + diff --git a/phpgwapi/templates/idots/css/traditional.css b/phpgwapi/templates/idots/css/traditional.css index 1abb9cdb15..2ffbf5fd87 100755 --- a/phpgwapi/templates/idots/css/traditional.css +++ b/phpgwapi/templates/idots/css/traditional.css @@ -471,8 +471,8 @@ body { background-color: white; } #socialMedia { - left: 273px; position: relative; + float:right; } #loginScreenMessage { text-align: center; From 35e5ff6d6ef674389cc0bc9c0c8d625bc5271039 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 25 Jul 2014 09:13:19 +0000 Subject: [PATCH 02/94] * Admin: restore from admin was not working (worked only from setup) --- admin/inc/class.admin_db_backup.inc.php | 4 +++- phpgwapi/inc/class.db_backup.inc.php | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/admin/inc/class.admin_db_backup.inc.php b/admin/inc/class.admin_db_backup.inc.php index 47f13c71ff..c2e57f5f52 100644 --- a/admin/inc/class.admin_db_backup.inc.php +++ b/admin/inc/class.admin_db_backup.inc.php @@ -23,7 +23,7 @@ class admin_db_backup { $this->db_backup = new db_backup(); - if ($f = $this->db_backup->fopen_backup()) + if (($f = $this->db_backup->fopen_backup())) { $this->db_backup->backup($f); if(is_resource($f)) @@ -41,9 +41,11 @@ class admin_db_backup $tpl_root = EGW_SERVER_ROOT.'/setup/templates/default'; $self = $GLOBALS['egw']->link('/index.php',array('menuaction'=>'admin.admin_db_backup.index')); translation::add_app('setup'); + egw_framework::csp_script_src_attrs('unsafe-inline'); include EGW_SERVER_ROOT.'/setup/db_backup.php'; + unset($tpl_root, $self); common::egw_footer(); } } diff --git a/phpgwapi/inc/class.db_backup.inc.php b/phpgwapi/inc/class.db_backup.inc.php index 58a61d064a..e17bfdd8e6 100644 --- a/phpgwapi/inc/class.db_backup.inc.php +++ b/phpgwapi/inc/class.db_backup.inc.php @@ -149,7 +149,7 @@ class db_backup } else // called from eGW { - $this->schema_proc = CreateObject('phpgwapi.schema_proc'); + $this->schema_proc = new schema_proc(); if (!($this->backup_dir = $GLOBALS['egw_info']['server']['backup_dir'])) { $this->backup_dir = $GLOBALS['egw_info']['server']['files_dir'].'/db_backup'; @@ -437,7 +437,7 @@ class db_backup @ini_set('mbstring.internal_encoding',$charset); // check if we really need to convert the charset, as it's not perfect and can do some damage - if ($convert_to_system_charset && !strcasecmp($convert_to_system_charset,$charset)) + if ($convert_to_system_charset && !strcasecmp($this->schema_proc->system_charset, $charset)) { $convert_to_system_charset = false; // no conversation necessary } @@ -567,8 +567,8 @@ class db_backup if ($convert_to_system_charset) // store the changed charset { - $this->db->insert($GLOBALS['egw_setup']->config_table,array( - 'config_value' => $GLOBALS['egw_setup']->system_charset, + $this->db->insert(config::TABLE, array( + 'config_value' => $this->schema_proc->system_charset, ),array( 'config_app' => 'phpgwapi', 'config_name' => 'system_charset', From 970331b97c746661bae1e7de8b5ea91388310648 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 25 Jul 2014 10:17:15 +0000 Subject: [PATCH 03/94] * Addressbook/all apps: dates change every time they get stored (temporary fix as conditions causing that are not clear) --- etemplate/js/et2_widget_date.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/etemplate/js/et2_widget_date.js b/etemplate/js/et2_widget_date.js index 7373fde1d2..6c83d61c42 100644 --- a/etemplate/js/et2_widget_date.js +++ b/etemplate/js/et2_widget_date.js @@ -238,6 +238,10 @@ var et2_date = et2_inputWidget.extend( this.date.setMonth(0); this.date.setFullYear(1970); } + else if (this._type == 'date') + { + this.date.setHours(12); + } // Convert to timestamp - no seconds this.date.setSeconds(0,0); return Math.round(this.date.valueOf() / 1000); From acfd576c75d5455ce7ce79699a0ccf354cc57f2c Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 25 Jul 2014 10:47:39 +0000 Subject: [PATCH 04/94] fixed not translated update-notification --- phpgwapi/lang/egw_de.lang | 4 ++-- phpgwapi/lang/egw_en.lang | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/phpgwapi/lang/egw_de.lang b/phpgwapi/lang/egw_de.lang index 2ccc882ae6..1010586433 100644 --- a/phpgwapi/lang/egw_de.lang +++ b/phpgwapi/lang/egw_de.lang @@ -91,7 +91,7 @@ austria common de ÖSTERREICH author common de Autor autohide sidebox menu's common de Linkes Navigationsmenü ausblenden autohide sidebox menus common de Linkes Navigationsmenü ausblenden -automatic update check failed, you need to check manually! admin de Automatischer Test fehlgeschlagen, Sie müssen selbst überprüfen ob neue Updates vorliegen! +automatic update check failed, you need to check manually! common de Automatischer Test fehlgeschlagen, Sie müssen selbst überprüfen ob neue Updates vorliegen! automatically hide the sidebox menu's? common de Automatisch linkes Navigationsmenü ausblenden? automatically hide the sidebox menus? common de Automatisch linkes Navigationsmenü ausblenden? autosave default category common de Standard-Kategorie automatisch speichern @@ -267,7 +267,7 @@ edit categories common de Kategorien editieren edit category common de Kategorie editieren egroupware common de EGroupware egroupware api version common de EGroupware API Version -egroupware maintenance update %1 available admin de EGroupware Fehlerbehebungsupdate %1 ist verfügbar +egroupware maintenance update %1 available common de EGroupware Fehlerbehebungsupdate %1 ist verfügbar egroupware security update %1 needs to be installed! common de EGroupware Sicherheitsupdate %1 muss installiert werden! egroupware: login blocked for user '%1', ip %2 common de EGroupware: Anmelden gesperrt für Benutzer '%1', IP %2 egypt common de ÄGYPTEN diff --git a/phpgwapi/lang/egw_en.lang b/phpgwapi/lang/egw_en.lang index 748c167c30..3a9d29775c 100644 --- a/phpgwapi/lang/egw_en.lang +++ b/phpgwapi/lang/egw_en.lang @@ -91,7 +91,7 @@ austria common en AUSTRIA author common en Author autohide sidebox menu's common en Autohide side menu autohide sidebox menus common en Autohide side menu -automatic update check failed, you need to check manually! admin en Automatic update check failed, you need to check manually! +automatic update check failed, you need to check manually! common en Automatic update check failed, you need to check manually! automatically hide the sidebox menu's? common en Automatically hide the side menu? automatically hide the sidebox menus? common en Automatically hide the side menu? autosave default category common en Auto-save default category. @@ -267,7 +267,7 @@ edit categories common en Edit categories edit category common en Edit category egroupware common en EGroupware egroupware api version common en EGroupware API version -egroupware maintenance update %1 available admin en EGroupware maintenance update %1 available +egroupware maintenance update %1 available common en EGroupware maintenance update %1 available egroupware security update %1 needs to be installed! common en EGroupware security update %1 needs to be installed! egroupware: login blocked for user '%1', ip %2 common en Login blocked for user '%1', IP %2 egypt common en EGYPT From 6744ba967e1387e4e21ae6643c59566feaddff37 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 25 Jul 2014 12:22:57 +0000 Subject: [PATCH 05/94] force CKEditor moono theme/skin on 14.1 update --- phpgwapi/setup/tables_update_1_8.inc.php | 1 + 1 file changed, 1 insertion(+) diff --git a/phpgwapi/setup/tables_update_1_8.inc.php b/phpgwapi/setup/tables_update_1_8.inc.php index 83a8208d24..41644a85d7 100644 --- a/phpgwapi/setup/tables_update_1_8.inc.php +++ b/phpgwapi/setup/tables_update_1_8.inc.php @@ -562,6 +562,7 @@ function phpgwapi_upgrade1_9_021() { preferences::change_preference('common', 'template_set', 'pixelegg', null, 'forced'); preferences::change_preference('common', 'theme', 'pixelegg', null, 'forced'); + preferences::change_preference('common', 'rte_skin', 'moono', null, 'forced'); } preferences::change_preference('common', 'maxmatchs', '20', null, 'forced'); From c6783d8b8e7be49c2fcbe65eee74636f6eb43cd8 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 25 Jul 2014 12:32:34 +0000 Subject: [PATCH 06/94] document hack, to work around birthdays changing one day for each time they are stored --- etemplate/js/et2_widget_date.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/etemplate/js/et2_widget_date.js b/etemplate/js/et2_widget_date.js index 6c83d61c42..868de776f0 100644 --- a/etemplate/js/et2_widget_date.js +++ b/etemplate/js/et2_widget_date.js @@ -238,6 +238,8 @@ var et2_date = et2_inputWidget.extend( this.date.setMonth(0); this.date.setFullYear(1970); } + // this is a hack, to work around birthdays changing one day for each time they are stored + // ToDo: either find and fix the reason, or send date as YYYY-mm-dd string to server else if (this._type == 'date') { this.date.setHours(12); From 69076614024574bd95d88deb10dcd77f97e9f966 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 25 Jul 2014 14:14:45 +0000 Subject: [PATCH 07/94] copying 14.1 changelog to trunk, to stop update notification --- doc/rpm-build/debian.changes | 46 ++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/doc/rpm-build/debian.changes b/doc/rpm-build/debian.changes index 7e8fe5e851..2878e5c2ec 100644 --- a/doc/rpm-build/debian.changes +++ b/doc/rpm-build/debian.changes @@ -1,3 +1,49 @@ +egroupware-epl (14.1.20140725-1) hardy; urgency=low + + * Admin: restore backups from admin was not working (worked only from setup) + * Addressbook/all apps: dates change every time they get stored (temporary fix as conditions causing that are not clear) + + -- Ralf Becker Fri, 25 Jul 2014 12:18:25 +0200 + +egroupware-epl (14.1.20140724-1) hardy; urgency=low + + * Admin: automatic update check displaying an icon for available (security-)updates for admins, escalating for security updates to all users after 3 days + * EMailAdmin: if wizzard was called on error, it was not able to save fixed account (showed same error again) + * API/Admin: fixed not working Admin >> Clear cache for default APC(u) and files backends + * Admin/API: remove no longer fully supported method to not "store session-id in cookie", it is the safer default anyway + * Mail: fixed wrong folders displayed, if Cyrus administration was activated + * eTemplate2: fixed popups eg. tracker open empty, not rendering popup content + * Admin/LDAP: deactivated accounts could not be reactivated, as account popup was not showing selected account + * API/CKEditor: update to version 4.4.3 adding additional skins/themes + * Admin/Setup: restore of 14.1 backup was not working (backup file itself is correct) + + -- Ralf Becker Wed, 23 Jul 2014 18:50:31 +0200 + +egroupware-epl (14.1.20140714-1) hardy; urgency=low + + * Backup: backup could contain rows multiple times (which caused restore to fail) + * API: fixed broken configuration, causing eg. ActiveDirectory or LDAP authentication to fail (you need to run Setup >> Clear cache!) + * Preferences: non-admins were allowed to changed default, forced or group preferences + * Preferences: do NOT use deny configuration for admins + * SiteMgr: fixed sliteshow (was loaded before jQuery) + * Mail: unlock tree again after copy/move actions + * ProjectManager: fix broken duration units causing times to display as undefined + * eTemplate2: several fixes in widgets + + -- Ralf Becker Mon, 14 Jul 2014 18:40:34 +0200 + +egroupware-epl (14.1.20140710-1) hardy; urgency=low + + * final 14.1 release + * Admin/all apps: fix refresh of admin after calling site configuration, categories, etc from apps + * Admin: custom-fields were not loaded, account was edited from admin not addressbook + * EMailAdmin: fixed migration of Sieve to use SSL/TLS for port 5190 and StartTLS for all other ports + * EMailAdmin: fixed mail accounts valid for groups or multiple users and switching regular accounts to or from that + * Addressbook: fixed sorting of category tree + * Added context menu to download all linked files in one zip file + + -- Ralf Becker Wed, 09 Jul 2014 20:50:54 +0200 + egroupware-epl (14.1.20140708-1) hardy; urgency=low * Debian: aptitude install egroupware-epl now removes 1.8 community packages or updates all EPL 11.1 packages From 40aa20eaa2100bec6dac7534ec88f4d527c668e2 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Mon, 28 Jul 2014 15:29:49 +0000 Subject: [PATCH 08/94] As we replace spaces with + for those account ids which contain spaces, therefore we need to do the same for getting request-id too. --- etemplate/inc/class.etemplate_request_cache.inc.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/etemplate/inc/class.etemplate_request_cache.inc.php b/etemplate/inc/class.etemplate_request_cache.inc.php index 82e650561f..10f57c2378 100644 --- a/etemplate/inc/class.etemplate_request_cache.inc.php +++ b/etemplate/inc/class.etemplate_request_cache.inc.php @@ -114,7 +114,9 @@ class etemplate_request_cache extends etemplate_request */ static function request_id() { - return uniqid($GLOBALS['egw_info']['flags']['currentapp'].'_'.$GLOBALS['egw_info']['user']['account_lid'].'_',true); + // As we replace spaces with + for those account ids which contain spaces, therefore we need to do the same for getting request id too. + $userID = str_replace(' ', '+', rawurldecode($GLOBALS['egw_info']['user']['account_lid'])); + return uniqid($GLOBALS['egw_info']['flags']['currentapp'].'_'.$userID.'_',true); } /** From 9851a8a6eff794ebf891d285dd6f03f17e08c225 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Mon, 28 Jul 2014 20:51:49 +0000 Subject: [PATCH 09/94] Trigger a clear event on the etemplate DOMContainer when the etemplate is cleared, so app code can listen for it. This allows a 'et2_unload' sort of processing. --- etemplate/js/etemplate2.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/etemplate/js/etemplate2.js b/etemplate/js/etemplate2.js index ada8af36fc..2c8268c4c3 100644 --- a/etemplate/js/etemplate2.js +++ b/etemplate/js/etemplate2.js @@ -121,6 +121,8 @@ etemplate2.prototype.resize = function() */ etemplate2.prototype.clear = function() { + $j(this.DOMContainer).trigger('clear'); + // Remove any handlers on window (resize) if(this.uniqueId) { From 8a70df4df8bd8debba6c1485cbb3900e42895816 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Mon, 28 Jul 2014 21:00:39 +0000 Subject: [PATCH 10/94] Handle num_rows set by application: - Don't overwrite num_rows setting if the application sets it for some reason - If num_rows is 0, don't get the initial rows server side - If num_rows is 0 and the initial rows are missing, trigger an update right away to get them asyncronously. --- .../inc/class.etemplate_widget_nextmatch.inc.php | 11 +++++++++-- etemplate/js/et2_extension_nextmatch.js | 9 ++++++++- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/etemplate/inc/class.etemplate_widget_nextmatch.inc.php b/etemplate/inc/class.etemplate_widget_nextmatch.inc.php index b217ab1a3d..316ab7007a 100644 --- a/etemplate/inc/class.etemplate_widget_nextmatch.inc.php +++ b/etemplate/inc/class.etemplate_widget_nextmatch.inc.php @@ -113,7 +113,11 @@ class etemplate_widget_nextmatch extends etemplate_widget $value = self::get_array(self::$request->content, $form_name, true); $value['start'] = 0; - $value['num_rows'] = self::INITIAL_ROWS; + if(!array_key_exists('num_rows',$value)) + { + $value['num_rows'] = self::INITIAL_ROWS; + } + $value['rows'] = array(); $send_value = $value; @@ -159,7 +163,10 @@ class etemplate_widget_nextmatch extends etemplate_widget $send_value['order'] = $send_value['sort']['id']; $send_value['sort'] = $send_value['sort']['asc'] ? 'ASC' : 'DESC'; } - $total = self::call_get_rows($send_value, $send_value['rows'], self::$request->readonlys); + if($value['num_rows'] != 0) + { + $total = self::call_get_rows($send_value, $send_value['rows'], self::$request->readonlys); + } $value =& self::get_array(self::$request->content, $form_name, true); // Add favorite here so app doesn't save it in the session diff --git a/etemplate/js/et2_extension_nextmatch.js b/etemplate/js/et2_extension_nextmatch.js index c4e2daac5c..4c165b30b0 100644 --- a/etemplate/js/et2_extension_nextmatch.js +++ b/etemplate/js/et2_extension_nextmatch.js @@ -1082,7 +1082,7 @@ var et2_nextmatch = et2_DOMWidget.extend([et2_IResizeable, et2_IInput], this.dataview.grid.setTotalCount(total); // Insert any data sent from server, so invalidate finds data already - if(this.options.settings.rows) + if(this.options.settings.rows && this.options.settings.num_rows) { this.controller.loadInitialData( this.options.settings.dataStorePrefix, @@ -1510,6 +1510,13 @@ var et2_nextmatch = et2_DOMWidget.extend([et2_IResizeable, et2_IInput], // Set filters to current values this.controller.setFilters(this.activeFilters); + // If no data was sent from the server, and num_rows is 0, the nm will be empty. + // This triggers a cache check. + if(!(this.options.settings.rows && this.options.settings.num_rows)) + { + this.controller.update(); + } + // Load the default sort order if (this.options.settings.order && this.options.settings.sort) { From df76846b378b812d42f64efedc2ea6e478374ebd Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Mon, 28 Jul 2014 21:17:06 +0000 Subject: [PATCH 11/94] Allow for long-term client side caching of dataFetch responses. --- phpgwapi/js/jsapi/egw_data.js | 152 +++++++++++++++++++++++++++++++++- 1 file changed, 149 insertions(+), 3 deletions(-) diff --git a/phpgwapi/js/jsapi/egw_data.js b/phpgwapi/js/jsapi/egw_data.js index 576875a095..0a2340290c 100644 --- a/phpgwapi/js/jsapi/egw_data.js +++ b/phpgwapi/js/jsapi/egw_data.js @@ -26,6 +26,15 @@ egw.extend("data", egw.MODULE_APP_LOCAL, function (_app, _wnd) { var lastModification = null; + /** + * cacheCallback stores callbacks that determine if data is placed + * into cacheStorage, or simply kept temporarily. It is indexed + * by prefix. + * + * @type Array + */ + var cacheCallback = {}; + /** * The uid function generates a session-unique id for the current * application by appending the application name to the given uid. @@ -40,6 +49,35 @@ egw.extend("data", egw.MODULE_APP_LOCAL, function (_app, _wnd) { return _prefix + "::" + _uid; } + /** + * Looks like too much data is cached. Forget some. + * + * Tries to free up localStorage by removing cached data for the given + * prefix, but if none is found it will remove all cached data. + * + * @param {string} _prefix UID / application prefix + * @returns {Number} Number of cached recordsets removed + */ + function _clearCache(_prefix) + { + // Find cached items for the prefix, we prefer to expire just within the app + var indexes = []; + for(var i = 0; i < window.localStorage.length; i++) + { + if(window.localStorage.key(i).indexOf('cache_'+_prefix) == 0) + { + indexes.push(i); + window.localStorage.removeItem(window.localStorage.key(i)); + } + } + // Nothing for that prefix? Clear all cached data. + if(_prefix && indexes.length == 0) + { + return _clearCache(''); + } + return indexes.length; + } + function parseServerResponse(_result, _callback, _context) { // Check whether the result is valid @@ -61,9 +99,12 @@ egw.extend("data", egw.MODULE_APP_LOCAL, function (_app, _wnd) { if (_result.order && _result.data) { // Assemble the correct order uids - for (var i = 0; i < _result.order.length; i++) + if(!(_result.order.length && _result.order[0] && _result.order[0].indexOf(_context.prefix) == 0)) { - _result.order[i] = UID(_result.order[i], _context.prefix); + for (var i = 0; i < _result.order.length; i++) + { + _result.order[i] = UID(_result.order[i], _context.prefix); + } } // Load all data entries that have been sent or delete them @@ -95,6 +136,37 @@ egw.extend("data", egw.MODULE_APP_LOCAL, function (_app, _wnd) { } } + // Check to see if we need long-term caching of the query and its results + if(window.localStorage && _context.prefix && cacheCallback[_context.prefix]) + { + // Ask registered callbacks if we should cache this + for(var i = 0; i < cacheCallback[_context.prefix].length; i++) + { + var cc = cacheCallback[_context.prefix][i]; + var cache_key = false + if(cache_key = cc.callback.call(cc.context, _context)) + { + cache_key = 'cache_' + _context.prefix + '::' + cache_key; + try + { + window.localStorage.setItem(cache_key,JSON.stringify(_result)); + } + catch (e) + { + egw.debug('warning', 'Tried to cache some data', cache_key, e); + + // Maybe ran out of space? Free some up... + if(e.name == 'QuotaExceededError' // storage quota is exceeded, remove cached data + || 'NS_ERROR_DOM_QUOTA_REACHED') // FF-name + { + var count = _clearCache(_context.prefix); + egw.debug('info', 'localStorage full, removed ' + count + ' stored datasets'); + } + } + } + } + } + // Call the callback function and pass the calculated "order" array // as well as the "total" count and the "timestamp" to the listener. if (_callback) @@ -204,6 +276,29 @@ egw.extend("data", egw.MODULE_APP_LOCAL, function (_app, _wnd) { knownUids.slice(typeof _queriedRange.start != "undefined" ? _queriedRange.start:0,KNOWN_UID_LIMIT); } + // Check to see if we have long-term caching of the query and its results + if(window.localStorage && _context.prefix && cacheCallback[_context.prefix]) + { + // Ask registered callbacks if we should cache this + for(var i = 0; i < cacheCallback[_context.prefix].length; i++) + { + var cc = cacheCallback[_context.prefix][i]; + var cache_key = false + if(cache_key = cc.callback.call(cc.context, _context)) + { + cache_key = 'cache_' + _context.prefix + '::' + cache_key; + + var cached = window.localStorage.getItem(cache_key); + if(cached) + { + egw.debug('log', 'Data cached query: ' + cache_key + "\nprocessing..."); + // Call right away with cached data. We'll still ask the server + // though. + parseServerResponse(JSON.parse(cached), _callback, _context); + } + } + } + } var request = egw.json( _app+".etemplate_widget_nextmatch.ajax_get_rows.etemplate", [ @@ -221,8 +316,59 @@ egw.extend("data", egw.MODULE_APP_LOCAL, function (_app, _wnd) { true ); request.sendRequest(); - } + }, + /** + * Turn on long-term client side cache of a particular request + * (cache the nextmatch query results) for fast, immediate response + * with old data. + * + * The request is still sent to the server, and the cache is updated + * with fresh data, and any needed callbacks are called again with + * the fresh data. + * + * @param {string} prefix UID / Application prefix should match the + * individual record prefix + * @param {function} callback A function that will analize the provided fetch + * parameters and return a reproducable cache key, or false to not cache + * the request. + * @param {object} context Context for callback function. + */ + dataCacheRegister: function(prefix, callback, context) + { + if(typeof cacheCallback[prefix] == 'undefined') + { + cacheCallback[prefix] = []; + } + cacheCallback[prefix].push({ + callback: callback, + context: context + }); + }, + + /** + * Unregister a previously registered cache callback + * @param {string} prefix UID / Application prefix should match the + * individual record prefix + * @param {function} [callback] Callback function to un-register. If + * omitted, all functions for the prefix will be removed. + */ + dataCacheUnregister: function(prefix, callback) + { + if(typeof callback != 'undefined') + { + for(var i = 0; i < cacheCallback[prefix].length; i++) + { + if(cacheCallback[prefix][i].callback == callback) + { + cacheCallback[prefix].splice(i,1); + return; + } + } + } + // Callback not provided or not found, reset by prefix + cacheCallback[prefix] = []; + } }; }); From 73c1f064b989a606ffd1257dfa971ef7aa3367f4 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Mon, 28 Jul 2014 21:21:23 +0000 Subject: [PATCH 12/94] Don't send mail rows when opening mail app, but use client side cache instead. Gives large speed improvements when changing to previously opened folders. --- mail/inc/class.mail_ui.inc.php | 2 ++ mail/js/app.js | 35 ++++++++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php index 8d34dd236e..c5717fc10a 100644 --- a/mail/inc/class.mail_ui.inc.php +++ b/mail/inc/class.mail_ui.inc.php @@ -421,6 +421,8 @@ class mail_ui ); } } + + $content[self::$nm_index]['num_rows'] = 0; // Do not send any rows with initial request $content[self::$nm_index]['default_cols'] = 'status,attachments,subject,address,date,size'; // I columns to use if there's no user or default pref (! as first char uses all but the named columns), default all columns $content[self::$nm_index]['csv_fields'] = false; if ($msg) diff --git a/mail/js/app.js b/mail/js/app.js index ea1d711f79..9e0a625df1 100644 --- a/mail/js/app.js +++ b/mail/js/app.js @@ -65,6 +65,11 @@ app.classes.mail = AppJS.extend( */ init: function() { this._super.apply(this,arguments); + + // Turn on client side, persistent cache + // egw.data system runs encapsulated below etemplate, so this must be + // done before the nextmatch is created. + this.egw.dataCacheRegister('mail',this.nm_cache, this); }, /** @@ -81,6 +86,10 @@ app.classes.mail = AppJS.extend( $j(nm).off('refresh'); } } + + // Unregister client side cache + this.egw.dataCacheUnregister('mail'); + delete this.et2_obj; // call parent this._super.apply(this, arguments); @@ -255,6 +264,32 @@ app.classes.mail = AppJS.extend( } }, + /** + * Callback function for dataFetch caching. + * + * We only cache the first chunk (50 rows), and only if search filter is not set, + * but we cache this for every combination of folder, filter & filter2. + * + * @param {object} query_context Query information from egw.dataFetch() + * @returns {string|false} Cache key, or false to not cache + */ + nm_cache: function(query_context) + { + // Only cache first chunk of rows, if no search filter + if((!query_context || !query_context.start) && query_context.count == 0 && !( + query_context.self._filters.search || false) + ) + { + // Make sure keys match, even if some filters are not defined + return JSON.stringify({ + selectedFolder: query_context.self._filters.selectedFolder || '', + filter: query_context.self._filters.filter || '', + filter2: query_context.self._filters.filter2 + }); + } + return false; + }, + /** * mail rebuild Action menu On nm-list * From 2fe7b340818576115bffedc15630026d554b9d8e Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Mon, 28 Jul 2014 22:07:47 +0000 Subject: [PATCH 13/94] Smarter cache expiry based on age --- phpgwapi/js/jsapi/egw_data.js | 43 ++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/phpgwapi/js/jsapi/egw_data.js b/phpgwapi/js/jsapi/egw_data.js index 0a2340290c..69c6ef0a71 100644 --- a/phpgwapi/js/jsapi/egw_data.js +++ b/phpgwapi/js/jsapi/egw_data.js @@ -52,11 +52,11 @@ egw.extend("data", egw.MODULE_APP_LOCAL, function (_app, _wnd) { /** * Looks like too much data is cached. Forget some. * - * Tries to free up localStorage by removing cached data for the given - * prefix, but if none is found it will remove all cached data. + * Tries to free up localStorage by removing the oldest cached data for the + * given prefix, but if none is found it will look at all cached data. * * @param {string} _prefix UID / application prefix - * @returns {Number} Number of cached recordsets removed + * @returns {Number} Number of cached recordsets removed, normally 1. */ function _clearCache(_prefix) { @@ -66,8 +66,21 @@ egw.extend("data", egw.MODULE_APP_LOCAL, function (_app, _wnd) { { if(window.localStorage.key(i).indexOf('cache_'+_prefix) == 0) { - indexes.push(i); - window.localStorage.removeItem(window.localStorage.key(i)); + var key = window.localStorage.key(i); + var cached = JSON.parse(window.localStorage.getItem(key)); + + if(cached.lastModification) + { + indexes.push({ + key: key, + lastModification: cached.lastModification + }); + } + else + { + // No way to know how old it is, just remove it + window.localStorage.removeItem(key); + } } } // Nothing for that prefix? Clear all cached data. @@ -75,6 +88,17 @@ egw.extend("data", egw.MODULE_APP_LOCAL, function (_app, _wnd) { { return _clearCache(''); } + // Found some cached for that prefix, only remove the oldest + else if (indexes.length > 0) + { + indexes.sort(function(a,b) { + if(a.lastModification < b.lastModification) return 1; + if(a.lastModification > b.lastModification) return -1; + return 0; + }) + window.localStorage.removeItem(indexes.pop().key); + return 1; + } return indexes.length; } @@ -153,15 +177,18 @@ egw.extend("data", egw.MODULE_APP_LOCAL, function (_app, _wnd) { } catch (e) { - egw.debug('warning', 'Tried to cache some data', cache_key, e); - - // Maybe ran out of space? Free some up... + // Maybe ran out of space? Free some up. if(e.name == 'QuotaExceededError' // storage quota is exceeded, remove cached data || 'NS_ERROR_DOM_QUOTA_REACHED') // FF-name { var count = _clearCache(_context.prefix); egw.debug('info', 'localStorage full, removed ' + count + ' stored datasets'); } + // No, something worse happened + else + { + egw.debug('warning', 'Tried to cache some data. It did not work.', cache_key, e); + } } } } From ffb986f560c3bef633b2e1c252086eaaf524cb40 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Mon, 28 Jul 2014 23:11:22 +0000 Subject: [PATCH 14/94] Handle if ID is not a string instead of erroring. --- phpgwapi/js/jsapi/egw_data.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpgwapi/js/jsapi/egw_data.js b/phpgwapi/js/jsapi/egw_data.js index 69c6ef0a71..3c3a15b770 100644 --- a/phpgwapi/js/jsapi/egw_data.js +++ b/phpgwapi/js/jsapi/egw_data.js @@ -123,7 +123,7 @@ egw.extend("data", egw.MODULE_APP_LOCAL, function (_app, _wnd) { if (_result.order && _result.data) { // Assemble the correct order uids - if(!(_result.order.length && _result.order[0] && _result.order[0].indexOf(_context.prefix) == 0)) + if(!(_result.order.length && _result.order[0] && _result.order[0].indexOf && _result.order[0].indexOf(_context.prefix) == 0)) { for (var i = 0; i < _result.order.length; i++) { From af749e891e9d59a3466fe45af55562484d58313a Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Tue, 29 Jul 2014 08:13:34 +0000 Subject: [PATCH 15/94] * Mail: handle broken filenames (non utf8) in attachments --- mail/inc/class.mail_ui.inc.php | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php index c5717fc10a..376c90f240 100644 --- a/mail/inc/class.mail_ui.inc.php +++ b/mail/inc/class.mail_ui.inc.php @@ -2100,8 +2100,24 @@ class mail_ui foreach ($attachments as $key => $value) { - if (function_exists('mb_convert_variables')) mb_convert_variables("UTF-8","ISO-8559-1",$value['name']); # iso 2 UTF8 - $attachmentHTML[$key]['filename']= ($value['name'] ? ( $filename ? $filename : $value['name'] ) : lang('(no subject)')); + $attachmentHTML[$key]['filename']= ($value['name'] ? ( $value['filename'] ? $value['filename'] : $value['name'] ) : lang('(no subject)')); + $test = @json_encode($attachmentHTML[$key]['filename']); + //error_log(__METHOD__.__LINE__.' ->'.strlen($singleBodyPart['body']).' Error:'.json_last_error().'<- BodyPart:#'.$test.'#'); + if (($test=="null" || $test === false || is_null($test)) && strlen($attachmentHTML[$key]['filename'])>0) + { + // try to fix broken utf8 + $x = utf8_encode($attachmentHTML[$key]['filename']); + $test = @json_encode($x); + if (($test=="null" || $test === false || is_null($test)) && strlen($attachmentHTML[$key]['filename'])>0) + { + // this should not be needed, unless something fails with charset detection/ wrong charset passed + $attachmentHTML[$key]['filename'] = (function_exists('mb_convert_encoding')?mb_convert_encoding($attachmentHTML[$key]['filename'],'UTF-8','UTF-8'):(function_exists('iconv')?@iconv("UTF-8","UTF-8//IGNORE",$attachmentHTML[$key]['filename']):$attachmentHTML[$key]['filename'])); + } + else + { + $attachmentHTML[$key]['filename'] = $x; + } + } $attachmentHTML[$key]['type']=$value['mimeType']; $attachmentHTML[$key]['mimetype']=mime_magic::mime2label($value['mimeType']); $attachmentHTML[$key]['size']=egw_vfs::hsize($value['size']); From 235888ad886e4a76f0800927066789aba56b2545 Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Tue, 29 Jul 2014 12:50:39 +0000 Subject: [PATCH 16/94] fix typo, that prevented the correct split of TreeNodeOpenItems --- etemplate/js/et2_widget_tree.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etemplate/js/et2_widget_tree.js b/etemplate/js/et2_widget_tree.js index 75b4616fb5..4ed5148739 100644 --- a/etemplate/js/et2_widget_tree.js +++ b/etemplate/js/et2_widget_tree.js @@ -687,7 +687,7 @@ var et2_tree = et2_inputWidget.extend( */ getTreeNodeOpenItems: function (_nodeID, mode) { if(this.input == null) return null; - var z = this.input.getSubItems(_nodeID).split(","); + var z = this.input.getSubItems(_nodeID).split(this.input.dlmtr); var oS; var PoS; var rv; From 81dc9a9be3de2bb13a41a9504f5e7577dc2e4a36 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Tue, 29 Jul 2014 15:02:46 +0000 Subject: [PATCH 17/94] Make sure all DOMSubtrees are loaded before trigger the print job on window onload. Fix error "getComputing is not function" when closing the window while the print preview is loaded --- infolog/js/app.js | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/infolog/js/app.js b/infolog/js/app.js index af8ce4e6a8..8a82642c70 100644 --- a/infolog/js/app.js +++ b/infolog/js/app.js @@ -58,8 +58,7 @@ app.classes.infolog = AppJS.extend( break; case 'infolog.edit.print': // Trigger print command if the infolog oppend for printing porpuse - var that = this; - jQuery('#infolog-edit-print').bind('load',function(){that.infolog_print_preview();}); + this.infolog_print_preview_onload(); } }, @@ -372,12 +371,36 @@ app.classes.infolog = AppJS.extend( egw_open(id,'infolog','edit',{print:1}); }, + /** + * Trigger print() onload window + */ + infolog_print_preview_onload: function () + { + var that = this; + jQuery('#infolog-edit-print').bind('load',function(){ + var isLoadingCompleted = true; + jQuery('#infolog-edit-print').bind("DOMSubtreeModified",function(event){ + isLoadingCompleted = false; + jQuery('#infolog-edit-print').unbind("DOMSubtreeModified"); + }); + setTimeout(function(){isLoadingCompleted = false},1000); + var interval = setInterval(function(){ + if (!isLoadingCompleted) + { + clearInterval(interval); + that.infolog_print_preview(); + } + + }, 100); + }); + }, + /** * Trigger print() function to print the current window */ - infolog_print_preview: function () + infolog_print_preview: function() { - this.egw.message('Printing....'); + this.egw.message('Printing...'); this.egw.window.print(); }, From cf9616fa0cb31512a4a1b7f2c0d04d63938b2b9c Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Tue, 29 Jul 2014 15:56:48 +0000 Subject: [PATCH 18/94] Avoid iframe, fixes favorites giving error after trying an invalid path --- filemanager/inc/class.filemanager_ui.inc.php | 1 + 1 file changed, 1 insertion(+) diff --git a/filemanager/inc/class.filemanager_ui.inc.php b/filemanager/inc/class.filemanager_ui.inc.php index 751822797f..9b34d8be29 100644 --- a/filemanager/inc/class.filemanager_ui.inc.php +++ b/filemanager/inc/class.filemanager_ui.inc.php @@ -736,6 +736,7 @@ class filemanager_ui egw::redirect_link('/index.php',array('menuaction'=>'filemanager.filemanager_ui.index', 'path' => self::get_home_dir(), 'msg' => lang('The requested path %1 is not available.',egw_vfs::decodePath($query['path'])), + 'ajax' => 'true' )); } $rows = $dir_is_writable = array(); From 6689ca64f7587b3e7689605dce73fd3b6f89531a Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Tue, 29 Jul 2014 17:39:35 +0000 Subject: [PATCH 19/94] SelectAccount with type "none" should get sel_options but it should be readonly if user has no admin access. Fix infolog delegation for admin users with selectAccount type "none" selected --- etemplate/inc/class.etemplate_widget_menupopup.inc.php | 4 +++- etemplate/js/et2_widget_selectAccount.js | 1 - infolog/inc/class.infolog_ui.inc.php | 2 -- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/etemplate/inc/class.etemplate_widget_menupopup.inc.php b/etemplate/inc/class.etemplate_widget_menupopup.inc.php index 9587edf56d..e408e81b0f 100644 --- a/etemplate/inc/class.etemplate_widget_menupopup.inc.php +++ b/etemplate/inc/class.etemplate_widget_menupopup.inc.php @@ -199,8 +199,10 @@ class etemplate_widget_menupopup extends etemplate_widget { // Check selection preference, we may be able to skip reading some data $select_pref = $GLOBALS['egw_info']['user']['preferences']['common']['account_selection']; - if($this->attrs['type'] == 'select-account' && !$GLOBALS['egw_info']['apps']['admin'] && $select_pref == 'none') + if($this->attrs['type'] == 'select-account' && !$GLOBALS['egw_info']['user']['apps']['admin'] && $select_pref == 'none') { + self::$request->preserv[$this->id] = self::$request->content[$this->id]; + unset(self::$request->content[$this->id]); $this->attrs['readonly'] = true; } diff --git a/etemplate/js/et2_widget_selectAccount.js b/etemplate/js/et2_widget_selectAccount.js index b4f2de90cd..e56f9c0a16 100644 --- a/etemplate/js/et2_widget_selectAccount.js +++ b/etemplate/js/et2_widget_selectAccount.js @@ -111,7 +111,6 @@ var et2_selectAccount = et2_selectbox.extend( switch(type) { case 'none': - break; case 'selectbox': case 'groupmembers': default: diff --git a/infolog/inc/class.infolog_ui.inc.php b/infolog/inc/class.infolog_ui.inc.php index 9272307cc6..68952376c2 100644 --- a/infolog/inc/class.infolog_ui.inc.php +++ b/infolog/inc/class.infolog_ui.inc.php @@ -2060,8 +2060,6 @@ class infolog_ui { $readonlys['tabs']['project'] = true; // disable the project tab } - $readonlys['tabs']['delegation'] = $GLOBALS['egw_info']['user']['preferences']['common']['account_selection'] == 'none' && - !isset($GLOBALS['egw_info']['user']['apps']['admin']); $content['duration_format'] = $this->duration_format; $content['hours_per_workday'] = $this->hours_per_workday; From 795e2cdb9c7c404e78d437e844ff691fe330ff6b Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Tue, 29 Jul 2014 21:46:01 +0000 Subject: [PATCH 20/94] Refine cache check conditions, rows is always empty by this point. --- etemplate/js/et2_extension_nextmatch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etemplate/js/et2_extension_nextmatch.js b/etemplate/js/et2_extension_nextmatch.js index 4c165b30b0..b66028f211 100644 --- a/etemplate/js/et2_extension_nextmatch.js +++ b/etemplate/js/et2_extension_nextmatch.js @@ -1512,7 +1512,7 @@ var et2_nextmatch = et2_DOMWidget.extend([et2_IResizeable, et2_IInput], // If no data was sent from the server, and num_rows is 0, the nm will be empty. // This triggers a cache check. - if(!(this.options.settings.rows && this.options.settings.num_rows)) + if(!this.options.settings.num_rows) { this.controller.update(); } From 5b873215b0228083e5528b2b187b2ab5a0a8cf18 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Tue, 29 Jul 2014 21:51:37 +0000 Subject: [PATCH 21/94] - Fix expanding closed projects by passing parent ID - Fix missing milestone icon --- etemplate/js/et2_widget_gantt.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/etemplate/js/et2_widget_gantt.js b/etemplate/js/et2_widget_gantt.js index 764ea0a8a7..0ec7abe235 100644 --- a/etemplate/js/et2_widget_gantt.js +++ b/etemplate/js/et2_widget_gantt.js @@ -229,6 +229,8 @@ var et2_gantt = et2_valueWidget.extend([et2_IResizeable,et2_IInput], set_value: function(value) { if(this.gantt == null) return false; + this.gantt.clearAll(); + // Ensure proper format, no extras var safe_value = { data: value.data || [], @@ -505,11 +507,12 @@ var et2_gantt = et2_valueWidget.extend([et2_IResizeable,et2_IInput], // Bind AJAX for dynamic expansion // TODO: This could be improved this.gantt.attachEvent("onTaskOpened", function(id, item) { + var task = this.getTask(id); // Node children are already there & displayed var value = gantt_widget.getInstanceManager().getValues(gantt_widget.getInstanceManager().widgetContainer); var request = gantt_widget.egw().json(gantt_widget.options.autoload, - [id,value], + [id,value,task.parent||false], function(data) { this.parse(data); }, @@ -732,7 +735,7 @@ et2_register_widget(et2_gantt, ["gantt"]); $j(function() { // Set icon to match application gantt.templates.grid_file = function(item) { - if(!item.pe_app || !egw.image(item.pe_icon)) return "
"; + if(!item.pe_icon || !egw.image(item.pe_icon)) return "
"; return "
"; } From d21e2b2dd7678ad4d2fc0946b1212127aca9eb40 Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Tue, 29 Jul 2014 22:10:48 +0000 Subject: [PATCH 22/94] Avoid error if _filters is not set --- mail/js/app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mail/js/app.js b/mail/js/app.js index 9e0a625df1..73f02b93e3 100644 --- a/mail/js/app.js +++ b/mail/js/app.js @@ -277,7 +277,7 @@ app.classes.mail = AppJS.extend( { // Only cache first chunk of rows, if no search filter if((!query_context || !query_context.start) && query_context.count == 0 && !( - query_context.self._filters.search || false) + !query_context.self._filters || query_context.self._filters.search || false) ) { // Make sure keys match, even if some filters are not defined From 5114fbe11a6e4d3351bd857aa2c72dd105d3d2d8 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Wed, 30 Jul 2014 14:17:38 +0000 Subject: [PATCH 23/94] Add timesheet ID to nm listview --- timesheet/templates/default/index.xet | 2 ++ 1 file changed, 2 insertions(+) diff --git a/timesheet/templates/default/index.xet b/timesheet/templates/default/index.xet index f865f61232..9656a67858 100644 --- a/timesheet/templates/default/index.xet +++ b/timesheet/templates/default/index.xet @@ -28,6 +28,7 @@ + @@ -67,6 +68,7 @@ + From ef6aed6579d2d572ed3a5533ab36f405c51cda24 Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Wed, 30 Jul 2014 15:12:05 +0000 Subject: [PATCH 24/94] Make sure we are getting the current appName --- etemplate/js/et2_widget_link.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etemplate/js/et2_widget_link.js b/etemplate/js/et2_widget_link.js index d3578098f4..1dd202cb83 100644 --- a/etemplate/js/et2_widget_link.js +++ b/etemplate/js/et2_widget_link.js @@ -912,7 +912,7 @@ var et2_link_entry = et2_inputWidget.extend( // Remove specific display and revert to CSS file // show() would use inline, should be inline-block this.clear.css('display',''); - this.request = egw.json(this.egw().getAppName() + ".etemplate_widget_link.ajax_link_search.etemplate", + this.request = egw.json(egw_getAppName() + ".etemplate_widget_link.ajax_link_search.etemplate", [this.app_select.val(), '', request.term, request.options], this._results, this,true,this From c1c90c262108a91f8a80e05272fff43fe12dae25 Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Thu, 31 Jul 2014 10:10:07 +0000 Subject: [PATCH 25/94] cache subscribedFolders Call to be used in getfolderStatus; control param if to fetch subscribed Info on getFolderStatus at all; own getMailboxCounters wrapper, instead of getFolderStatus, if one needs the counters only --- mail/inc/class.mail_ui.inc.php | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php index 376c90f240..ab55f90448 100644 --- a/mail/inc/class.mail_ui.inc.php +++ b/mail/inc/class.mail_ui.inc.php @@ -875,8 +875,10 @@ class mail_ui if ($levelCt>$cmblevelsCt+1) $fetchCounters=false; } //error_log(__METHOD__.__LINE__.' fc:'.$fetchCounters.'/'.$_fetchCounters.'('.$levelCt.'/'.$cmblevelsCt.')'.' for:'.array2string($key)); - $fS = $this->mail_bo->getFolderStatus($key,false,($fetchCounters?false:true)); - //error_log(__METHOD__.__LINE__.array2string($fS)); + $fS = $this->mail_bo->getFolderStatus($key,false,($fetchCounters?false:true),false); + //error_log(__METHOD__.__LINE__.'Object:'.array2string($obj)); + //error_log(__METHOD__.__LINE__.'Status:'.array2string($fS)); + //error_log(__METHOD__.__LINE__."-------------------------"); $fFP = $folderParts = explode($obj->delimiter, $key); if (in_array($key,$userDefinedFunctionFolders)) $obj->shortDisplayName = lang($obj->shortDisplayName); //get rightmost folderpart @@ -3323,7 +3325,7 @@ class mail_ui if ($profileID != $this->mail_bo->profileID) continue; // only current connection if ($folderName) { - $fS = $this->mail_bo->getFolderStatus($folderName,false); + $fS = $this->mail_bo->getFolderStatus($folderName,false,false,false); if (in_array($fS['shortDisplayName'],mail_bo::$autoFolders)) $fS['shortDisplayName']=lang($fS['shortDisplayName']); //error_log(__METHOD__.__LINE__.array2string($fS)); if ($fS['unseen']) @@ -3565,7 +3567,7 @@ class mail_ui if (!empty($folderName)) { $parentFolder=(!empty($folderName)?$folderName:'INBOX'); - $folderInfo = $this->mail_bo->getFolderStatus($parentFolder,false); + $folderInfo = $this->mail_bo->getFolderStatus($parentFolder,false,false,false); if ($folderInfo['unseen']) { $folderInfo['shortDisplayName'] = $folderInfo['shortDisplayName'].' ('.$folderInfo['unseen'].')'; @@ -3629,7 +3631,7 @@ class mail_ui strpos($parentFolder,$folderName)===false)))) // indicates that we move the older up the tree within its own branch { //error_log(__METHOD__.__LINE__."$folderName, $parentFolder, $_newName"); - $oldFolderInfo = $this->mail_bo->getFolderStatus($folderName,false); + $oldFolderInfo = $this->mail_bo->getFolderStatus($folderName,false,false,false); //error_log(__METHOD__.__LINE__.array2string($oldFolderInfo)); if (!empty($oldFolderInfo['attributes']) && stripos(array2string($oldFolderInfo['attributes']),'\hasnochildren')=== false) { @@ -3674,7 +3676,7 @@ class mail_ui $msg = $e->getMessage(); } $this->mail_bo->reopen($parentFolder); - $this->mail_bo->getFolderStatus($parentFolder,false); + $this->mail_bo->getFolderStatus($parentFolder,false,false,false); //error_log(__METHOD__.__LINE__.array2string($fS)); if ($hasChildren) { @@ -3706,8 +3708,8 @@ class mail_ui { translation::add_app('mail'); - $oldFolderInfo = $this->mail_bo->getFolderStatus($oldParentFolder,false); - $folderInfo = $this->mail_bo->getFolderStatus($parentFolder,false); + $oldFolderInfo = $this->mail_bo->getFolderStatus($oldParentFolder,false,false,false); + $folderInfo = $this->mail_bo->getFolderStatus($parentFolder,false,false,false); $refreshData = array( $profileID.self::$delimiter.$oldParentFolder=>$oldFolderInfo['shortDisplayName'], $profileID.self::$delimiter.$parentFolder=>$folderInfo['shortDisplayName']); @@ -3756,7 +3758,7 @@ class mail_ui //error_log(__METHOD__.__LINE__."$folderName, implode($del,$pA), $_newName"); $oA = array(); $subFolders = array(); - $oldFolderInfo = $this->mail_bo->getFolderStatus($folderName,false); + $oldFolderInfo = $this->mail_bo->getFolderStatus($folderName,false,false,false); //error_log(__METHOD__.__LINE__.array2string($oldFolderInfo)); if (!empty($oldFolderInfo['attributes']) && stripos(array2string($oldFolderInfo['attributes']),'\hasnochildren')=== false) { @@ -4015,7 +4017,7 @@ class mail_ui } if ($rememberServerID != $this->mail_bo->profileID) { - $oldFolderInfo = $this->mail_bo->getFolderStatus($trashFolder,false); + $oldFolderInfo = $this->mail_bo->getFolderStatus($trashFolder,false,false,false); $response = egw_json_response::get(); $response->call('egw.message',lang('empty trash')); $response->call('app.mail.mail_reloadNode',array($icServerID.self::$delimiter.$trashFolder=>$oldFolderInfo['shortDisplayName'])); From 8ccef246b485b8fa866abbefba2d61a088869a9f Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Thu, 31 Jul 2014 10:18:41 +0000 Subject: [PATCH 26/94] Do not openConnection an extra time to imap server on constructor for changeProfile, refreshQuotaDisplay --- mail/inc/class.mail_ui.inc.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php index ab55f90448..61b9820f13 100644 --- a/mail/inc/class.mail_ui.inc.php +++ b/mail/inc/class.mail_ui.inc.php @@ -126,7 +126,13 @@ class mail_ui $this->mail_bo = mail_bo::getInstance(true,self::$icServerID); if (mail_bo::$debug) error_log(__METHOD__.__LINE__.' Fetched IC Server:'.self::$icServerID.'/'.$this->mail_bo->profileID.':'.function_backtrace()); //error_log(__METHOD__.__LINE__.array2string($this->mail_bo->icServer)); - if ($_GET['menuaction'] != 'mail.etemplate_widget_nextmatch.ajax_get_rows.etemplate') + + // RegEx to minimize extra openConnection + $needle = '/mail.etemplate_widget_nextmatch.ajax_get_rows.etemplate|' + . 'mail.mail_ui.ajax_refreshQuotaDisplay|' + . 'mail.mail_ui.ajax_changeProfile|' + . '^(?!mail)/'; + if (!preg_match($needle,$_GET['menuaction'])) { //error_log(__METHOD__.__LINE__.' Fetched IC Server openConnection:'.self::$icServerID.'/'.$this->mail_bo->profileID.':'.function_backtrace()); //openConnection gathers SpecialUseFolderInformation and Delimiter Info From 14711b891f3d1c685ee5ab907f6b824b3e767201 Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Thu, 31 Jul 2014 10:42:56 +0000 Subject: [PATCH 27/94] fix call for mail.mail_ui.ajax_refreshQuotaDisplay; as the refresh of quota was not working after changing a profile after rev47954 --- mail/inc/class.mail_ui.inc.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php index 61b9820f13..cc41373b3a 100644 --- a/mail/inc/class.mail_ui.inc.php +++ b/mail/inc/class.mail_ui.inc.php @@ -3974,9 +3974,10 @@ class mail_ui //error_log(__METHOD__.__LINE__.' change Profile to ->'.$icServerID); $this->changeProfile($icServerID); } - if($this->mail_bo->connectionStatus !== false) { + try + { $quota = $this->mail_bo->getQuotaRoot(); - } else { + } catch (Exception $e) { $quota['limit'] = 'NOT SET'; } From 3358da94e58bfb51d5d3618253c492150497a4f5 Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Thu, 31 Jul 2014 10:47:55 +0000 Subject: [PATCH 28/94] alter condion on not calling openConnection; as the refresh of quota was not working after changing a profile after rev47954 and not relyable after rev47956 --- mail/inc/class.mail_ui.inc.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php index cc41373b3a..8b4cbcddfb 100644 --- a/mail/inc/class.mail_ui.inc.php +++ b/mail/inc/class.mail_ui.inc.php @@ -129,7 +129,7 @@ class mail_ui // RegEx to minimize extra openConnection $needle = '/mail.etemplate_widget_nextmatch.ajax_get_rows.etemplate|' - . 'mail.mail_ui.ajax_refreshQuotaDisplay|' +// . 'mail.mail_ui.ajax_refreshQuotaDisplay|' . 'mail.mail_ui.ajax_changeProfile|' . '^(?!mail)/'; if (!preg_match($needle,$_GET['menuaction'])) From f6e5b613276930133f6719f791f08413ce719e2a Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Thu, 31 Jul 2014 11:47:49 +0000 Subject: [PATCH 29/94] pending translations from our translation server --- phpgwapi/lang/egw_de.lang | 3 ++- phpgwapi/lang/egw_en.lang | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/phpgwapi/lang/egw_de.lang b/phpgwapi/lang/egw_de.lang index 1010586433..16392f5a6e 100644 --- a/phpgwapi/lang/egw_de.lang +++ b/phpgwapi/lang/egw_de.lang @@ -518,6 +518,7 @@ netherlands antilles common de NIEDERLÄNDISCHE ANTILLEN never common de Niemals new caledonia common de NEU CALEDONIEN new entry added sucessfully common de Neuer Eintrag wurde erfolgreich hinzugefügt +new favorite common de Erstellen Sie hier einen neuen Favorit new main category common de neue Hauptkategorie new value common de Neuer Wert new zealand common de NEUSEELAND @@ -832,7 +833,7 @@ unconnected nodes will be moved to %1. admin de Nicht Verbundene Knoten werden n underline common de Unterstrichen unicode common de Unicode united arab emirates common de VEREINIGTEN ARABISCHEN EMIRATE -united kingdom common de GROSSBRITANIEN +united kingdom common de GROSSBRITANNIEN united states common de VEREINIGTE STAATEN VON AMERIKA united states minor outlying islands common de UNITED STATES MINOR OUTLYING ISLANDS unknown common de Unbekannt diff --git a/phpgwapi/lang/egw_en.lang b/phpgwapi/lang/egw_en.lang index 3a9d29775c..eba99f4f09 100644 --- a/phpgwapi/lang/egw_en.lang +++ b/phpgwapi/lang/egw_en.lang @@ -518,6 +518,7 @@ netherlands antilles common en NETHERLANDS ANTILLES never common en Never new caledonia common en NEW CALEDONIA new entry added sucessfully common en New entry added successfully. +new favorite common en New favorite new main category common en New main category new value common en New value new zealand common en NEW ZEALAND From 3f2eddc0c7e1e9b378b1cd4cbbc45c82fcee669a Mon Sep 17 00:00:00 2001 From: Hadi Nategh Date: Thu, 31 Jul 2014 17:43:33 +0000 Subject: [PATCH 30/94] Fix confilict ID in filemanager file dialog. Additionally, add "Cancel button to superuser authentication form" --- filemanager/templates/default/file.xet | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/filemanager/templates/default/file.xet b/filemanager/templates/default/file.xet index 9b0cfe67e7..896f51f96c 100644 --- a/filemanager/templates/default/file.xet +++ b/filemanager/templates/default/file.xet @@ -276,7 +276,7 @@