* Timesheet: fix (un)setting project for adding, editing and save&new timesheets

- fixed et2_widget_textbox to update options.blur in set_blur(), as it is used in getValue, also updating input
- fixed et2_widget_linkentry to trigger change event, after reacting to click on X in search
- fixed timesheet to handle ts_project and pm_id in bo (ts_project is always stored in db for searching, even if it contains no custom project name)
- fixed not working change of project in an existing timesheet
- fixed unsetting of project
This commit is contained in:
Ralf Becker 2014-10-14 15:58:37 +00:00
parent fa11f01258
commit 83b6706964
6 changed files with 129 additions and 42 deletions

View File

@ -545,6 +545,7 @@ var et2_link_entry = et2_inputWidget.extend(
this._super.apply(this, arguments); this._super.apply(this, arguments);
this.search = null; this.search = null;
this.clear = null;
this.app_select = null; this.app_select = null;
this._oldValue = { this._oldValue = {
id: null, id: null,
@ -570,6 +571,7 @@ var et2_link_entry = et2_inputWidget.extend(
this.search.autocomplete("destroy"); this.search.autocomplete("destroy");
} }
this.search = null; this.search = null;
this.clear = null;
this.app_select = null; this.app_select = null;
this.request = null; this.request = null;
}, },
@ -691,6 +693,7 @@ var et2_link_entry = et2_inputWidget.extend(
this.clear = $j(document.createElement("span")) this.clear = $j(document.createElement("span"))
.addClass("ui-icon ui-icon-close") .addClass("ui-icon ui-icon-close")
.click(function(e){ .click(function(e){
if (!self.search) return; // only gives an error, we should never get into that situation
// No way to tell if the results is open, so if they click the button while open, it clears // No way to tell if the results is open, so if they click the button while open, it clears
if(self.last_search && self.last_search != self.search.val()) if(self.last_search && self.last_search != self.search.val())
{ {
@ -705,7 +708,11 @@ var et2_link_entry = et2_inputWidget.extend(
self.search.autocomplete("close"); self.search.autocomplete("close");
self.set_value(null); self.set_value(null);
self.search.val(""); self.search.val("");
self.search.trigger("change"); // call trigger, after finishing this handler, not in the middle of it
window.setTimeout(function()
{
self.search.trigger("change");
}, 0);
} }
self.search.focus(); self.search.focus();
}) })

View File

@ -217,8 +217,10 @@ var et2_textbox = et2_inputWidget.extend(
}); });
} }
} else { } else {
if (!this.getValue()) this.input.val('');
this.input.removeAttr("placeholder"); this.input.removeAttr("placeholder");
} }
this.options.blur = _value;
} }
}); });
et2_register_widget(et2_textbox, ["textbox", "passwd"]); et2_register_widget(et2_textbox, ["textbox", "passwd"]);

View File

@ -152,6 +152,13 @@ class timesheet_bo extends so_sql_cf
*/ */
var $columns_to_search = array('egw_timesheet.ts_id', 'ts_project', 'ts_title', 'ts_description', 'ts_duration', 'ts_quantity', 'ts_unitprice'); var $columns_to_search = array('egw_timesheet.ts_id', 'ts_project', 'ts_title', 'ts_description', 'ts_duration', 'ts_quantity', 'ts_unitprice');
/**
* all cols in data which are not (direct)in the db, for data_merge
*
* @var array
*/
var $non_db_cols = array('pm_id');
function __construct() function __construct()
{ {
parent::__construct(TIMESHEET_APP,'egw_timesheet',self::EXTRA_TABLE,'','ts_extra_name','ts_extra_value','ts_id'); parent::__construct(TIMESHEET_APP,'egw_timesheet',self::EXTRA_TABLE,'','ts_extra_name','ts_extra_value','ts_id');
@ -627,19 +634,21 @@ class timesheet_bo extends so_sql_cf
$this->user = $this->data['ts_modifier']; $this->user = $this->data['ts_modifier'];
} }
// check if we have a real modification // check if we have a real modification of an existing record
// read the old record if ($this->data['ts_id'])
$new =& $this->data;
unset($this->data);
$this->read($new['ts_id']);
$old =& $this->data;
$this->data =& $new;
$changed[] = array();
if (isset($old)) foreach($old as $name => $value)
{ {
if (isset($new[$name]) && $new[$name] != $value) $changed[] = $name; $new =& $this->data;
unset($this->data);
$this->read($new['ts_id']);
$old =& $this->data;
$this->data =& $new;
$changed = array();
if (isset($old)) foreach($old as $name => $value)
{
if (isset($new[$name]) && $new[$name] != $value) $changed[] = $name;
}
} }
if (!$changed) if (isset($old) && !$changed)
{ {
return false; return false;
} }
@ -666,7 +675,6 @@ class timesheet_bo extends so_sql_cf
egw_link::notify_update(TIMESHEET_APP,$this->data['ts_id'],$this->data); egw_link::notify_update(TIMESHEET_APP,$this->data['ts_id'],$this->data);
} }
return $err; return $err;
} }
@ -970,4 +978,68 @@ class timesheet_bo extends so_sql_cf
} }
if ($backup) $this->data = $backup; if ($backup) $this->data = $backup;
} }
/**
* changes the data from the db-format to your work-format
*
* Reimplemented to store just ts_project in db, but have pm_id and ts_project in memory,
* with ts_project only set, if it contains a custom project name.
*
* @param array $data =null if given works on that array and returns result, else works on internal data-array
* @return array
*/
function db2data($data=null)
{
if (($intern = !is_array($data)))
{
$data =& $this->data;
}
// get pm_id from links and ts_project: either project matching ts_project or first found project
if (!isset($data['pm_id']) && $data['ts_id'])
{
$first_pm_id = null;
foreach(egw_link::get_links('timesheet', $data['ts_id'], 'projectmanager') as $pm_id)
{
if (!isset($first_pm_id)) $first_pm_id = $pm_id;
if ($data['ts_project'] == egw_link::title('projectmanager', $pm_id))
{
$data['pm_id'] = $pm_id;
$data['ts_project_blur'] = $data['ts_project'];
$data['ts_project'] = '';
break;
}
}
if (!isset($data['pm_id']) && isset($first_pm_id)) $data['pm_id'] = $first_pm_id;
}
elseif ($data['ts_id'] && $data['pm_id'] && egw_link::title('projectmanager', $data['pm_id']) == $data['ts_project'])
{
$data['ts_project_blur'] = $data['ts_project'];
$data['ts_project'] = '';
}
return parent::db2data($intern ? null : $data); // important to use null, if $intern!
}
/**
* changes the data from your work-format to the db-format
*
* Reimplemented to store just ts_project in db, but have pm_id and ts_project in memory,
* with ts_project only set, if it contains a custom project name.
*
* @param array $data =null if given works on that array and returns result, else works on internal data-array
* @return array
*/
function data2db($data=null)
{
if (($intern = !is_array($data)))
{
$data =& $this->data;
}
// allways store ts_project to be able to search for it, even if no custom project is set
if (empty($data['ts_project']))
{
$data['ts_project'] = $data['pm_id'] ? egw_link::title('projectmanager', $data['pm_id']) : '';
}
return parent::data2db($intern ? null : $data); // important to use null, if $intern!
}
} }

View File

@ -91,6 +91,7 @@ class timesheet_ui extends timesheet_bo
$only_admin_edit = true; $only_admin_edit = true;
$msg = lang('only Admin can edit this status'); $msg = lang('only Admin can edit this status');
} }
$this->data['ts_project_blur'] = $this->data['pm_id'] ? egw_link::title('projectmanager', $this->data['pm_id']) : '';
} }
else else
{ {
@ -144,19 +145,12 @@ class timesheet_ui extends timesheet_bo
list($button) = @each($content['button']); list($button) = @each($content['button']);
$view = $content['view']; $view = $content['view'];
$referer = $content['referer']; $referer = $content['referer'];
$content['ts_project_blur'] = $content['pm_id'] ? egw_link::title('projectmanager', $content['pm_id']) : '';
$this->data = $content; $this->data = $content;
foreach(array('button','view','referer','tabs','start_time') as $key) foreach(array('button','view','referer','tabs','start_time') as $key)
{ {
unset($this->data[$key]); unset($this->data[$key]);
} }
// user switched project to none --> remove project and blur
if ($this->data['ts_project_blur'] && !$this->data['pm_id'] && $this->data['old_pm_id'])
{
unset($this->data['ts_project_blur']);
unset($content['ts_project_blur']);
unset($this->data['ts_project']);
unset($content['ts_project']);
}
switch($button) switch($button)
{ {
case 'edit': case 'edit':
@ -186,8 +180,6 @@ class timesheet_ui extends timesheet_bo
{ {
$etpl->set_validation_error('start_time',lang('Starttime has to be before endtime !!!')); $etpl->set_validation_error('start_time',lang('Starttime has to be before endtime !!!'));
} }
// only store project-blur, if a project is selected
if (!$this->data['ts_project'] && $this->data['pm_id']) $this->data['ts_project'] = $this->data['ts_project_blur'];
// set ts_title to ts_project if short viewtype (title is not editable) // set ts_title to ts_project if short viewtype (title is not editable)
if($this->ts_viewtype == 'short') if($this->ts_viewtype == 'short')
{ {
@ -213,6 +205,20 @@ class timesheet_ui extends timesheet_bo
} }
if ($etpl->validation_errors()) break; // the user need to fix the error, before we can save the entry if ($etpl->validation_errors()) break; // the user need to fix the error, before we can save the entry
// account for changed project --> remove old one from links and add new one
if ((int) $this->data['pm_id'] != (int) $this->data['old_pm_id'])
{
// update links accordingly
if ($this->data['pm_id'])
{
egw_link::link(TIMESHEET_APP,$content['link_to']['to_id'],'projectmanager',$this->data['pm_id']);
}
if ($this->data['old_pm_id'])
{
egw_link::unlink2(0,TIMESHEET_APP,$content['link_to']['to_id'],0,'projectmanager',$this->data['old_pm_id']);
unset($this->data['old_pm_id']);
}
}
// check if we are linked to a project, but that is NOT set as project // check if we are linked to a project, but that is NOT set as project
if (!$this->data['pm_id'] && is_array($content['link_to']['to_id'])) if (!$this->data['pm_id'] && is_array($content['link_to']['to_id']))
{ {
@ -221,6 +227,7 @@ class timesheet_ui extends timesheet_bo
if ($data['app'] == 'projectmanager') if ($data['app'] == 'projectmanager')
{ {
$this->data['pm_id'] = $data['id']; $this->data['pm_id'] = $data['id'];
$this->data['ts_project_blur'] = egw_link::title('projectmanager', $data['id']);
break; break;
} }
} }
@ -234,19 +241,6 @@ class timesheet_ui extends timesheet_bo
else else
{ {
$msg = lang('Entry saved'); $msg = lang('Entry saved');
if ((int) $this->data['pm_id'] != (int) $this->data['old_pm_id'])
{
// update links accordingly
if ($this->data['pm_id'])
{
egw_link::link(TIMESHEET_APP,$content['link_to']['to_id'],'projectmanager',$this->data['pm_id']);
}
if ($this->data['old_pm_id'])
{
egw_link::unlink2(0,TIMESHEET_APP,$content['link_to']['to_id'],0,'projectmanager',$this->data['old_pm_id']);
unset($this->data['old_pm_id']);
}
}
if (is_array($content['link_to']['to_id']) && count($content['link_to']['to_id'])) if (is_array($content['link_to']['to_id']) && count($content['link_to']['to_id']))
{ {
egw_link::link(TIMESHEET_APP,$this->data['ts_id'],$content['link_to']['to_id']); egw_link::link(TIMESHEET_APP,$this->data['ts_id'],$content['link_to']['to_id']);
@ -371,10 +365,6 @@ class timesheet_ui extends timesheet_bo
{ {
$content['pm_id'] = $preserv['old_pm_id']; $content['pm_id'] = $preserv['old_pm_id'];
} }
if ($content['pm_id'])
{
$preserv['ts_project_blur'] = $content['ts_project_blur'] = egw_link::title('projectmanager',$content['pm_id']);
}
if ($this->pm_integration == 'full') if ($this->pm_integration == 'full')
{ {
$preserv['ts_project'] = $preserv['ts_project_blur']; $preserv['ts_project'] = $preserv['ts_project_blur'];
@ -392,7 +382,7 @@ class timesheet_ui extends timesheet_bo
// the actual title-blur is either the preserved title blur (if we are called from infolog entry), // the actual title-blur is either the preserved title blur (if we are called from infolog entry),
// or the preserved project-blur comming from the current selected project // or the preserved project-blur comming from the current selected project
$content['ts_title_blur'] = $preserv['ts_title_blur'] ? $preserv['ts_title_blur'] : $preserv['ts_project_blur']; $content['ts_title_blur'] = $preserv['ts_title_blur'] ? $preserv['ts_title_blur'] : $content['ts_project_blur'];
$readonlys = array( $readonlys = array(
'button[delete]' => !$this->data['ts_id'] || !$this->check_acl(EGW_ACL_DELETE) || $this->data['ts_status'] == self::DELETED_STATUS, 'button[delete]' => !$this->data['ts_id'] || !$this->check_acl(EGW_ACL_DELETE) || $this->data['ts_status'] == self::DELETED_STATUS,
'button[undelete]' => $this->data['ts_status'] != self::DELETED_STATUS, 'button[undelete]' => $this->data['ts_status'] != self::DELETED_STATUS,

View File

@ -96,4 +96,20 @@ app.classes.timesheet = AppJS.extend(
egw.css(".et2_label.ts_description","display:" + (filter2.getValue() == '1' ? "block;" : "none;")); egw.css(".et2_label.ts_description","display:" + (filter2.getValue() == '1' ? "block;" : "none;"));
} }
}, },
/**
* Change handler for project selection to set empty ts_project string, if project get deleted
*
* @param {type} _egw
* @param {et2_widget_link_entry} _widget
* @returns {undefined}
*/
pm_id_changed: function(_egw, _widget)
{
var ts_project = this.et2.getWidgetById('ts_project');
if (ts_project)
{
ts_project.set_blur(_widget.getValue() ? _widget.search.val() : '');
}
}
}); });

View File

@ -16,7 +16,7 @@
<row> <row>
<description value="Project" for="ts_project"/> <description value="Project" for="ts_project"/>
<hbox disabled="@pm_integration=none"> <hbox disabled="@pm_integration=none">
<link-entry id="pm_id" onchange="1" only_app='projectmanager' blur='None' class="et2_fullWidth"/> <link-entry id="pm_id" onchange="app.timesheet.pm_id_changed" only_app='projectmanager' blur='None' class="et2_fullWidth"/>
</hbox> </hbox>
<description/> <description/>
<hbox disabled="@pm_integration=full" span="all"> <hbox disabled="@pm_integration=full" span="all">