From bec51776a496345cf5d6253fa9a9daf6ce8ef913 Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Mon, 29 Apr 2013 08:43:42 +0000 Subject: [PATCH 01/84] we set allowedContent to true as the 4.1 contentFiltering system allows only activated features as content --- phpgwapi/inc/class.egw_ckeditor_config.inc.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/phpgwapi/inc/class.egw_ckeditor_config.inc.php b/phpgwapi/inc/class.egw_ckeditor_config.inc.php index 71719ffbee..a1257bc8e2 100644 --- a/phpgwapi/inc/class.egw_ckeditor_config.inc.php +++ b/phpgwapi/inc/class.egw_ckeditor_config.inc.php @@ -212,6 +212,8 @@ class egw_ckeditor_config $config['entities_latin'] = false; $config['editingBlock'] = true; $config['disableNativeSpellChecker'] = true; + // we set allowedContent to true as the 4.1 contentFiltering system allows only activated features as content + $config['allowedContent'] = true; $config['removePlugins'] = 'elementspath'; From 035e4b32b6090f8e0723a38a64670bf62c6f3862 Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Mon, 29 Apr 2013 14:56:33 +0000 Subject: [PATCH 02/84] implement move7copy mails; rename folder simple renanme implemented. refresh of tree still to be done, if renaming a leaf inbetween --- mail/inc/class.mail_bo.inc.php | 57 +++++++++++++++++- mail/inc/class.mail_bopreferences.inc.php | 18 ++++-- mail/inc/class.mail_ui.inc.php | 73 +++++++++++++++++++++-- mail/js/app.js | 15 ++++- 4 files changed, 151 insertions(+), 12 deletions(-) diff --git a/mail/inc/class.mail_bo.inc.php b/mail/inc/class.mail_bo.inc.php index 7f161b8589..5a88db2b2d 100644 --- a/mail/inc/class.mail_bo.inc.php +++ b/mail/inc/class.mail_bo.inc.php @@ -1617,7 +1617,7 @@ class mail_bo $HierarchyDelimiter = $this->getHierarchyDelimiter(); $newFolderName = $parent . $HierarchyDelimiter . $folderName; } - if (self::$debug); error_log("create folder: $newFolderName"); + if (self::$debug) error_log("create folder: $newFolderName"); $rv = $this->icServer->renameMailbox($oldFolderName, $newFolderName); if ( PEAR::isError($rv) ) { if (self::$debug) error_log(__METHOD__." failed for $oldFolderName, $newFolderName with error: ".print_r($rv->message,true)); @@ -2662,6 +2662,61 @@ class mail_bo return true; // as we do not catch/examine setFlags returnValue } + /** + * move Message(s) + * + * @param string _foldername target folder + * @param mixed array/string _messageUID array of ids to flag, or 'all' + * @param boolean $deleteAfterMove - decides if a mail is moved (true) or copied (false) + * @param string $currentFolder + * @param boolean $returnUIDs - control wether or not the action called should return the new uids + * caveat: not all servers do support that + * + * @return mixed/bool true,false or new uid + */ + function moveMessages($_foldername, $_messageUID, $deleteAfterMove=true, $currentFolder = Null, $returnUIDs = false) + { + $msglist = ''; + + $deleteOptions = $GLOBALS['egw_info']["user"]["preferences"]["mail"]["deleteOptions"]; + $retUid = $this->icServer->copyMessages($_foldername, $_messageUID, (!empty($currentFolder)?$currentFolder: $this->sessionData['mailbox']), true, $returnUIDs); + if ( PEAR::isError($retUid) ) { + error_log(__METHOD__.__LINE__."Copying to Folder $_foldername failed! PEAR::Error:".array2string($retUid->message)); + throw new egw_exception("Copying to Folder $_foldername failed! PEAR::Error:".array2string($retUid->message)); + return false; + } + if ($deleteAfterMove === true) + { + $retValue = $this->icServer->deleteMessages($_messageUID, true); + if ( PEAR::isError($retValue)) + { + error_log(__METHOD__.__LINE__."Delete After Move PEAR::Error:".array2string($retValue->message)); + throw new egw_exception("Delete After Move PEAR::Error:".array2string($retValue->message)); + return false; + } + + if($deleteOptions != "mark_as_deleted") + { + $structure = egw_cache::getCache(egw_cache::INSTANCE,'email','structureCache'.trim($GLOBALS['egw_info']['user']['account_id']),$callback=null,$callback_params=array(),$expiration=60*60*1); + $cachemodified = false; + foreach ((array)$_messageUID as $k => $_uid) + { + if (isset($structure[$this->icServer->ImapServerId][(!empty($currentFolder)?$currentFolder: $this->sessionData['mailbox'])][$_uid])) + { + $cachemodified = true; + unset($structure[$this->icServer->ImapServerId][(!empty($currentFolder)?$currentFolder: $this->sessionData['mailbox'])][$_uid]); + } + } + if ($cachemodified) egw_cache::setCache(egw_cache::INSTANCE,'email','structureCache'.trim($GLOBALS['egw_info']['user']['account_id']),$structure,$expiration=60*60*1); + + // delete the messages finaly + $this->icServer->expunge(); + } + } + //error_log(__METHOD__.__LINE__.array2string($retUid)); + return ($returnUIDs ? $retUid : true); + } + /** * Helper function to handle wrong or unrecognized timezones * returns the date as it is parseable by strtotime, or current timestamp if everything failes diff --git a/mail/inc/class.mail_bopreferences.inc.php b/mail/inc/class.mail_bopreferences.inc.php index 3c713bb2d0..f350ce4e90 100644 --- a/mail/inc/class.mail_bopreferences.inc.php +++ b/mail/inc/class.mail_bopreferences.inc.php @@ -47,7 +47,6 @@ class mail_bopreferences extends mail_sopreferences * constructor * * @param boolean $_restoreSession=true - */ function __construct($_restoreSession = true) { @@ -438,7 +437,15 @@ class mail_bopreferences extends mail_sopreferences parent::deleteAccountData($GLOBALS['egw_info']['user']['account_id'], $identity); } - function setProfileActive($_status, $_identity=NULL) + /** + * setProfileActive + * sets the profile given as active; updates database via parent call + * @param boolean $_status + * @param int $_identityID=NULL Identity to update. + * @param boolean $_identityOnly indicates, that the profile represented by id ($_identity) is an identity only (true), or a full mailprofile (false) + * @return void + */ + function setProfileActive($_status, $_identity=NULL, $_identityOnly=false) { $this->sessionData = array(); $this->saveSessionData(); @@ -446,11 +453,12 @@ class mail_bopreferences extends mail_sopreferences { //error_log(__METHOD__.__LINE__.' change status of Profile '.$_identity.' to '.$_status); // globals preferences add appname varname value - $GLOBALS['egw']->preferences->add('mail','ActiveProfileID',$_identity,'user'); + if (!$_identityOnly) $GLOBALS['egw']->preferences->add('mail','ActiveProfileID',$_identity,'user'); // save prefs - $GLOBALS['egw']->preferences->save_repository(true); - egw_cache::setSession('mail','activeProfileID',$_identity); + if (!$_identityOnly) $GLOBALS['egw']->preferences->save_repository(true); + if (!$_identityOnly) egw_cache::setSession('mail','activeProfileID',$_identity); } + // the parentCall only saves the database value parent::setProfileActive($GLOBALS['egw_info']['user']['account_id'], $_status, $_identity); } } diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php index a13a8e033b..bd1496a0b3 100644 --- a/mail/inc/class.mail_ui.inc.php +++ b/mail/inc/class.mail_ui.inc.php @@ -2181,11 +2181,11 @@ blockquote[type=cite] { //error_log(__METHOD__.__LINE__.' OldFolderName:'.array2string($_folderName).' NewName:'.array2string($_newName)); if ($_folderName) { - $_folderName = $this->mail_bo->decodeEntityFolderName($_folderName); + $decodedFolderName = $this->mail_bo->decodeEntityFolderName($_folderName); $_newName = translation::convert($this->mail_bo->decodeEntityFolderName($_newName), $this->charset, 'UTF7-IMAP'); $del = $this->mail_bo->getHierarchyDelimiter(false); $oA = array(); - list($profileID,$folderName) = explode(self::$delimiter,$_folderName,2); + list($profileID,$folderName) = explode(self::$delimiter,$decodedFolderName,2); if (is_numeric($profileID)) { if ($profileID != $this->mail_bo->profileID) return; // only current connection @@ -2195,26 +2195,33 @@ blockquote[type=cite] { if (strtoupper($folderName)!= 'INBOX') { //error_log(__METHOD__.__LINE__."$folderName, $parentFolder, $_newName"); + $this->mail_bo->reopen('INBOX'); if($newFolderName = $this->mail_bo->renameFolder($folderName, $parentFolder, $_newName)) { $this->mail_bo->resetFolderObjectCache($profileID); //enforce the subscription to the newly named server, as it seems to fail for names with umlauts $rv = $this->mail_bo->subscribe($newFolderName, true); $rv = $this->mail_bo->subscribe($folderName, false); } + $this->mail_bo->reopen($newFolderName); $fS = $this->mail_bo->getFolderStatus($newFolderName,false); //error_log(__METHOD__.__LINE__.array2string($fS)); + $oA[$_folderName]['id'] = $profileID.self::$delimiter.$newFolderName; if ($fS['unseen']) { - $oA[$_folderName] = ''.$fS['shortDisplayName'].' ('.$fS['unseen'].')'; + $oA[$_folderName]['desc'] = ''.$fS['shortDisplayName'].' ('.$fS['unseen'].')'; } + else + { + $oA[$_folderName]['desc'] = $fS['shortDisplayName']; + } } } //error_log(__METHOD__.__LINE__.array2string($oA)); if ($oA) { $response = egw_json_response::get(); - $response->call('app.mail.mail_setFolderStatus',$oA,'mail'); + $response->call('app.mail.mail_setLeaf',$oA,'mail'); } } } @@ -2361,8 +2368,36 @@ blockquote[type=cite] { */ function ajax_moveMessages($_folderName, $_messageList) { - if(mail_bo::$debug); error_log(__METHOD__."->".$_folderName.':'.print_r($_messageList,true)); + if(mail_bo::$debug) error_log(__METHOD__."->".$_folderName.':'.print_r($_messageList,true)); + $_folderName = $this->mail_bo->decodeEntityFolderName($_folderName); + list($profileID,$targetFolder) = explode(self::$delimiter,$_folderName,2); + if ($_messageList=='all' || !empty($_messageList['msg'])) + { + if ($_messageList=='all') + { + // we have no folder information + $folder=null; + } + else + { + $uidA = self::splitRowID($_messageList['msg'][0]); + $folder = $uidA['folder']; // all messages in one set are supposed to be within the same folder + } + foreach($_messageList['msg'] as $rowID) + { + $hA = self::splitRowID($rowID); + $messageList[] = $hA['msgUID']; + } + + $this->mail_bo->moveMessages($targetFolder,$messageList,true,$folder); + $response = egw_json_response::get(); + $response->call('egw_refresh',lang('moved %1 message(s) from %2 to %3',count($messageList),$folder,$targetFolder),'mail'); + } + else + { + if(mail_bo::$debug) error_log(__METHOD__."-> No messages selected."); + } } /** @@ -2376,7 +2411,35 @@ blockquote[type=cite] { function ajax_copyMessages($_folderName, $_messageList) { if(mail_bo::$debug); error_log(__METHOD__."->".$_folderName.':'.print_r($_messageList,true)); + $_folderName = $this->mail_bo->decodeEntityFolderName($_folderName); + list($profileID,$targetFolder) = explode(self::$delimiter,$_folderName,2); + if ($_messageList=='all' || !empty($_messageList['msg'])) + { + if ($_messageList=='all') + { + // we have no folder information + $folder=null; + } + else + { + $uidA = self::splitRowID($_messageList['msg'][0]); + $folder = $uidA['folder']; // all messages in one set are supposed to be within the same folder + } + foreach($_messageList['msg'] as $rowID) + { + $hA = self::splitRowID($rowID); + $messageList[] = $hA['msgUID']; + } + + $this->mail_bo->moveMessages($targetFolder,$messageList,false,$folder); + $response = egw_json_response::get(); + $response->call('egw_refresh',lang('copied %1 message(s) from %2 to %3',count($messageList),$folder,$targetFolder),'mail'); + } + else + { + if(mail_bo::$debug) error_log(__METHOD__."-> No messages selected."); + } } } diff --git a/mail/js/app.js b/mail/js/app.js index c980233194..089206ffee 100644 --- a/mail/js/app.js +++ b/mail/js/app.js @@ -169,6 +169,19 @@ app.mail = AppJS.extend( for (var i in _status) ftree.setLabel(i,_status[i]);//alert(i +'->'+_status[i]); }, + /** + * mail_setLeaf, function to set the id and description for the folder given by status key + */ + mail_setLeaf: function(_status) { + //console.log('mail_setLeaf',_status); + var ftree = etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('nm[foldertree]'); + for (var i in _status) + { + ftree.renameItem(i,_status[i]['id'],_status[i]['desc']); + //alert(i +'->'+_status[i]['id']+'+'+_status[i]['desc']); + } + }, + /** * mail_refreshMessageGrid, function to call to reread ofthe current folder */ @@ -583,7 +596,7 @@ app.mail = AppJS.extend( */ mail_copy: function(_action,_senders,_target) { //console.log(_action,_senders,_target); - var target = _action.id == 'drop_copy_mail' ? _target.id : _action.id.substr(5); + var target = _action.id == 'drop_copy_mail' ? _target.iface.id : _action.id.substr(5); var messages = this.mail_getFormData(_senders); //alert('mail_copy('+messages.msg.join(',')+' --> '+target+')'); // TODO: Write move/copy function which cares about doing the same stuff From efd4d85143bd88cdfc24fba746fa775874fa9f4e Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Mon, 29 Apr 2013 14:58:29 +0000 Subject: [PATCH 03/84] add rename of an item. caveat, does not rename dependent leafs yet --- etemplate/js/et2_dataview_controller_selection.js | 2 +- etemplate/js/et2_widget_tree.js | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/etemplate/js/et2_dataview_controller_selection.js b/etemplate/js/et2_dataview_controller_selection.js index 05b5bdf9e1..4490c51562 100644 --- a/etemplate/js/et2_dataview_controller_selection.js +++ b/etemplate/js/et2_dataview_controller_selection.js @@ -182,10 +182,10 @@ var et2_dataview_selectionManager = Class.extend( false)); this._focusedEntry = null; } - // Mark the new given uid as focused if (_focused) { + console.log('et2_dataview_controller_selection::setFocused -> UID:'+_uid+' is focused by:'+this._actionObjectManager.name); var entry = this._focusedEntry = this._getRegisteredRowsEntry(_uid); this._updateEntryState(entry, egwSetBit(entry.state, EGW_AO_STATE_FOCUSED, true)); diff --git a/etemplate/js/et2_widget_tree.js b/etemplate/js/et2_widget_tree.js index 97381d7e53..94093f1c8b 100644 --- a/etemplate/js/et2_widget_tree.js +++ b/etemplate/js/et2_widget_tree.js @@ -391,6 +391,19 @@ var et2_tree = et2_inputWidget.extend( } }, + /** + * renameItem, renames an item by id + * @param _id ID of the node + * @param _newid ID of the node + * @param _label label to set + * @return void + */ + renameItem: function(_id, _newItemId, _label) { + if(this.input == null) return null; + this.input.changeItemId(_id,_newItemId); + if (typeof _label != 'undefined') this.input.setItemText(_newItemId,_label); + }, + /** * setLabel, sets the Label of of an item by id * @param _id ID of the node From 8913df2366f3cdcdfd9fce378717cec945c05e09 Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Mon, 29 Apr 2013 14:59:55 +0000 Subject: [PATCH 04/84] remove console logging on focused --- etemplate/js/et2_dataview_controller_selection.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etemplate/js/et2_dataview_controller_selection.js b/etemplate/js/et2_dataview_controller_selection.js index 4490c51562..adcee340fc 100644 --- a/etemplate/js/et2_dataview_controller_selection.js +++ b/etemplate/js/et2_dataview_controller_selection.js @@ -185,7 +185,7 @@ var et2_dataview_selectionManager = Class.extend( // Mark the new given uid as focused if (_focused) { - console.log('et2_dataview_controller_selection::setFocused -> UID:'+_uid+' is focused by:'+this._actionObjectManager.name); + //console.log('et2_dataview_controller_selection::setFocused -> UID:'+_uid+' is focused by:'+this._actionObjectManager.name); var entry = this._focusedEntry = this._getRegisteredRowsEntry(_uid); this._updateEntryState(entry, egwSetBit(entry.state, EGW_AO_STATE_FOCUSED, true)); From 06ab2ffcdc95b8c4f5ced9a03171b47b9637d9bd Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Mon, 29 Apr 2013 15:32:09 +0000 Subject: [PATCH 05/84] Implement delete import action --- ...ss.addressbook_import_contacts_csv.inc.php | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/addressbook/inc/class.addressbook_import_contacts_csv.inc.php b/addressbook/inc/class.addressbook_import_contacts_csv.inc.php index 575ea299e8..31a1611fcc 100644 --- a/addressbook/inc/class.addressbook_import_contacts_csv.inc.php +++ b/addressbook/inc/class.addressbook_import_contacts_csv.inc.php @@ -212,6 +212,26 @@ class addressbook_import_contacts_csv extends importexport_basic_import_csv { switch ($_action) { case 'none' : return true; + case 'delete': + if($_data['id']) + { + if ( $this->dry_run ) { + //print_r($_data); + $this->results[$_action]++; + return true; + } + $result = $this->bocontacts->delete($_data); + if($result && $result === true) + { + $this->results[$_action]++; + } + else + { + // Failure of some kind - unknown cause + $this->errors[$record_num] = lang('unable to delete'); + } + } + break; case 'update' : // Only update if there are changes $old = $this->bocontacts->read($_data['id']); From 42fd3fe37b18614ad7f7fceea095229b1bc1574a Mon Sep 17 00:00:00 2001 From: Nathan Gray Date: Mon, 29 Apr 2013 18:36:48 +0000 Subject: [PATCH 06/84] Implement optgroups for select widget --- etemplate/js/et2_widget_selectbox.js | 42 ++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/etemplate/js/et2_widget_selectbox.js b/etemplate/js/et2_widget_selectbox.js index d8adea0890..9c480b60e7 100644 --- a/etemplate/js/et2_widget_selectbox.js +++ b/etemplate/js/et2_widget_selectbox.js @@ -231,16 +231,17 @@ var et2_selectbox = et2_inputWidget.extend( /** * Add an option to regular drop-down select */ - _appendOptionElement: function(_value, _label, _title) { + _appendOptionElement: function(_value, _label, _title, dom_element) { if(_value == "" && (_label == null || _label == "")) { _label = this.options.empty_label; } if(this.input == null) { - return this._appendMultiOption(_value, _label, _title); + return this._appendMultiOption(_value, _label, _title, dom_element); } + var option = $j(document.createElement("option")) .attr("value", _value) .text(_label+""); @@ -256,14 +257,14 @@ var et2_selectbox = et2_inputWidget.extend( } else { - option.appendTo(this.input); + option.appendTo(dom_element || this.input); } }, /** * Append a value to multi-select */ - _appendMultiOption: function(_value, _label, _title) { + _appendMultiOption: function(_value, _label, _title, dom_element) { var option_data = null; if(typeof _label == "object") { @@ -309,7 +310,7 @@ var et2_selectbox = et2_inputWidget.extend( label.append(jQuery(""+_label+"")); var li = jQuery(document.createElement("li")).append(label); - li.appendTo(this.multiOptions); + li.appendTo(dom_element || this.multiOptions); }, /** @@ -568,7 +569,36 @@ var et2_selectbox = et2_inputWidget.extend( if (typeof _options[key] === 'object') { - if(this.input == null) + // Optgroup + if(typeof _options[key]["label"] == 'undefined' && typeof _options[key]["title"] == "undefined") + { + var group = $j(document.createElement("optgroup")) + .attr("label", this.options.no_lang ? key : this.egw().lang(key)) + .appendTo(this.input); + if(this.input == null) + { + group = jQuery(document.createElement("ul")) + .append('
  • '+key+'
  • ') + .appendTo(this.multiOptions); + } + + for(var sub in _options[key]) + { + if (typeof _options[key][sub] === 'object') + { + this._appendOptionElement(sub, + _options[key][sub]["label"] ? _options[key][sub]["label"] : "", + _options[key][sub]["title"] ? _options[key][sub]["title"] : "", + group + ); + } + else + { + this._appendOptionElement(key, _options[key][sub],undefined,group); + } + } + } + else if(this.input == null) { // Allow some special extras for objects by passing the whole thing _options[key]["label"] = _options[key]["label"] ? _options[key]["label"] : ""; From 0749b41b29fb15b02d166e89babfd5b6062aebed Mon Sep 17 00:00:00 2001 From: Klaus Leithoff Date: Tue, 30 Apr 2013 14:16:52 +0000 Subject: [PATCH 07/84] unset moved / deleted message store to control preview area --- mail/inc/class.mail_ui.inc.php | 3 ++- mail/js/app.js | 15 ++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/mail/inc/class.mail_ui.inc.php b/mail/inc/class.mail_ui.inc.php index bd1496a0b3..221e196a88 100644 --- a/mail/inc/class.mail_ui.inc.php +++ b/mail/inc/class.mail_ui.inc.php @@ -2120,7 +2120,8 @@ blockquote[type=cite] { function loadEmailBody($_messageID=null) { if (!$_messageID) $_messageID = $_GET['_messageID']; - if(mail_bo::$debug); error_log(__METHOD__."->".$_flag.':'.print_r($_messageID,true)); + if(mail_bo::$debug) error_log(__METHOD__."->".$_flag.':'.print_r($_messageID,true)); + if (empty($_messageID)) return ""; $uidA = self::splitRowID($_messageID); $folder = $uidA['folder']; // all messages in one set are supposed to be within the same folder $messageID = $uidA['msgUID']; diff --git a/mail/js/app.js b/mail/js/app.js index 089206ffee..d831e4a7db 100644 --- a/mail/js/app.js +++ b/mail/js/app.js @@ -64,11 +64,18 @@ app.mail = AppJS.extend( var _id = selected[0]; dataElem = egw.dataGetUIDdata(_id); } - else + if(typeof selected == 'undefined' || selected.length == 0 || typeof dataElem =='undefined') { + var subject =""; + etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('previewFromAddress').set_value(""); + etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('previewToAddress').set_value(""); + etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('previewDate').set_value(""); + etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('previewSubject').set_value(""); + var IframeHandle = etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('messageIFRAME'); + IframeHandle.set_src(egw.link('/index.php',{menuaction:'mail.mail_ui.loadEmailBody',_messageID:""})); return; } - console.log("mail_preview",dataElem); + //console.log("mail_preview",dataElem); var subject =dataElem.data.subject; etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('previewFromAddress').set_value(dataElem.data.fromaddress); etemplate2.getByApplication('mail')[0].widgetContainer.getWidgetById('previewToAddress').set_value(dataElem.data.toaddress); @@ -266,6 +273,7 @@ app.mail = AppJS.extend( this.mail_setRowClass(_elems,'deleted'); var request = new egw_json_request('mail.mail_ui.ajax_deleteMessages',[msg]); request.sendRequest(false); + for (var i = 0; i < msg['msg'].length; i++) egw.dataDeleteUID(msg['msg'][i]); this.mail_refreshMessageGrid(); }, @@ -527,7 +535,7 @@ app.mail = AppJS.extend( messages['msg'] = []; } - for (var i = 0; i < _actionObjects.length; i++) + for (var i = 0; i < _actionObjects.length; i++) { if (_actionObjects[i].id.length>0) { @@ -585,6 +593,7 @@ app.mail = AppJS.extend( // as the "onNodeSelect" function! var request = new egw_json_request('mail.mail_ui.ajax_moveMessages',[target, messages]); request.sendRequest(false); + for (var i = 0; i < messages['msg'].length; i++) egw.dataDeleteUID(messages['msg'][i]); this.mail_refreshMessageGrid(); }, /** From 005d5ed09045ef247b06e55490759d0a8718bebd Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 3 May 2013 11:46:26 +0000 Subject: [PATCH 08/84] value of description set via id need to get translated, if !no_lang is set, value set via value attribute already get translated via transformAttributes and translate: "!no_lang" of value --- etemplate/js/et2_widget_description.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/etemplate/js/et2_widget_description.js b/etemplate/js/et2_widget_description.js index 943ab07826..e94589311a 100644 --- a/etemplate/js/et2_widget_description.js +++ b/etemplate/js/et2_widget_description.js @@ -121,6 +121,8 @@ var et2_description = et2_baseWidget.extend([et2_IDetachedDOM], set_value: function(_value) { if(!_value) _value = ""; + else + if (!this.options.no_lang) _value = this.egw().lang(_value); et2_insertLinkText(this._parseText(_value), this.span[0], this.options.extra_link_target From 1b3c934823c3d37839338b73ecdcd39d138bb410 Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 3 May 2013 11:50:40 +0000 Subject: [PATCH 09/84] a few compatbility methods and hacks to get old etemplates to behaves a bit more like eT2 --- etemplate/inc/class.boetemplate.inc.php | 53 ++++++++++++++++++++--- etemplate/inc/class.etemplate_old.inc.php | 15 +++++-- 2 files changed, 59 insertions(+), 9 deletions(-) diff --git a/etemplate/inc/class.boetemplate.inc.php b/etemplate/inc/class.boetemplate.inc.php index a9601f362f..e7d7edb4c3 100644 --- a/etemplate/inc/class.boetemplate.inc.php +++ b/etemplate/inc/class.boetemplate.inc.php @@ -301,9 +301,9 @@ class boetemplate extends soetemplate * @param string $attr attribute-name * @return mixed the attribute or False if named cell not found */ - function &get_cell_attribute($name,$attr) + function &getElementAttribute($name,$attr) { - return $this->set_cell_attribute($name,$attr,NULL); + return $this->setElementAttribute($name,$attr,NULL); } /** @@ -314,7 +314,7 @@ class boetemplate extends soetemplate * @param mixed $val if not NULL sets attribute else returns it * @return mixed number of changed cells or False, if none changed */ - function &set_cell_attribute($name,$attr,$val) + function &setElementAttribute($name,$attr,$val) { //echo "

    set_cell_attribute(tpl->name=$this->name, name='$name', attr='$attr',val='$val')

    \n"; @@ -335,11 +335,54 @@ class boetemplate extends soetemplate * @param boolean $disabled=true disable or enable a cell, default true=disable * @return mixed number of changed cells or False, if none changed */ - function disable_cells($name,$disabled=True) + function disableElement($name,$disabled=True) { return $this->set_cell_attribute($name,'disabled',$disabled); } + /** + * Returns reference to an attribute in a named cell + * + * Currently we always return a reference to an not set value, unless it was set before. + * We do not return a reference to the actual cell, as it get's contructed on client-side! + * + * @param string $name cell-name + * @param string $attr attribute-name + * @return mixed reference to attribute, usually NULL + * @deprecated use getElementAttribute($name, $attr) + */ + public function &get_cell_attribute($name,$attr) + { + return self::getElementAttribute($name, $attr); + } + + /** + * set an attribute in a named cell if val is not NULL else return the attribute + * + * @param string $name cell-name + * @param string $attr attribute-name + * @param mixed $val if not NULL sets attribute else returns it + * @return reference to attribute + * @deprecated use setElementAttribute($name, $attr, $val) + */ + public function &set_cell_attribute($name,$attr,$val) + { + return self::setElementAttribute($name, $attr, $val); + } + + /** + * disables all cells with name == $name + * + * @param sting $name cell-name + * @param boolean $disabled=true disable or enable a cell, default true=disable + * @return reference to attribute + * @deprecated use disableElement($name, $disabled=true) + */ + public function disable_cells($name,$disabled=True) + { + return self::disableElement($name, $disabled); + } + /** * set one or more attibutes for row $n * @@ -1097,7 +1140,7 @@ if (!function_exists('set_cell_attribute_helper')) function &set_cell_attribute_helper(&$widget,&$extra) { // extra = array(0=>n,1=>name,2=>attr,3=>value) - if ($widget['name'] == $extra[1]) + if ($widget['name'] == $extra[1] || $widget['type'] == 'tab' && strpos($widget['name'], $extra[1].'=') === 0) { if (is_null($extra[3])) { diff --git a/etemplate/inc/class.etemplate_old.inc.php b/etemplate/inc/class.etemplate_old.inc.php index af8f74cc10..d43dbc2224 100644 --- a/etemplate/inc/class.etemplate_old.inc.php +++ b/etemplate/inc/class.etemplate_old.inc.php @@ -312,7 +312,7 @@ class etemplate_old extends boetemplate if($output_mode == 2) { $html .= "\n".''; } @@ -788,7 +788,7 @@ class etemplate_old extends boetemplate if (!(list($r_key) = each($data))) // no further row { if (!(($this->autorepeat_idx($cols['A'],0,$r,$idx,$idx_cname,false,$content) && $idx_cname) || - (substr($cols['A']['type'],1) == 'box' && $this->autorepeat_idx($cols['A'][1],0,$r,$idx,$idx_cname,false,$content) && $idx_cname) || + (in_array($cols['A']['type'], array('vbox','hbox','box')) && $this->autorepeat_idx($cols['A'][1],0,$r,$idx,$idx_cname,false,$content) && $idx_cname) || ($this->autorepeat_idx($cols['B'],1,$r,$idx,$idx_cname,false,$content) && $idx_cname)) || !$this->isset_array($content,$idx_cname)) { @@ -1091,6 +1091,10 @@ class etemplate_old extends boetemplate { $cell['onchange'] = $this->expand_name($cell['onchange'],$show_c,$show_row,$content['.c'],$content['.row'],$content); } + if ($cell['type'][0] == '@') + { + $cell['type'] = $this->expand_name($t=$cell['type'],$show_c,$show_row,$content['.c'],$content['.row'],$content); + } // the while loop allows to build extensions from other extensions // please note: only the first extension's post_process function is called !!! list($type,$sub_type) = explode('-',$cell['type']); @@ -1270,6 +1274,7 @@ class etemplate_old extends boetemplate case 'hidden': case 'passwd': case 'text': // size: [length][,maxLength[,preg[,html5type]]] + case 'textbox': $autocompletion_off=''; if ($type == 'passwd') $autocompletion_off='autocomplete="off"'; $cell_opts = $c = self::csv_split($cell_options); // allows to enclose preg in quote to allow comma @@ -2058,9 +2063,9 @@ class etemplate_old extends boetemplate $sels += $cell['sel_options']; } } - if (isset($this->sel_options[$name]) && is_array($this->sel_options[$name])) + if (($options = self::get_array($this->sel_options, $name)) && is_array($options)) { - $sels += $this->sel_options[$name]; + $sels += $options; } else { @@ -2082,6 +2087,7 @@ class etemplate_old extends boetemplate { $sels += $content["options-$name"]; } + //error_log(__METHOD__."(, '$name') returning ".array2string($sels)); return $sels; } @@ -2266,6 +2272,7 @@ class etemplate_old extends boetemplate case 'float': case 'passwd': case 'text': + case 'textbox': case 'hidden': case 'textarea': case 'colorpicker': From 3561de27aa325c0f89c9e65c378d73e939c8797a Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 3 May 2013 13:08:08 +0000 Subject: [PATCH 10/84] next step with new prefs, works now in old eTemplate too - even a little more then in eT2 ;-) --- .../inc/class.preferences_hooks.inc.php | 2 +- .../inc/class.preferences_settings.inc.php | 272 ++++++++++++++---- preferences/setup/etemplates.inc.php | 30 ++ preferences/templates/default/app.css | 10 +- preferences/templates/default/settings.xet | 43 ++- 5 files changed, 284 insertions(+), 73 deletions(-) create mode 100644 preferences/setup/etemplates.inc.php diff --git a/preferences/inc/class.preferences_hooks.inc.php b/preferences/inc/class.preferences_hooks.inc.php index 69f0fef770..78ae8b1882 100644 --- a/preferences/inc/class.preferences_hooks.inc.php +++ b/preferences/inc/class.preferences_hooks.inc.php @@ -144,7 +144,7 @@ class preferences_hooks 'type' => 'select', 'label' => 'Theme (colors/fonts) Selection', 'name' => 'theme', - 'values' => isset($GLOBALS['egw']->framework) ? $GLOBALS['egw']->framework->list_themes() : array(), + 'values' => !$hook_data['setup'] ? $GLOBALS['egw']->framework->list_themes() : array(), 'help' => 'A theme defines the colors and fonts used by the template.', 'xmlrpc' => True, 'admin' => False, diff --git a/preferences/inc/class.preferences_settings.inc.php b/preferences/inc/class.preferences_settings.inc.php index 4fb0a71d15..339b8d9116 100644 --- a/preferences/inc/class.preferences_settings.inc.php +++ b/preferences/inc/class.preferences_settings.inc.php @@ -43,71 +43,222 @@ class preferences_settings */ function index(array $content=null, $msg='') { - $tpl = new etemplate_new('preferences.settings'); + $tpl = new etemplate_old('preferences.settings'); if (!is_array($content)) { $appname = isset($_GET['appname']) ? $_GET['appname'] : 'preferences'; - if (!$this->call_hook($appname)) + $type = 'user'; + $account_id = $GLOBALS['egw_info']['user']['account_id']; + if ($GLOBALS['egw_info']['user']['apps']['admin'] && + isset($_GET['account_id']) && (int)$_GET['account_id'] && + $GLOBALS['egw']->accounts->exists((int)$_GET['account_id'])) { - throw new egw_exception_wrong_parameter("Could not find settings for application: ".$_GET['appname']); + $account_id = (int)$_GET['account_id']; + $type = $_GET['account_id'] < 0 ? 'group' : 'user'; } - //_debug_array($this->settings); exit; - $sel_options = $readonlys = $content = $tabs = array(); - // disable all but first tab and name current tab "tab1", for apps not using sections - $tab = 'tab1'; - $readonlys['tabs'] = array( - 'tab2' => true, - 'tab3' => true, - 'tab4' => true, - 'tab5' => true, - ); - - foreach($this->settings as $setting) - { - if (!is_array($setting)) continue; - switch($setting['type']) - { - case 'section': - $tabs[] = $setting['title']; - $tab = 'tab'.count($tabs); - $tpl->setElementAttribute($tab, 'label', $setting['title']); - $readonlys['tabs'][$tab] = false; - // fall through - case 'subsection': // is in old code, but never seen it used - continue 2; - - case 'input': - $setting['type'] = 'textbox'; - break; - case 'check': - $setting['type'] = 'select'; - $setting['values'] = array('no', 'yes'); - break; - case 'multiselect': - $setting['type'] = 'select'; - break; - case 'color': - $setting['type'] = 'colorpicker'; - break; - } - // move values/options to sel_options array - if (isset($setting['values']) && is_array($setting['values'])) - { - // need to call fix_encoded_options manually, as id is not matching because of autorepeat - etemplate_widget_menupopup::fix_encoded_options($setting['values']); - $sel_options[$tab][count($content[$tab]).'[value]'] = $setting['values']; - unset($setting['values']); - } - $content[$tab][] = $setting; - } - //_debug_array($content); exit; - //_debug_array($sel_options); exit; } else { - $this->appname = $content['appname']; + //_debug_array($content); + $appname = $content['appname'] ? $content['appname'] : 'preferences'; + list($type,$account_id) = explode(':', $content['type']); + $prefs = array_merge($content['tab1'], $content['tab2'], $content['tab3'], $content['tab4']); + if ($content['button']) + { + list($button) = each($content['button']); + switch($button) + { + case 'save': + case 'apply': + // ToDo: save preferences + + $msg = lang('Preferences saved.').array2string($prefs); + if ($button == 'apply') break; + // fall throught + case 'cancel': + egw::redirect_link('/preferences/index.php'); + } + } + //_debug_array($prefs); } - $tpl->exec('preferences.preferences_settings.index', $content, $sel_options, $readonlys, $content); + if ($account_id && $account_id != $GLOBALS['egw']->preferences->account_id) + { + $GLOBALS['egw']->preferences->account_id = $account_id; + $GLOBALS['egw']->preferences->read_repository(); + } + $content = $this->get_content($appname, $type, $sel_options, $readonlys, $tpl); + $content['msg'] = $msg; + + $tpl->exec('preferences.preferences_settings.index', $content, $sel_options, $readonlys, array( + 'appname' => $content['appname'], + 'type' => $content['type'], + )); + } + + /** + * Get content, sel_options and readonlys for given appname and type + * + * @param string $appname + * @param string $type + * @param array &$sel_options + * @param array &$readonlys + * @param etemplate $tpl + * @throws egw_exception_wrong_parameter + * @return array content + */ + function get_content($appname, $type, &$sel_options, &$readonlys, $tpl) + { + if (!$this->call_hook($appname, $type)) + { + throw new egw_exception_wrong_parameter("Could not find settings for application: ".$_GET['appname']); + } + if ($appname == 'preferences') $appname = 'common'; + $attribute = $type == 'group' ? 'user' : $type; + //error_log(__METHOD__."('$appname', '$type' ) attribute='$attribute', preferences->account_id=".$GLOBALS['egw']->preferences->account_id); + + //_debug_array($this->settings); exit; + $sel_options = $readonlys = $content = $tabs = array(); + // disable all but first tab and name current tab "tab1", for apps not using sections + $tab = 'tab1'; + foreach($this->settings as $setting) + { + if (!is_array($setting)) continue; + if ($type != 'forced' && !empty($GLOBALS['egw']->preferences->forced[$appname][$setting['name']])) + { + continue; // forced preferences are not displayed, unless we edit them + } + switch($old_type = $setting['type']) + { + case 'section': + $tab = 'tab'.(1+count($tabs)); + $tabs[$tab] = $setting['title']; + $tpl->setElementAttribute($tab, 'label', $setting['title']); + if (count($tabs) > 5) + { + throw new egw_exception_assertion_failed("App $appname has more then 4 preference tabs!"); + } + // fall through + case 'subsection': // is in old code, but never seen it used + continue 2; + + case 'vfs_file': + case 'vfs_dir': + case 'vfs_dirs': + case 'notify': + // ToDo: implementation ... + // handle as input for now + case 'input': + $setting['type'] = 'textbox'; + if (isset($setting['size'])) + { + $tpl->setElementAttribute($tab.'['.$setting['name'].']', 'size', $setting['size']); + } + break; + case 'check': + $setting['type'] = 'select'; + $setting['values'] = array('1' => lang('yes'), '0' => lang('no')); + break; + case 'multiselect': + $setting['type'] = 'select'; + $tpl->setElementAttribute($tab.'['.$setting['name'].']', 'multiple', 5); + if (!isset($setting['size'])) $setting['size'] = '5'; // old eT + break; + case 'color': + $setting['type'] = 'colorpicker'; + break; + } + // move values/options to sel_options array + if (isset($setting['values']) && is_array($setting['values'])) + { + if ($old_type != 'multiselect') + { + switch($type) + { + case 'user': + $setting['values'] = array('' => lang('Use default'))+$setting['values']; + break; + case 'forced'; + $setting['values'] = array('' => lang('Users choice'))+$setting['values']; + break; + } + } + // need to call fix_encoded_options manually, as id is not matching because of autorepeat + etemplate_widget_menupopup::fix_encoded_options($setting['values']); + $sel_options[$setting['name']] = $setting['values']; + } + if ($type == 'user') + { + $default = $GLOBALS['egw']->preferences->default[$appname][$setting['name']]; + if (isset($setting['values']) && (string)$setting['values'][$default] !== '') + { + $default = $setting['values'][$default]; + } + elseif (strpos($default, ',') !== false) + { + $values = array(); + foreach(explode(',', $default) as $value) + { + if (isset($setting['values'][$value])) $values[] = $setting['values'][$value]; + } + if ($values) $default = implode(', ', $values); + } + } + $content[$tab][] = array( + 'name' => $setting['name'], + 'type' => $setting['type'], + 'label' => str_replace('
    ', "\n", $setting['label']), + 'help' => str_replace('
    ', "\n", $setting['help']), + 'size' => $setting['size'], // old eT + 'default' => !empty($default) ? lang('Default').': '.$default : null, + ); + $content[$tab][$setting['name']] = $GLOBALS['egw']->preferences->{$attribute}[$appname][$setting['name']]; + //if ($old_type == 'multiselect') $content[$tab][$setting['name']] = explode(',', $content[$tab][$setting['name']]); + } + // disabling not used tabs, does NOT work in new eT + $readonlys['tabs'] = array( + 'tab2' => !isset($tabs['tab2']), + 'tab3' => !isset($tabs['tab3']), + 'tab4' => !isset($tabs['tab4']), + 'tab5' => !isset($tabs['tab5']), + ); + $tpl->setElementAttribute('tabs', 'label', implode('|', $tabs)); // old eT + + $content['appname'] = $appname; + $sel_options['appname'] = array(); + foreach($GLOBALS['egw']->hooks->hook_implemented('settings') as $app) + { + if ($app != 'preferences' && $GLOBALS['egw_info']['apps'][$app]) + { + $sel_options['appname'][$app] = $GLOBALS['egw_info']['apps'][$app]['title']; + } + } + natcasesort($sel_options['appname']); + + if ($GLOBALS['egw_info']['apps']['admin']) + { + $sel_options['type'] = array( + 'user' => 'Your preferences', + 'default' => 'Default preferences', + 'forced' => 'Forced preferences', + ); + $content['type'] = $type; + if ($GLOBALS['egw']->preferences->account_id != $GLOBALS['egw_info']['user']['account_id']) + { + $content['type'] .= ':'.$GLOBALS['egw']->preferences->account_id; + $sel_options['type'][$content['type']] = common::grab_owner_name($GLOBALS['egw']->preferences->account_id); + } + foreach($GLOBALS['egw']->accounts->search(array('type' => 'groups', 'sort' => 'account_lid')) as $account_id => $group) + { + $sel_options['type']['group:'.$account_id] = common::display_fullname($group['account_lid'], '', '', $account_id); + } + } + else + { + $content['type'] = 'user'; + } + //_debug_array($content); exit; + //_debug_array($sel_options); //exit; + return $content; } /** @@ -118,7 +269,7 @@ class preferences_settings * @param string $appname * @return boolean */ - protected function call_hook($appname) + protected function call_hook($appname, $type='user') { $this->appname = $appname; @@ -128,16 +279,19 @@ class preferences_settings translation::add_app('preferences'); // we need the prefs translations too } + // make type available, to hooks from applications can use it, eg. activesync + $GLOBALS['type'] = $type; + // calling app specific settings hook $settings = $GLOBALS['egw']->hooks->single('settings',$this->appname); // it either returns the settings or save it in $GLOBALS['settings'] (deprecated!) if (isset($settings) && is_array($settings) && $settings) { - $this->settings = array_merge($this->settings,$settings); + $this->settings = array_merge($this->settings, $settings); } elseif(isset($GLOBALS['settings']) && is_array($GLOBALS['settings']) && $GLOBALS['settings']) { - $this->settings = array_merge($this->settings,$GLOBALS['settings']); + $this->settings = array_merge($this->settings, $GLOBALS['settings']); } else { diff --git a/preferences/setup/etemplates.inc.php b/preferences/setup/etemplates.inc.php new file mode 100644 index 0000000000..e946ebfebd --- /dev/null +++ b/preferences/setup/etemplates.inc.php @@ -0,0 +1,30 @@ + 'preferences.settings','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:5:{i:0;a:3:{s:4:"name";s:3:"msg";s:4:"type";s:5:"label";s:4:"span";s:10:",redItalic";}i:1;a:3:{s:4:"type";s:6:"select";s:4:"name";s:4:"type";s:8:"onchange";i:1;}i:2;a:5:{s:4:"type";s:6:"select";s:4:"name";s:7:"appname";s:4:"size";s:18:"Common preferences";s:5:"label";s:11:"Application";s:8:"onchange";i:1;}i:3;a:3:{s:4:"name";s:29:"tabs=tab1|tab2|tab3|tab4|tab5";s:4:"type";s:3:"tab";s:5:"label";s:29:"Tab 1|Tab 2|Tab 3|Tab 4|Tab 5";}i:4;a:5:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"3";i:1;a:3:{s:5:"label";s:4:"Save";s:4:"name";s:12:"button[save]";s:4:"type";s:6:"button";}i:2;a:3:{s:5:"label";s:5:"Apply";s:4:"name";s:13:"button[apply]";s:4:"type";s:6:"button";}i:3;a:3:{s:5:"label";s:6:"Cancel";s:4:"name";s:14:"button[cancel]";s:4:"type";s:6:"button";}}}','size' => '','style' => '','modified' => '1367564824',); + +$templ_data[] = array('name' => 'preferences.settings.general','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:7:{s:4:"type";s:4:"grid";s:4:"name";s:7:"general";s:4:"data";a:2:{i:0;a:2:{s:1:"A";s:3:"50%";s:2:"c1";s:7:"prefRow";}i:1;a:2:{s:1:"A";a:5:{s:4:"type";s:3:"box";s:4:"size";s:1:"2";s:4:"span";s:9:",prefName";i:1;a:2:{s:4:"name";s:13:"${row}[label]";s:4:"type";s:5:"label";}i:2;a:3:{s:4:"name";s:12:"${row}[help]";s:4:"type";s:5:"label";s:4:"span";s:9:",prefHelp";}}s:1:"B";a:4:{s:4:"name";s:13:"${row}[value]";s:4:"type";s:4:"text";s:4:"span";s:10:",prefValue";s:4:"size";s:13:"@${row}[size]";}}}s:4:"cols";i:2;s:4:"rows";i:1;s:4:"size";s:16:"100%,,,prefTable";s:7:"options";a:2:{i:3;s:9:"prefTable";i:0;s:4:"100%";}}}','size' => '100%,,,prefTable','style' => '','modified' => '1367140794',); + +$templ_data[] = array('name' => 'preferences.settings.tab1','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:7:{s:4:"type";s:4:"grid";s:4:"name";s:4:"tab1";s:4:"data";a:2:{i:0;a:2:{s:1:"A";s:3:"50%";s:2:"c1";s:7:"prefRow";}i:1;a:2:{s:1:"A";a:5:{s:4:"type";s:3:"box";s:4:"size";s:1:"2";s:4:"span";s:9:",prefName";i:1;a:3:{s:3:"for";s:13:"${row}[value]";s:4:"name";s:13:"${row}[label]";s:4:"type";s:5:"label";}i:2;a:3:{s:4:"name";s:12:"${row}[help]";s:4:"type";s:5:"label";s:4:"span";s:9:",prefHelp";}}s:1:"B";a:4:{s:4:"type";s:3:"box";s:4:"size";s:1:"2";i:1;a:5:{s:4:"type";s:13:"@${row}[type]";s:4:"size";s:13:"@${row}[size]";s:7:"no_lang";s:1:"1";s:4:"name";s:13:"@${row}[name]";s:4:"span";s:10:",prefValue";}i:2;a:4:{s:7:"no_lang";s:1:"1";s:4:"name";s:15:"${row}[default]";s:4:"type";s:5:"label";s:4:"span";s:12:",prefDefault";}}}}s:4:"cols";i:2;s:4:"rows";i:1;s:4:"size";s:33:"100%,,,prefTable egwGridView_grid";s:7:"options";a:2:{i:3;s:26:"prefTable egwGridView_grid";i:0;s:4:"100%";}}}','size' => '100%,,,prefTable egwGridView_grid','style' => '','modified' => '1367565943',); + +$templ_data[] = array('name' => 'preferences.settings.tab2','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:7:{s:4:"type";s:4:"grid";s:4:"name";s:4:"tab2";s:4:"data";a:2:{i:0;a:2:{s:1:"A";s:3:"50%";s:2:"c1";s:7:"prefRow";}i:1;a:2:{s:1:"A";a:5:{s:4:"type";s:3:"box";s:4:"size";s:1:"2";s:4:"span";s:9:",prefName";i:1;a:3:{s:3:"for";s:13:"${row}[value]";s:4:"name";s:13:"${row}[label]";s:4:"type";s:5:"label";}i:2;a:3:{s:4:"name";s:12:"${row}[help]";s:4:"type";s:5:"label";s:4:"span";s:9:",prefHelp";}}s:1:"B";a:4:{s:4:"type";s:3:"box";s:4:"size";s:1:"2";i:1;a:5:{s:4:"type";s:13:"@${row}[type]";s:4:"size";s:13:"@${row}[size]";s:7:"no_lang";s:1:"1";s:4:"name";s:13:"@${row}[name]";s:4:"span";s:10:",prefValue";}i:2;a:4:{s:7:"no_lang";s:1:"1";s:4:"name";s:15:"${row}[default]";s:4:"type";s:5:"label";s:4:"span";s:12:",prefDefault";}}}}s:4:"cols";i:2;s:4:"rows";i:1;s:4:"size";s:33:"100%,,,prefTable egwGridView_grid";s:7:"options";a:2:{i:3;s:26:"prefTable egwGridView_grid";i:0;s:4:"100%";}}}','size' => '100%,,,prefTable egwGridView_grid','style' => '','modified' => '1367566575',); + +$templ_data[] = array('name' => 'preferences.settings.tab3','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:7:{s:4:"type";s:4:"grid";s:4:"name";s:4:"tab3";s:4:"data";a:2:{i:0;a:2:{s:1:"A";s:3:"50%";s:2:"c1";s:7:"prefRow";}i:1;a:2:{s:1:"A";a:5:{s:4:"type";s:3:"box";s:4:"size";s:1:"2";s:4:"span";s:9:",prefName";i:1;a:3:{s:3:"for";s:13:"${row}[value]";s:4:"name";s:13:"${row}[label]";s:4:"type";s:5:"label";}i:2;a:3:{s:4:"name";s:12:"${row}[help]";s:4:"type";s:5:"label";s:4:"span";s:9:",prefHelp";}}s:1:"B";a:4:{s:4:"type";s:3:"box";s:4:"size";s:1:"2";i:1;a:5:{s:4:"type";s:13:"@${row}[type]";s:4:"size";s:13:"@${row}[size]";s:7:"no_lang";s:1:"1";s:4:"name";s:13:"@${row}[name]";s:4:"span";s:10:",prefValue";}i:2;a:4:{s:7:"no_lang";s:1:"1";s:4:"name";s:15:"${row}[default]";s:4:"type";s:5:"label";s:4:"span";s:12:",prefDefault";}}}}s:4:"cols";i:2;s:4:"rows";i:1;s:4:"size";s:33:"100%,,,prefTable egwGridView_grid";s:7:"options";a:2:{i:3;s:26:"prefTable egwGridView_grid";i:0;s:4:"100%";}}}','size' => '100%,,,prefTable egwGridView_grid','style' => '','modified' => '1367566588',); + +$templ_data[] = array('name' => 'preferences.settings.tab4','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:7:{s:4:"type";s:4:"grid";s:4:"name";s:4:"tab4";s:4:"data";a:2:{i:0;a:2:{s:1:"A";s:3:"50%";s:2:"c1";s:7:"prefRow";}i:1;a:2:{s:1:"A";a:5:{s:4:"type";s:3:"box";s:4:"size";s:1:"2";s:4:"span";s:9:",prefName";i:1;a:3:{s:3:"for";s:13:"${row}[value]";s:4:"name";s:13:"${row}[label]";s:4:"type";s:5:"label";}i:2;a:3:{s:4:"name";s:12:"${row}[help]";s:4:"type";s:5:"label";s:4:"span";s:9:",prefHelp";}}s:1:"B";a:4:{s:4:"type";s:3:"box";s:4:"size";s:1:"2";i:1;a:5:{s:4:"type";s:13:"@${row}[type]";s:4:"size";s:13:"@${row}[size]";s:7:"no_lang";s:1:"1";s:4:"name";s:13:"@${row}[name]";s:4:"span";s:10:",prefValue";}i:2;a:4:{s:7:"no_lang";s:1:"1";s:4:"name";s:15:"${row}[default]";s:4:"type";s:5:"label";s:4:"span";s:12:",prefDefault";}}}}s:4:"cols";i:2;s:4:"rows";i:1;s:4:"size";s:33:"100%,,,prefTable egwGridView_grid";s:7:"options";a:2:{i:3;s:26:"prefTable egwGridView_grid";i:0;s:4:"100%";}}}','size' => '100%,,,prefTable egwGridView_grid','style' => '','modified' => '1367566604',); + +$templ_data[] = array('name' => 'preferences.settings.tab5','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:7:{s:4:"type";s:4:"grid";s:4:"name";s:4:"tab5";s:4:"data";a:2:{i:0;a:2:{s:1:"A";s:3:"50%";s:2:"c1";s:7:"prefRow";}i:1;a:2:{s:1:"A";a:5:{s:4:"type";s:3:"box";s:4:"size";s:1:"2";s:4:"span";s:9:",prefName";i:1;a:3:{s:3:"for";s:13:"${row}[value]";s:4:"name";s:13:"${row}[label]";s:4:"type";s:5:"label";}i:2;a:3:{s:4:"name";s:12:"${row}[help]";s:4:"type";s:5:"label";s:4:"span";s:9:",prefHelp";}}s:1:"B";a:4:{s:4:"type";s:3:"box";s:4:"size";s:1:"2";i:1;a:5:{s:4:"type";s:13:"@${row}[type]";s:4:"size";s:13:"@${row}[size]";s:7:"no_lang";s:1:"1";s:4:"name";s:13:"@${row}[name]";s:4:"span";s:10:",prefValue";}i:2;a:4:{s:7:"no_lang";s:1:"1";s:4:"name";s:15:"${row}[default]";s:4:"type";s:5:"label";s:4:"span";s:12:",prefDefault";}}}}s:4:"cols";i:2;s:4:"rows";i:1;s:4:"size";s:33:"100%,,,prefTable egwGridView_grid";s:7:"options";a:2:{i:3;s:26:"prefTable egwGridView_grid";i:0;s:4:"100%";}}}','size' => '100%,,,prefTable egwGridView_grid','style' => '','modified' => '1367583114',); + +$templ_data[] = array('name' => 'preferences.test','template' => '','lang' => '','group' => '0','version' => '','data' => 'a:1:{i:0;a:4:{s:4:"type";s:4:"grid";s:4:"data";a:2:{i:0;a:0:{}i:1;a:1:{s:1:"A";a:3:{s:4:"type";s:5:"label";s:5:"label";s:5:"Label";s:4:"name";s:2:"id";}}}s:4:"rows";i:1;s:4:"cols";i:1;}}','size' => '','style' => '','modified' => '1367563385',); + diff --git a/preferences/templates/default/app.css b/preferences/templates/default/app.css index 43061f9f83..18a021572b 100644 --- a/preferences/templates/default/app.css +++ b/preferences/templates/default/app.css @@ -14,7 +14,7 @@ table.prefTable { tr.prefRow { position: relative; } -td.prefName, td.prefValue { +td.prefName { width: 50%; } .prefHelp { @@ -30,4 +30,10 @@ td.prefName, td.prefValue { tr.prefRow:hover .prefHelp { display: block; z-index: 10; /* FF: displays it under next prefName without */ -} \ No newline at end of file +} +.prefDefault, .prefValue { + float: left; +} +.prefValue { + margin-right: 5px; +} diff --git a/preferences/templates/default/settings.xet b/preferences/templates/default/settings.xet index 11624c770f..eb0e14180b 100644 --- a/preferences/templates/default/settings.xet +++ b/preferences/templates/default/settings.xet @@ -10,10 +10,13 @@ - + - + + + + @@ -27,10 +30,13 @@ - + - + + + + @@ -44,10 +50,13 @@ - + - + + + + @@ -61,10 +70,13 @@ - + - + + + + @@ -78,16 +90,25 @@ - + - + + + +