added context menu for nextmatch widget: first implemenation in timesheet

- legacy actions column and multiple action row below table is switched off by default, but can be switched on again
- legacy action button is NOT yet working
- "whole query" checkbox need to go into context menu too
This commit is contained in:
Ralf Becker 2011-04-16 21:45:13 +00:00
parent 72ac7937de
commit 806d3d604c
12 changed files with 400 additions and 154 deletions

View File

@ -863,7 +863,8 @@ abstract class bo_merge
*
* @return List of documents, suitable for a selectbox. The key is document_<filename>.
*/
public static function get_documents($dir) {
public static function get_documents($dir)
{
if (!$dir) return array();
$list = array();
@ -872,7 +873,7 @@ abstract class bo_merge
foreach($files as $file)
{
// return only the mime-types we support
if (!self::is_implemented($file['mime'],substr($file['name'],-4))) continue;
if (!self::is_implemented($file['mime'],'.'.array_pop($parts=explode('.',$file['name'])))) continue;
$list['document_'.$file['name']] = /*lang('Insert in document').': '.*/$file['name'];
}
@ -880,10 +881,33 @@ abstract class bo_merge
return $list;
}
/**
* Get insert-in-document action
*
* @param string $dir
* @param int $group see nextmatch_widget::egw_actions
* @param string $caption='Insert in document'
* @return array see nextmatch_widget::egw_actions
*/
public static function document_action($dir, $group=0, $caption='Insert in document')
{
$documents = self::get_documents($dir);
return array(
'icon' => 'etemplate/merge',
'caption' => $caption,
'children' => $documents,
'enabled' => (boolean)$documents,
'hideOnDisabled' => true,
'group' => $group,
);
}
/**
* Get a list of supported extentions
*/
public static function get_file_extensions() {
public static function get_file_extensions()
{
return array('txt', 'rtf', 'odt', 'ods', 'docx', 'xml');
}

View File

@ -48,6 +48,7 @@ class boetemplate extends soetemplate
'deck' => 'Deck', // a container of elements where only one is visible, size = # of elem.
'passwd' => 'Password', // a text of type password
'colorpicker' => 'Colorpicker', // input for a color (eg. #123456)
'hidden'=> 'Hidden input', // a hidden input eg. to submit javascript computed values back
);
/**
@ -479,10 +480,10 @@ class boetemplate extends soetemplate
return (self::$extensions[$type] || $this->loadExtension($type,$ui)) &&
($function == '' || self::$extensions[$type]->public_functions[$function]);
}
/**
* Check if we have a widget of type $type
*
*
* @param string $type
* @return boolean true widget exists, false unknow widget type
*/
@ -759,6 +760,7 @@ class boetemplate extends soetemplate
* - csv_split('"1,2,3",2,3') === array('1,2,3','2','3')
* - csv_split('1,2,3',2) === array('1','2,3')
* - csv_split('"1,2,3",2,3',2) === array('1,2,3','2,3')
* - csv_split('"a""b,c",d') === array('a"b,c','d') // to escape enclosures double them!
*
* @param string $str
* @param int $num=null in how many parts to split maximal, parts over this number end up (unseparated) in the last part
@ -783,7 +785,7 @@ class boetemplate extends soetemplate
$part .= $delimiter.$parts[++$n];
unset($parts[$n]);
}
$part = substr($part,1,-1);
$part = substr(str_replace($enclosure.$enclosure,$enclosure,$part),1,-1);
}
}
$parts = array_values($parts); // renumber the parts (in case we had to concat them)
@ -949,7 +951,7 @@ class boetemplate extends soetemplate
// check if new import necessary, currently on every request
$msg = self::test_import($name);
//if ($msg) echo "<p>".__METHOD__."($name,$template,$lang,$group,$version) self::test_import($name) returning $msg</p>\n";
if (is_array($name))
{
$version = $name['version'];

View File

@ -776,6 +776,8 @@ class etemplate extends boetemplate
{
$opts = array();
}
$row_id = $content['_row_id'];
$max_cols = $grid['cols'];
for ($r = 0; $row = 1+$r /*list($row,$cols) = each($data)*/; ++$r)
{
@ -823,6 +825,11 @@ class etemplate extends boetemplate
$cl = isset(self::$class_conf[$cl]) ? self::$class_conf[$cl] : $cl;
$rows[".$row"] .= html::formatOptions($cl,'class');
$rows[".$row"] .= html::formatOptions($class,',valign');
// set row-id, if requested
if ($row_id && isset($content[$r][$row_id]))
{
$rows[".$row"] .= ' id="'.htmlspecialchars($content[$r][$row_id]).'"';
}
reset ($cols);
$row_data = array();
for ($c = 0; True /*list($col,$cell) = each($cols)*/; ++$c)
@ -967,54 +974,22 @@ class etemplate extends boetemplate
$html .= '
<script type="text/javascript">
//Temporary function called on onExecute
function alertClicked(_action, _senders)
{
var ids = "";
for (var i = 0; i < _senders.length; i++)
ids += _senders[i].id + ((i < _senders.length - 1) ? ", " : "");
alert("Action \'" + _action.caption + "\' executed on elements \'"
+ ids + "\'");
}
$(document).ready(function() {
// Initialize the action manager and add some actions to it
'.$prefix.'actionManager = new egwActionManager();
'.$prefix.'objectManager = new egwActionObjectManager("", '.$prefix.'actionManager);
// Add some dummy actions to the actionManager
'.$prefix.'actionManager.updateActions(
[
{
"id": "folder_open",
"iconUrl": "imgs/folder.png",
"caption": "Open folder",
"onExecute": "javaScript:alertClicked",
"allowOnMultiple": false,
"type": "popup",
"default": true
},
{
"id": "file_view",
"iconUrl": "imgs/view.png",
"caption": "View",
"onExecute": "javaScript:alertClicked",
"allowOnMultiple": false,
"type": "popup",
"default": true
}
]
);
'.$prefix.'actionManager.updateActions('.str_replace('},',"},\n",
json_encode(nextmatch_widget::egw_actions($content['_actions'], $this->name))).');
var actionLinks = [];//"folder_open", "file_view"];
var actionLinks = ['.($content['_actions'] ? '"'.implode('","', isset($content['_actions_enabled']) ?
$content['_actions_enabled'] : array_keys($content['_actions'])).'"' : '').'];
// Create a new action object for each table row
// TODO: only apply function to outer level
$("table.egwGridView_grid>tbody>tr").each(function(index, elem) {
console.log(elem);
$("table.egwGridView_grid>tbody>tr").each(function(index, elem)
{
// Create a new action object
var obj = '.$prefix.'objectManager.addObject(elem.id, new nextmatchRowAOI(elem));
@ -1300,7 +1275,8 @@ class etemplate extends boetemplate
}
$cell_options .= ',,'.($cell['type'] == 'int' ? '/^-?[0-9]*$/' : '/^-?[0-9]*[,.]?[0-9]*$/');
// fall-through
case 'passwd' :
case 'hidden':
case 'passwd':
case 'text': // size: [length][,maxLength[,preg]]
$cell_opts = explode(',',$cell_options,3);
if ($readonly && (int)$cell_opts[0] >= 0)
@ -1310,7 +1286,7 @@ class etemplate extends boetemplate
else
{
if ($cell_opts[0] < 0) $cell_opts[0] = abs($cell_opts[0]);
$html .= html::input($form_name,$value,$type == 'passwd' ? 'password' : '',
$html .= html::input($form_name,$value,$type == 'passwd' ? 'password' : ($type == 'hidden' ? 'hidden' : ''),
$options.html::formatOptions($cell_opts,'SIZE,MAXLENGTH'));
if (!$readonly)
@ -2246,6 +2222,7 @@ class etemplate extends boetemplate
case 'float':
case 'passwd':
case 'text':
case 'hidden':
case 'textarea':
case 'colorpicker':
if ((string)$value === '' && $attr['needed'] && !$attr['blur'])

View File

@ -501,9 +501,185 @@ class nextmatch_widget
}
$value['bottom'] = $value; // copy the values for the bottom-bar
// pass actions and row_id to etemplate::show_grid()
$value['rows']['_actions'] =& $value['actions'];
$value['rows']['_row_id'] =& $value['row_id'];
$value['action'] = $value['selected'] = $value['select_all'] = null; // nothing yet
return False; // NO extra Label
}
/**
* Return egw_actions
*
* The following attributes are understood for actions on eTemplate/PHP side:
* - string 'id' id of the action (set as key not attribute!)
* - string 'caption' name/label or action, get's automatic translated
* - boolean 'no_lang' do NOT translate caption, default false
* - string 'icon' icon, eg. 'edit' or 'infolog/task', if no app given app of template or API is used
* - string 'iconUrl' full url of icon, better use 'icon'
* - boolean 'allowOnMultiple' should action be shown if multiple lines are marked, default true!
* - boolean 'enabled' is action available, default true!
* - boolena 'hideOnDisabled' hide disabled actions, default false
* - string 'type' type of action, default 'popup' for contenxt menus
* - boolean 'default' is that action the default action, default false
* - array 'children' array with actions of submenu
* - int 'group' to group items, default all actions are in one group
* - string 'onExecute' javascript to run, default 'javascript:nm_action' which runs action specified in nm_action attribute:
* - string 'nm_action'
* + 'alert' debug action, shows alert with action caption, id and id's of selected rows
* + 'submit' default action, sets nm[action], nm[selected]
* + 'location' redirects / set location.href to 'url' attribute
* + 'popup' opens popup with url given in 'url' attribute
* - string 'url' url for location or popup
* - string 'target' target for location or popup
* - string 'width' for popup
* - string 'height' for popup
*
* That's what we should return looks JSON encoded like
* [
* {
* "id": "folder_open",
* "iconUrl": "imgs/folder.png",
* "caption": "Open folder",
* "onExecute": "javaScript:nm_action",
* "allowOnMultiple": false,
* "type": "popup",
* "default": true
* },
* ]
*
* @param array $actions id indexed array of actions / array with valus for keys: 'iconUrl', 'caption', 'onExecute', ...
* @param string $template_name='' name of the template, used as default for app name of images
* @param string $prefix='' prefix for ids
* @return array
*/
public static function egw_actions(array $actions=null, $template_name='', $prefix='')
{
// default icons for some common actions
static $default_icons = array(
'view' => 'view',
'edit' => 'edit',
'add' => 'new',
'delete' => 'delete',
'cat' => 'attach', // add as category icon to api
'document' => 'etemplate/merge',
);
//echo "actions="; _debug_array($actions);
$egw_actions = array();
foreach((array)$actions as $id => $action)
{
// in case it's only selectbox id => label pairs
if (!is_array($action)) $action = array('caption' => $action);
$action['id'] = $prefix.$id;
// set some defaults
if (!isset($action['type'])) $action['type'] = 'popup';
if (!isset($action['onExecute']))
{
$action['onExecute'] = 'javaScript:nm_action'; // defined in etemplate/js/nextmatch_action.js
}
// set default icon, if no other is specified
if (!isset($action['icon']) && isset($default_icons[$id]))
{
$action['icon'] = $default_icons[$id];
}
// use common eTemplate image semantics
if (!isset($action['iconUrl']) && !empty($action['icon']))
{
list($app,$img) = explode('/',$action['icon'],2);
if (!$app || !$img || !is_dir(EGW_SERVER_ROOT.'/'.$app) || strpos($img,'/')!==false)
{
$img = $action['icon'];
list($app) = explode('.', $template_name);
}
$action['iconUrl'] = common::find_image($app, $img);
unset($action['icon']); // no need to submit it
}
// translate labels
if (!$action['no_lang']) $action['caption'] = lang($action['caption']);
unset($action['no_lang']);
if (isset($action['confirm']))
{
$action['confirm'] = lang($action['confirm']).(substr($action['confirm'],-1) != '?' ? '?' : '');
}
// link or popup action
if ($action['url'])
{
$action['url'] = egw::link('/index.php',$action['url']);
if ($action['popup'])
{
list($action['data']['width'],$action['data']['height']) = explode('x',$action['popup']);
unset($action['popup']);
$action['data']['nm_action'] = 'popup';
}
else
{
$action['data']['nm_action'] = 'location';
}
}
// add sub-menues
if ($action['children'])
{
$action['children'] = self::egw_actions($action['children'], $template_name, $action['prefix']);
unset($action['prefix']);
}
static $egw_action_supported = array( // attributes supported by egw_action
'id','caption','iconUrl','type','default','onExecute','group',
'enabled','allowOnMultiple','hideOnDisabled','data','children',
);
// add all not egw_action supported attributes to data
$action['data'] = array_merge(array_diff_key($action, array_flip($egw_action_supported)),(array)$action['data']);
if (!$action['data']) unset($action['data']);
// only add egw_action attributes
$egw_actions[] = array_intersect_key($action, array_flip($egw_action_supported));
}
//echo "egw_actions="; _debug_array($egw_actions);
return $egw_actions;
}
/**
* Action with submenu to set category
*
* Maybe category hierarchy should be returned as such, currently we return them in one menu idented by level
*
* @param string $app
* @param int $group=0 see self::egw_actions
* @param string $caption='Change category'
* @param string $prefix='cat_' prefix category id to get action id
* @return array like self::egw_actions
*/
public static function category_action($app, $group=0, $caption='Change category', $prefix='cat_')
{
$cat_actions = array();
$cat = new categories(null,$app);
foreach((array)$cat->return_sorted_array($start=0,$limit=false,$query='',$sort='ASC',$order='cat_name',$globals=true, $parent_id=0,$unserialize_data=true) as $cat)
{
$name = str_repeat('&nbsp;',$cat['level']) . stripslashes($cat['name']);
if (categories::is_global($cat)) $name .= ' &#9830;';
$cat_actions[$cat['id']] = array(
'caption' => $name,
'no_lang' => true,
);
}
if (!$actions['cat']['children']) $actions['cat']['enabled'] = false;
return array(
'caption' => $caption,
'children' => $cat_actions,
'enabled' => (boolean)$cat_actions,
'group' => $group,
'prefix' => $prefix,
);
}
/**
* Calling our callback
*
@ -973,6 +1149,11 @@ class nextmatch_widget
{
self::csv_export($extension_data);
}
// allows return selected as array
$value['selected'] = $value['selected'] === '' ? array() : boetemplate::csv_split($value['selected']);
$value['select_all'] = (boolean)$value['select_all'];
return True;
}

View File

@ -24,8 +24,8 @@ function nextmatchRowAOI(_node)
aoi.checkBox = ($(":checkbox", aoi.node))[0];
// Rows without a checkbox are unselectable
if (typeof aoi.checkBox != "undefined")
// Rows without a checkbox OR an id set are unselectable
if (typeof aoi.checkBox != "undefined" || _node.id)
{
aoi.doGetDOMNode = function() {
return aoi.node;
@ -80,3 +80,66 @@ function nextmatchRowAOI(_node)
return aoi;
}
/**
* Default action for nextmatch rows, runs action specified _action.nm_action: set nextmatch_widget::egw_actions()
*
* @param _action action object with attributes caption, id, nm_action, ...
* @param _senders array of rows selected
*/
function nm_action(_action, _senders)
{
if (typeof _action.data == 'undefined' || !_action.data) _action.data = {};
if (typeof _action.data.nm_action == 'undefined') _action.data.nm_action = 'submit';
var ids = "";
for (var i = 0; i < _senders.length; i++)
{
ids += (_senders[i].id.indexOf(',') >= 0 ? '"'+_senders[i].id.replace(/"/g,'""')+'"' : _senders[i].id) +
((i < _senders.length - 1) ? "," : "");
}
console.log(_action);
console.log(_senders);
// let user confirm the action first
if (typeof _action.data.confirm != 'undefined')
{
if (!confirm(_action.data.confirm)) return;
}
var url = '#';
if (typeof _action.data.url != 'undefined')
{
url = _action.data.url;
if (url.substr(-1) == '=') url += ids;
}
var target;
if (typeof _action.data.target != 'undefined') target = _action.data.target;
switch(_action.data.nm_action)
{
case 'alert':
alert(_action.caption + " (\'" + _action.id + "\') executed on rows: " + ids);
break;
case 'location':
window.location.href = url;
break;
case 'popup':
egw_openWindowCentered2(url,target,_action.data.width,_action.data.height);
break;
case 'submit':
document.getElementById('exec[nm][action]').value = _action.id;
document.getElementById('exec[nm][selected]').value = ids;
if (typeof _action.data.button != 'undefined')
{
submitit(eTemplate,'exec[nm][rows]['+_action.data.button+']['+ids+']');
}
else
{
eTemplate.submit();
}
break;
}
}

View File

@ -2,7 +2,7 @@
/**
* eGroupWare - eTemplates for Application etemplate
* http://www.egroupware.org
* generated by soetemplate::dump4setup() 2011-03-27 18:11
* generated by soetemplate::dump4setup() 2011-04-16 22:25
*
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @package etemplate
@ -143,7 +143,7 @@ $templ_data[] = array('name' => 'etemplate.link_widget.to','template' => '','lan
.type_hide { display: none; }
.hide_comment input { display: none; width: 99%; }','modified' => '1260292296',);
$templ_data[] = array('name' => 'etemplate.nextmatch_widget','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:1:{i:0;a:5:{s:4:"type";s:4:"grid";s:4:"data";a:6:{i:0;a:8:{s:1:"A";s:3:"35%";s:1:"C";s:3:"35%";s:2:"c1";s:7:"noPrint";s:2:"c2";s:7:"noPrint";s:2:"c5";s:7:"noPrint";s:2:"h5";s:13:",!@bottom_too";s:2:"h3";s:15:",!@lettersearch";s:2:"c3";s:7:"noPrint";}i:1;a:3:{s:1:"A";a:2:{s:4:"type";s:8:"template";s:4:"name";s:12:"@header_left";}s:1:"B";a:6:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";s:5:"align";s:6:"center";i:1;a:4:{s:4:"type";s:5:"label";s:5:"label";s:7:"showing";s:7:"no_lang";s:1:"1";s:4:"name";s:5:"range";}i:2;a:4:{s:4:"type";s:5:"label";s:5:"label";s:2:"of";s:7:"no_lang";s:1:"1";s:4:"name";s:5:"total";}s:4:"span";s:16:",nextmatch-range";}s:1:"C";a:3:{s:4:"type";s:8:"template";s:5:"align";s:5:"right";s:4:"name";s:13:"@header_right";}}i:2;a:3:{s:1:"A";a:4:{s:4:"type";s:8:"template";s:4:"span";s:3:"all";s:5:"align";s:6:"center";s:4:"name";s:33:"etemplate.nextmatch_widget.nm_row";}s:1:"B";a:2:{s:4:"type";s:5:"label";s:8:"onchange";s:1:"1";}s:1:"C";a:1:{s:4:"type";s:5:"label";}}i:3;a:3:{s:1:"A";a:5:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"1";s:4:"span";s:3:"all";s:4:"name";s:12:"lettersearch";i:1;a:6:{s:4:"type";s:5:"label";s:5:"label";s:3:"All";s:5:"align";s:5:"right";s:4:"name";s:3:"all";s:6:"needed";s:1:"1";s:4:"span";s:20:",lettersearch_active";}}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}}i:4;a:3:{s:1:"A";a:5:{s:4:"type";s:8:"template";s:4:"size";s:4:"rows";s:4:"span";s:20:"all,egwGridView_grid";s:5:"align";s:6:"center";s:4:"name";s:9:"@template";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}}i:5;a:3:{s:1:"A";a:5:{s:4:"type";s:8:"template";s:4:"size";s:6:"bottom";s:4:"span";s:3:"all";s:5:"align";s:6:"center";s:4:"name";s:33:"etemplate.nextmatch_widget.nm_row";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}}}s:4:"rows";i:5;s:4:"cols";i:3;s:4:"size";s:4:"100%";}}','size' => '100%','style' => '','modified' => '1155978375',);
$templ_data[] = array('name' => 'etemplate.nextmatch_widget','template' => '','lang' => '','group' => '0','version' => '1.9.001','data' => 'a:4:{i:0;a:2:{s:4:"type";s:6:"hidden";s:4:"name";s:6:"action";}i:1;a:2:{s:4:"type";s:6:"hidden";s:4:"name";s:8:"selected";}i:2;a:2:{s:4:"type";s:6:"hidden";s:4:"name";s:10:"select_all";}i:3;a:5:{s:4:"type";s:4:"grid";s:4:"data";a:6:{i:0;a:8:{s:1:"A";s:3:"35%";s:1:"C";s:3:"35%";s:2:"c1";s:7:"noPrint";s:2:"c2";s:7:"noPrint";s:2:"c5";s:7:"noPrint";s:2:"h5";s:13:",!@bottom_too";s:2:"h3";s:15:",!@lettersearch";s:2:"c3";s:7:"noPrint";}i:1;a:3:{s:1:"A";a:2:{s:4:"type";s:8:"template";s:4:"name";s:12:"@header_left";}s:1:"B";a:6:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"2";s:5:"align";s:6:"center";i:1;a:4:{s:4:"type";s:5:"label";s:5:"label";s:7:"showing";s:7:"no_lang";s:1:"1";s:4:"name";s:5:"range";}i:2;a:4:{s:4:"type";s:5:"label";s:5:"label";s:2:"of";s:7:"no_lang";s:1:"1";s:4:"name";s:5:"total";}s:4:"span";s:16:",nextmatch-range";}s:1:"C";a:3:{s:4:"type";s:8:"template";s:5:"align";s:5:"right";s:4:"name";s:13:"@header_right";}}i:2;a:3:{s:1:"A";a:4:{s:4:"type";s:8:"template";s:4:"span";s:3:"all";s:5:"align";s:6:"center";s:4:"name";s:33:"etemplate.nextmatch_widget.nm_row";}s:1:"B";a:2:{s:4:"type";s:5:"label";s:8:"onchange";s:1:"1";}s:1:"C";a:1:{s:4:"type";s:5:"label";}}i:3;a:3:{s:1:"A";a:5:{s:4:"type";s:4:"hbox";s:4:"size";s:1:"1";s:4:"span";s:3:"all";s:4:"name";s:12:"lettersearch";i:1;a:6:{s:4:"type";s:5:"label";s:5:"label";s:3:"All";s:5:"align";s:5:"right";s:4:"name";s:3:"all";s:6:"needed";s:1:"1";s:4:"span";s:20:",lettersearch_active";}}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}}i:4;a:3:{s:1:"A";a:5:{s:4:"type";s:8:"template";s:4:"size";s:4:"rows";s:4:"span";s:20:"all,egwGridView_grid";s:5:"align";s:6:"center";s:4:"name";s:9:"@template";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}}i:5;a:3:{s:1:"A";a:5:{s:4:"type";s:8:"template";s:4:"size";s:6:"bottom";s:4:"span";s:3:"all";s:5:"align";s:6:"center";s:4:"name";s:33:"etemplate.nextmatch_widget.nm_row";}s:1:"B";a:1:{s:4:"type";s:5:"label";}s:1:"C";a:1:{s:4:"type";s:5:"label";}}}s:4:"rows";i:5;s:4:"cols";i:3;s:4:"size";s:4:"100%";}}','size' => '100%','style' => '','modified' => '1155978375',);
$templ_data[] = array('name' => 'etemplate.nextmatch_widget.header_only','template' => '','lang' => '','group' => '0','version' => '0.9.15.002','data' => 'a:1:{i:0;a:5:{s:4:"type";s:4:"grid";s:4:"data";a:3:{i:0;a:2:{s:1:"A";s:3:"50%";s:1:"B";s:3:"50%";}i:1;a:2:{s:1:"A";a:2:{s:4:"type";s:8:"template";s:4:"name";s:12:"@header_left";}s:1:"B";a:3:{s:4:"type";s:8:"template";s:5:"align";s:5:"right";s:4:"name";s:13:"@header_right";}}i:2;a:2:{s:1:"A";a:5:{s:4:"type";s:8:"template";s:4:"size";s:4:"rows";s:4:"span";s:3:"all";s:5:"align";s:6:"center";s:4:"name";s:9:"@template";}s:1:"B";a:1:{s:4:"type";s:5:"label";}}}s:4:"rows";i:2;s:4:"cols";i:2;s:4:"size";s:4:"100%";}}','size' => '100%','style' => '.activ_sortcolumn { color: red; font-weight: bold; }
.inactiv_sortcolumn { color: green; font-weight: normal; }','modified' => '1075985789',);

View File

@ -55,6 +55,8 @@
</grid>
</template>
<template id="etemplate.nextmatch_widget" template="" lang="" group="0" version="1.9.001">
<description id="action"/>
<hidden id="selected"/>
<grid width="100%">
<columns>
<column width="35%"/>

View File

@ -5,7 +5,7 @@
* @link http://www.egroupware.org
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @package timesheet
* @copyright (c) 2005-10 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2005-11 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
@ -45,10 +45,6 @@ class timesheet_ui extends timesheet_bo
$this->pm_integration = $this->config_data['pm_integration'];
$this->ts_viewtype = $this->config_data['ts_viewtype'];
// our javascript
// to be moved in a seperate file if rewrite is over
$GLOBALS['egw_info']['flags']['java_script'] .= $this->js();
}
function view()
@ -620,9 +616,9 @@ class timesheet_ui extends timesheet_bo
$total = parent::get_rows($query,$rows,$readonlys);
$ids = array();
foreach($rows as $row)
foreach($rows as &$row)
{
$ids[] = $row['ts_id'];
if ($row['ts_id'] > 0) $ids[] = $row['ts_id'];
}
if ($id_only)
{
@ -691,6 +687,7 @@ class timesheet_ui extends timesheet_bo
if (!$this->quantity_sum) $row['ts_quantity'] = '';
$row['class'] = 'th';
$row['titleClass'] = 'titleSum';
unset($row['ts_id']); // otherwise row would be selectable action-wise
continue;
}
if (!$this->check_acl(EGW_ACL_EDIT,$row))
@ -779,27 +776,33 @@ class timesheet_ui extends timesheet_bo
$content['action'] = 'document';
$content['nm']['rows']['checked'] = array($id);
}
if ($content['action'] != '')
// support old actions
if ($content['action'])
{
if (!count($content['nm']['rows']['checked']) && !$content['use_all'])
$content['nm']['action'] = $content['action'];
$content['nm']['selected'] = $content['nm']['rows']['checked'];
$content['nm']['select_all'] = $content['nm']['select_all'] || $content['use_all'];
}
if ($content['nm']['action'])
{
if (!count($content['nm']['selected']) && !$content['nm']['select_all'])
{
$msg = lang('You need to select some timesheets first');
}
else
{
// Action has a parameter - cat_id, percent, etc
$multi_action = $content['action'];
$multi_action = $content['nm']['action'];
if (in_array($multi_action, array('cat')))
{
if(is_array($content[$multi_action]))
{
$content[$multi_action] = implode(',',$content[$multi_action]);
}
$content['action'] .= '_' . $content[$multi_action];
$content['nm']['action'] .= '_' . $content[$multi_action];
}
if ($this->action($content['action'],$content['nm']['rows']['checked'],$content['use_all'],
$success,$failed,$action_msg,'index',$msg))
if ($this->action($content['nm']['action'],$content['nm']['selected'],$content['nm']['select_all'],
$success,$failed,$action_msg,'index',$msg))
{
$msg .= lang('%1 timesheets(s) %2',$success,$action_msg);
}
@ -811,7 +814,7 @@ class timesheet_ui extends timesheet_bo
}
$content = array(
'nm' => $GLOBALS['egw']->session->appsession('index',TIMESHEET_APP),
// 'nm' => $GLOBALS['egw']->session->appsession('index',TIMESHEET_APP),
'msg' => $msg,
);
if (!is_array($content['nm']))
@ -833,6 +836,9 @@ class timesheet_ui extends timesheet_bo
'header_right' => 'timesheet.index.add',
'filter_onchange' => "set_style_by_class('table','custom_hide','visibility',this.value == 'custom' ? 'visible' : 'hidden'); if (this.value != 'custom') this.form.submit();",
'filter2' => (int)$GLOBALS['egw_info']['user']['preferences'][TIMESHEET_APP]['show_details'],
'row_id' => 'ts_id',
'actions' => $this->get_actions(),
'default_cols' => '!legacy_actions', // switch legacy actions column and row off by default
);
}
if($_GET['search'])
@ -850,33 +856,81 @@ class timesheet_ui extends timesheet_bo
);
$content['nm']['no_status'] = count($sel_options['ts_status']) <= 1; // 1 because of 'No status'
$status =array();
$sel_options['action'] ['delete']= lang('Delete Timesheet');
$sel_options['action']['cat'] = lang('Change category');
foreach ($this->status_labels as $status_id => $label_status)
{
$status['to_status_'.$status_id] = $label_status;
}
$sel_options['action'][lang('Modify the Status of the Timesheet')] = $status;
unset($status);
// Merge print
if ($GLOBALS['egw_info']['user']['preferences']['timesheet']['document_dir'])
{
$sel_options['action'][lang('Insert in document').':'] = timesheet_merge::get_documents($GLOBALS['egw_info']['user']['preferences']['timesheet']['document_dir']);
}
if ($this->pm_integration != 'full')
{
$projects =& $this->query_list('ts_project');
if (!is_array($projects)) $projects = array();
$sel_options['ts_project'] = $projects + array(lang('No project'));
}
// to be moved in a seperate file if rewrite is over
$GLOBALS['egw_info']['flags']['java_script'] .= $this->js();
// dont show [Export] button if app is not availible to the user or we are on php4
$readonlys['export'] = !$GLOBALS['egw_info']['user']['apps']['importexport'] || (int) phpversion() < 5;
return $etpl->exec(TIMESHEET_APP.'.timesheet_ui.index',$content,$sel_options,$readonlys,$preserv);
}
/**
* Get actions / context menu for index
*
* @return array see nextmatch_widget::egw_actions()
*/
private function get_actions()
{
$actions = array(
'view' => array(
'caption' => 'View',
'default' => true,
'allowOnMultiple' => false,
'url' => 'menuaction=timesheet.timesheet_ui.view&ts_id=',
'popup' => egw_link::get_registry('timesheet', 'view_popup'),
'group' => $group=1,
),
'edit' => array(
'caption' => 'Edit',
'allowOnMultiple' => false,
'url' => 'menuaction=timesheet.timesheet_ui.edit&ts_id=',
'popup' => egw_link::get_registry('timesheet', 'add_popup'),
'group' => $group,
),
'add' => array(
'caption' => 'Add',
'url' => 'menuaction=timesheet.timesheet_ui.edit',
'popup' => egw_link::get_registry('timesheet', 'add_popup'),
'group' => $group,
),
'cat' => nextmatch_widget::category_action(
'timesheet',++$group,'Change category','cat_'
),
'status' => array(
'icon' => 'apply',
'caption' => 'Modify status',
'group' => ++$group,
'children' => $this->status_labels,
'prefix' => 'to_status_',
'enabled' => (boolean)$this->status_labels,
'hideOnDisabled' => true,
),
'document' => array(
'caption' => lang('Insert in %1',egw_vfs::basename($GLOBALS['egw_info']['user']['preferences']['timesheet']['default_document'])),
'enabled' => (boolean)$GLOBALS['egw_info']['user']['preferences']['timesheet']['default_document'],
'hideOnDisabled' => true,
'group' => ++$group,
),
'documents' => timesheet_merge::document_action(
$GLOBALS['egw_info']['user']['preferences']['timesheet']['document_dir'], $group
),
'delete' => array(
'caption' => 'Delete',
'confirm' => 'Delete this entry',
'group' => ++$group,
),
);
return $actions;
}
/**
* apply an action to multiple timesheets
*
@ -967,7 +1021,7 @@ class timesheet_ui extends timesheet_bo
case 'document':
$msg = $this->download_document($checked,$settings);
$failed = count($checked);
return false;
return false;
}
return !$failed;
@ -1069,34 +1123,7 @@ class timesheet_ui extends timesheet_bo
"Export",400,400);
return false;
}
/**
* Javascript handling for multiple entry actions
*/
function do_action(selbox)
{
if(selbox.value == "") return;
var prefix = selbox.id.substring(0,selbox.id.indexOf("["));
var popup = document.getElementById(prefix + "[" + selbox.value + "_popup]");
if(popup) {
popup.style.display = "block";
return;
}
selbox.form.submit();
selbox.value = "";
}
/**
* Hide popup and clear values
*/
function hide_popup(element, div_id) {
var prefix = element.id.substring(0,element.id.indexOf("["));
var popup = document.getElementById(prefix+"["+div_id+"]");
if(popup) {
popup.style.display = "none";
}
}
</script>';
</script>';
}
/**
@ -1120,7 +1147,6 @@ class timesheet_ui extends timesheet_bo
{
return lang("Document '%1' does not exist or is not readable for you!",$document);
}
require_once(EGW_INCLUDE_ROOT.'/timesheet/inc/class.timesheet_merge.inc.php');
$document_merge = new timesheet_merge();
return $document_merge->download($document,$ids);

View File

@ -26,7 +26,6 @@ custom fields timesheet de Benutzerdefinierte Felder
default document to insert entries timesheet de Standarddokument zum Einfügen von Stundenzetteln
delete this entry timesheet de Diesen Eintrag löschen
delete this status timesheet de Diesen Status löschen
delete timesheet timesheet de Stundenzettel löschen
deleted timesheet de gelöscht
deletes this field timesheet de Dies Feld löschen
determines the order the fields are displayed timesheet de verändert die Reihenfolge der angezeigten Felder
@ -65,6 +64,7 @@ if you specify a document (full vfs path) here, %1 displays an extra document ic
if you specify an export definition, it will be used when you export timesheet de Wählen Sie eine Export Definition für den Export
imports entries into the timesheet from a csv file. timesheet de Importiert Einträge für den Stundenzettel aus einer CSV Datei.
insert timesheet de einfügen
insert in %1 timesheet de In %1 einfügen
insert in document timesheet de In ein Dokument einfügen
invalid field: %1 = %2, it needs to be a number. timesheet de Ungültiges Feld: %1 =%2, es muss eine Zahl sein
invalid owner id: %1. might be a bad field translation. used %2 instead. timesheet de Ungültiger Benutze ID: %1 könnte eine falsche Feldzuordnung haben. %2 wird stattdessen verwendet.
@ -79,7 +79,7 @@ links timesheet de Verknüpfungen
manage mapping timesheet de Verwaltung der Feldzuordnung
max length of the input [, length of the inputfield (optional)] timesheet de maximale Länge der Eingabe[,Länge des Eingabefeldes (optional)]
modified timesheet de Geändert
modify the status of the timesheet timesheet de Status des Stundenzettels verändern
modify status timesheet de Status ändern
name of current user, all other contact fields are valid too timesheet de Name des aktuellen Benutzers, all anderen Kontaktfelder sind weiterhin gültig.
new ticket submitted by %1 at %2 timesheet de Neues Ticket erstellt von %1 am %2
new timesheet submitted by %1 at %2 timesheet de Neuer Stundenzettel von %1 am %2

View File

@ -26,7 +26,6 @@ custom fields timesheet en Custom fields
default document to insert entries timesheet en Default document to insert entries
delete this entry timesheet en Delete this entry
delete this status timesheet en Delete this status
delete timesheet timesheet en Delete Timesheet
deleted timesheet en deleted
deletes this field timesheet en deletes this field
determines the order the fields are displayed timesheet en determines the order the fields are displayed
@ -65,6 +64,7 @@ if you specify a document (full vfs path) here, %1 displays an extra document ic
if you specify an export definition, it will be used when you export timesheet en If you specify an export definition, it will be used when you export
imports entries into the timesheet from a csv file. timesheet en Imports entries into the timesheet from a CSV File.
insert timesheet en insert
insert in %1 timesheet en Insert in %1
insert in document timesheet en Insert in document
invalid field: %1 = %2, it needs to be a number. timesheet en Invalid field: %1 = %2, it needs to be a number.
invalid owner id: %1. might be a bad field translation. used %2 instead. timesheet en Invalid owner ID: %1. Might be a bad field translation. Used %2 instead.
@ -79,7 +79,7 @@ links timesheet en Links
manage mapping timesheet en Manage mapping
max length of the input [, length of the inputfield (optional)] timesheet en max length of the input [, length of the inputfield (optional)]
modified timesheet en Modified
modify the status of the timesheet timesheet en Modify the Status of the Timesheet
modify status timesheet en Modify status
name of current user, all other contact fields are valid too timesheet en Name of current user, all other contact fields are valid too
new ticket submitted by %1 at %2 timesheet en New ticket submitted by %1 at %2
new timesheet submitted by %1 at %2 timesheet en New timesheet submitted by %1 at %2

File diff suppressed because one or more lines are too long

View File

@ -15,7 +15,7 @@
<template id="timesheet.index.add" template="" lang="" group="0" version="1.7.001">
<buttononly label="Add" id="add" onclick="window.open(egw::link('/index.php','menuaction=timesheet.timesheet_ui.edit'),'_blank','dependent=yes,width=600,height=400,scrollbars=yes,status=yes'); return false;"/>
</template>
<template id="timesheet.index.rows" template="" lang="" group="0" version="1.7.003">
<template id="timesheet.index.rows" template="" lang="" group="0" version="1.9.001">
<grid width="100%">
<columns>
<column width="15%"/>
@ -70,7 +70,7 @@
<nextmatch-filterheader id="ts_status" onchange="1" options="All status"/>
<nextmatch-customfields id="customfields"/>
<hbox class="noPrint">
<description value="Actions" class="noPrint" align="right"/>
<nextmatch-header label="Actions" class="noPrint" align="right" id="legacy_actions"/>
<button label="Check all" image="check" id="check_all" needed="1" statustext="Check all" onclick="toggle_all(this.form,form::name('checked[]')); return false;"/>
</hbox>
</row>
@ -98,6 +98,7 @@
<hbox class="noPrint" align="right">
<button image="view" label="View" id="view[$row_cont[ts_id]]" onclick="window.open(egw::link('/index.php','menuaction=timesheet.timesheet_ui.view&amp;ts_id=$row_cont[ts_id]'),'_blank','dependent=yes,width=600,height=400,scrollbars=yes,status=yes'); return false;" statustext="View this entry"/>
<button image="edit" label="Edit" id="edit[$row_cont[ts_id]]" statustext="Edit this entry" onclick="window.open(egw::link('/index.php','menuaction=timesheet.timesheet_ui.edit&amp;ts_id=$row_cont[ts_id]'),'_blank','dependent=yes,width=600,height=400,scrollbars=yes,status=yes'); return false;"/>
<button id="document[$row_cont[ts_id]]" image="etemplate/merge" label="Insert in document" class="image16"/>
<button image="delete" label="Delete" id="delete[$row_cont[ts_id]]" statustext="Delete this entry" onclick="return confirm('Delete this entry');"/>
<checkbox options="$row_cont[ts_id]" id="checked[]" statustext="Select multiple timeshhets for a further action"/>
</hbox>
@ -105,7 +106,7 @@
</rows>
</grid>
</template>
<template id="timesheet.index" template="" lang="" group="0" version="1.7.003">
<template id="timesheet.index" template="" lang="" group="0" version="1.9.001">
<grid width="100%">
<columns>
<column/>
@ -126,20 +127,14 @@
<row>
<nextmatch id="nm" options="timesheet.index.rows" span="all"/>
</row>
<row class="noPrint">
<row class="noPrint" disabled="!@nm[selectcols]=/legacy_actions/">
<button label="Add" id="add" onclick="window.open(egw::link('/index.php','menuaction=timesheet.timesheet_ui.edit'),'_blank','dependent=yes,width=600,height=400,scrollbars=yes,status=yes'); return false;"/>
<hbox align="right">
<checkbox id="use_all" label="whole query" onchange="if (this.checked==true &amp;&amp; !confirm('Apply the action on the whole query, NOT only the shown timesheets!!!')) this.checked=false;" statustext="Apply the action on the whole query, NOT only the shown timesheets!!!"/>
<menulist>
<menupopup onchange="do_action(this);" options="Select action" id="action" statustext="Select action"/>
</menulist>
<buttononly id="legacy_actions" statustext="Select action" label="Select action" onclick="if (!egw_objectManager.executeActionImplementation(this, 'popup')) alert(egw::lang('You need to select some timesheets first')); return false;;"/>
<button image="arrow_ltr" label="Check all" id="check_all" statustext="Check all" onclick="toggle_all(this.form,form::name('nm[rows][checked][]')); return false;" needed="1" class="checkAllArrow"/>
</hbox>
</row>
<row disabled="1">
<button label="Export" onclick="timesheet_export(); return false;" id="export"/>
<description/>
</row>
</rows>
</grid>
</template>