egroupware/calendar/inc/class.calendar_ui.inc.php
Nathan Gray 33437acb96 Keep internal date span up to date if user is using list view and week or month filter.
Fixes some problems with strange date ranges when merging using the sidemenu selectbox
2015-12-11 19:38:52 +00:00

896 lines
29 KiB
PHP

<?php
/**
* eGroupWare - Calendar's shared base-class of all UI classes
*
* @link http://www.egroupware.org
* @package calendar
* @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
* @copyright (c) 2004-15 by RalfBecker-At-outdoor-training.de
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
* @version $Id$
*/
/**
* Shared base-class of all calendar UserInterface classes
*
* It manages eg. the state of the controls in the UI and generated the calendar navigation (sidebox-menu)
*
* The new UI, BO and SO classes have a strikt definition, in which time-zone they operate:
* UI only operates in user-time, so there have to be no conversation at all !!!
* BO's functions take and return user-time only (!), they convert internaly everything to servertime, because
* SO operates only on server-time
*
* All permanent debug messages of the calendar-code should done via the debug-message method of the bocal class !!!
*/
class calendar_ui
{
/**
* @var $debug mixed integer level or string function-name
*/
var $debug=false;
/**
* instance of the bocal or bocalupdate class
*
* @var calendar_boupdate
*/
var $bo;
/**
* instance of jscalendar
*
* @var jscalendar
*/
var $jscal;
/**
* Reference to global datetime class
*
* @var egw_datetime
*/
var $datetime;
/**
* Instance of categories class
*
* @var categories
*/
var $categories;
/**
* Reference to global uiaccountsel class
*
* @var uiaccountsel
*/
var $accountsel;
/**
* @var array $common_prefs reference to $GLOBALS['egw_info']['user']['preferences']['common']
*/
var $common_prefs;
/**
* @var array $cal_prefs reference to $GLOBALS['egw_info']['user']['preferences']['calendar']
*/
var $cal_prefs;
/**
* @var int $wd_start user pref. workday start
*/
var $wd_start;
/**
* @var int $wd_start user pref. workday end
*/
var $wd_end;
/**
* @var int $interval_m user pref. interval
*/
var $interval_m;
/**
* @var int $user account_id of loged in user
*/
var $user;
/**
* @var string $date session-state: date (Ymd) of shown view
*/
var $date;
/**
* @var int $cat_it session-state: selected category
*/
var $cat_id;
/**
* @var int $filter session-state: selected filter, at the moment all or hideprivate
*/
var $filter;
/**
* @var int/array $owner session-state: selected owner(s) of shown calendar(s)
*/
var $owner;
/**
* @var string $sortby session-state: filter of planner: 'category' or 'user'
*/
var $sortby;
/**
* @var string $view session-state: selected view
*/
var $view;
/**
* @var string $view menuaction of the selected view
*/
var $view_menuaction;
/**
* @var boolean test checkbox checked
*/
var $test;
/**
* @var int $first first day of the shown view
*/
var $first;
/**
* @var int $last last day of the shown view
*/
var $last;
/**
* @var array $states_to_save all states that will be saved to the user prefs
*/
var $states_to_save = array('owner','filter','cat_id','view','sortby','planner_days','weekend');
/**
* Constructor
*
* @param boolean $use_boupdate use bocalupdate as parenent instead of bocal
* @param array $set_states to manualy set / change one of the states, default NULL = use $_REQUEST
*/
function __construct($use_boupdate=false,$set_states=NULL)
{
if ($use_boupdate)
{
$this->bo = new calendar_boupdate();
}
else
{
$this->bo = new calendar_bo();
}
$this->jscal = $GLOBALS['egw']->jscalendar;
$this->datetime = $GLOBALS['egw']->datetime;
$this->accountsel = $GLOBALS['egw']->uiaccountsel;
$this->categories = new categories($this->user,'calendar');
$this->common_prefs = &$GLOBALS['egw_info']['user']['preferences']['common'];
$this->cal_prefs = &$GLOBALS['egw_info']['user']['preferences']['calendar'];
$this->bo->check_set_default_prefs();
$this->wd_start = 60*$this->cal_prefs['workdaystarts'];
$this->wd_end = 60*$this->cal_prefs['workdayends'];
$this->interval_m = $this->cal_prefs['interval'];
$this->user = $GLOBALS['egw_info']['user']['account_id'];
$this->manage_states($set_states);
$GLOBALS['uical'] = &$this; // make us available for ExecMethod, else it creates a new instance
// calendar does not work with hidden sidebox atm.
unset($GLOBALS['egw_info']['user']['preferences']['common']['auto_hide_sidebox']);
// make sure the hook for export_limit is registered
if (!$GLOBALS['egw']->hooks->hook_exists('export_limit','calendar')) $GLOBALS['egw']->hooks->register_single_app_hook('calendar','export_limit');
}
/**
* Checks and terminates (or returns for home) with a message if $this->owner include a user/resource we have no read-access to
*
* If currentapp == 'home' we return the error instead of terminating with it !!!
*
* @return boolean/string false if there's no error or string with error-message
*/
function check_owners_access($users = null, &$no_access = array())
{
$no_access = $no_access_group = array();
$owner_array = $users ? $users : explode(',',$this->owner);
foreach($owner_array as $idx => $owner)
{
$owner = trim($owner);
if (is_numeric($owner) && $GLOBALS['egw']->accounts->get_type($owner) == 'g')
{
foreach($GLOBALS['egw']->accounts->member($owner) as $member)
{
$member = $member['account_id'];
if (!$this->bo->check_perms(EGW_ACL_READ|EGW_ACL_READ_FOR_PARTICIPANTS|EGW_ACL_FREEBUSY,0,$member))
{
$no_access_group[$member] = $this->bo->participant_name($member);
}
}
}
elseif (!$this->bo->check_perms(EGW_ACL_READ|EGW_ACL_READ_FOR_PARTICIPANTS|EGW_ACL_FREEBUSY,0,$owner))
{
$no_access[$owner] = $this->bo->participant_name($owner);
unset($owner_array[$idx]);
}
}
if (count($no_access))
{
$message = lang('Access denied to the calendar of %1 !!!',implode(', ',$no_access));
egw_framework::message($message,'error');
$this->owner = implode(',',$owner_array);
return $message;
}
if (count($no_access_group))
{
$this->bo->warnings['groupmembers'] = lang('Groupmember(s) %1 not included, because you have no access.',implode(', ',$no_access_group));
}
return false;
}
/**
* show the egw-framework plus evtl. $this->group_warning from check_owner_access
*/
function do_header()
{
// Include the jQuery-UI CSS - many more complex widgets use it
$theme = 'redmond';
egw_framework::includeCSS("/phpgwapi/js/jquery/jquery-ui/$theme/jquery-ui-1.10.3.custom.css");
// Load our CSS after jQuery-UI, so we can override it
egw_framework::includeCSS('/etemplate/templates/default/etemplate2.css');
// load etemplate2
egw_framework::validate_file('/etemplate/js/etemplate2.js');
// load our app.js file
egw_framework::validate_file('/calendar/js/app.js');
common::egw_header();
if ($this->bo->warnings) echo '<pre class="message" align="center">'.html::htmlspecialchars(implode("\n",$this->bo->warnings))."</pre>\n";
}
/**
* Manages the states of certain controls in the UI: date shown, category selected, ...
*
* The state of all these controls is updated if they are set in $_REQUEST or $set_states and saved in the session.
* The following states are used:
* - date or year, month, day: the actual date of the period displayed
* - cat_id: the selected category
* - owner: the owner of the displayed calendar
* - save_owner: the overriden owner of the planner
* - filter: the used filter: all or hideprivate
* - sortby: category or user of planner
* - view: the actual view, where dialogs should return to or which they refresh
* @param array $set_states array to manualy set / change one of the states, default NULL = use $_REQUEST
*/
function manage_states($set_states=NULL)
{
// retrieve saved states from prefs
$states = is_array($this->bo->cal_prefs['saved_states']) ?
$this->bo->cal_prefs['saved_states'] : unserialize($this->bo->cal_prefs['saved_states']);
// only look at _REQUEST, if we are in the calendar (prefs and admin show our sidebox menu too!)
if (is_null($set_states))
{
// ajax-exec call has get-parameter in some json
if (isset($_REQUEST['json_data']) && ($json_data = json_decode($_REQUEST['json_data'], true)) &&
!empty($json_data['request']['parameters'][0]))
{
if (is_array($json_data['request']['parameters'][0]))
{
//error_log(__METHOD__.__LINE__.array2string($json_data['request']['parameters'][0]));
$set_states = $json_data['request']['parameters'][0];
}
else
{
parse_str(substr($json_data['request']['parameters'][0], 10), $set_states); // cut off "/index.php?"
}
}
else
{
$set_states = substr($_GET['menuaction'],0,9) == 'calendar.' ? $_REQUEST : array();
}
}
if (!$states['date'] && $states['year'] && $states['month'] && $states['day'])
{
$states['date'] = $this->bo->date2string($states);
}
foreach(array(
'date' => $this->bo->date2string($this->bo->now_su),
'cat_id' => 0,
'filter' => 'default',
'owner' => $this->user,
'save_owner' => 0,
'sortby' => 'category',
'planner_days'=> 0, // full month
'view' => ($this->bo->cal_prefs['defaultcalendar']?$this->bo->cal_prefs['defaultcalendar']:'day'), // use pref, if exists else use the dayview
'listview_days'=> '', // no range
'test' => 'false',
) as $state => $default)
{
if (isset($set_states[$state]))
{
if ($state == 'owner')
{
// only change the owners of the same resource-type as given in set_state[owner]
$set_owners = is_array($set_states['owner']) ? $set_states['owner'] : explode(',',$set_states['owner']);
if ((string)$set_owners[0] === '0') // set exactly the specified owners (without the 0)
{
if ($set_states['owner'] === '0,r0') // small fix for resources
{
$set_states['owner'] = $default; // --> set default, instead of none
}
else
{
$set_states['owner'] = substr($set_states['owner'],2);
}
}
else // change only the owners of the given type
{
$res_type = is_numeric($set_owners[0]) ? false : $set_owners[0][0];
$owners = $states['owner'] ? $states['owner'] : $default;
if(!is_array($owners))
{
$owners = explode(',',$owners);
}
foreach($owners as $key => $owner)
{
if (!$res_type && is_numeric($owner) || $res_type && $owner[0] == $res_type)
{
unset($owners[$key]);
}
}
if (!$res_type || !in_array($res_type.'0',$set_owners))
{
$owners = array_merge($owners,$set_owners);
}
$set_states['owner'] = implode(',',$owners);
}
}
// for the uiforms class (eg. edit), dont store the (new) owner, as it might change the view
if (substr($_GET['menuaction'],0,25) == 'calendar.calendar_uiforms')
{
$this->owner = $set_states[$state];
continue;
}
$states[$state] = $set_states[$state];
}
elseif (!is_array($states) || !isset($states[$state]))
{
$states[$state] = $default;
}
if ($state == 'date')
{
$date_arr = $this->bo->date2array($states['date']);
foreach(array('year','month','day') as $name)
{
$this->$name = $states[$name] = $date_arr[$name];
}
}
$this->$state = $states[$state];
}
// remove a given calendar from the view
if (isset($_GET['close']) && ($k = array_search($_GET['close'], $owners=explode(',',$this->owner))) !== false)
{
unset($owners[$k]);
$this->owner = $states['owner'] = implode(',',$owners);
}
if(is_array($this->owner))
{
$this->owner = implode(',',$this->owner);
}
if (substr($this->view,0,8) == 'planner_')
{
$states['sortby'] = $this->sortby = $this->view == 'planner_cat' ? 'category' : 'user';
$states['view'] = $this->view = 'planner';
}
// set the actual view as return_to
if (isset($_GET['menuaction']))
{
list(,$class,$func) = explode('.',$_GET['menuaction']);
if ($func == 'index')
{
$func = $this->view; $this->view = 'index'; // switch to the default view
}
}
else // eg. calendar/index.php
{
$func = $this->view;
$class = $this->view == 'listview' ? 'calendar_uilist' : 'calendar_uiviews';
}
if ($class == 'calendar_uiviews' || $class == 'calendar_uilist')
{
// if planner_start_with_group is set in the users prefs: switch owner for planner to planner_start_with_group and back
if ($this->cal_prefs['planner_start_with_group'])
{
if ($this->cal_prefs['planner_start_with_group'] > 0) $this->cal_prefs['planner_start_with_group'] *= -1; // fix old 1.0 pref
if (!$states_session && !$_GET['menuaction']) $this->view = ''; // first call to calendar
if ($func == 'planner' && $this->view != 'planner' && $this->owner == $this->user)
{
//echo "<p>switched for planner to {$this->cal_prefs['planner_start_with_group']}, view was $this->view, func=$func, owner was $this->owner</p>\n";
$states['save_owner'] = $this->save_owner = $this->owner;
$states['owner'] = $this->owner = $this->cal_prefs['planner_start_with_group'];
}
elseif ($func != 'planner' && $this->view == 'planner' && $this->owner == $this->cal_prefs['planner_start_with_group'] && $this->save_owner)
{
//echo "<p>switched back to $this->save_owner, view was $this->view, func=$func, owner was $this->owner</p>\n";
$states['owner'] = $this->owner = $this->save_owner;
$states['save_owner'] = $this->save_owner = 0;
}
}
$this->view = $states['view'] = $func;
}
$this->view_menuaction = $this->view == 'listview' ? 'calendar.calendar_uilist.listview' : 'calendar.calendar_uiviews.index';
if ($this->debug > 0 || $this->debug == 'manage_states') $this->bo->debug_message('uical::manage_states(%1) session was %2, states now %3',True,$set_states,$states_session,$states);
// save the states in the session only when we are in calendar
if ($GLOBALS['egw_info']['flags']['currentapp']=='calendar')
{
// save defined states into the user-prefs
if(!empty($states) && is_array($states))
{
$saved_states = array_intersect_key($states,array_flip($this->states_to_save));
if ($saved_states != $this->cal_prefs['saved_states'])
{
$GLOBALS['egw']->preferences->add('calendar','saved_states',$saved_states);
$GLOBALS['egw']->preferences->save_repository(false,'user',true);
}
}
}
}
/**
* gets the icons displayed for a given event
*
* @param array $event
* @return array of 'img' / 'title' pairs
*/
function event_icons($event)
{
$is_private = !$event['public'] && !$this->bo->check_perms(EGW_ACL_READ,$event);
$icons = array();
if (!$is_private)
{
if($event['priority'] == 3)
{
$icons[] = html::image('calendar','high',lang('high priority'));
}
if($event['recur_type'] != MCAL_RECUR_NONE)
{
$icons[] = html::image('calendar','recur',lang('recurring event'));
}
// icons for single user, multiple users or group(s) and resources
foreach(array_keys($event['participants']) as $uid)
{
if(is_numeric($uid) || !isset($this->bo->resources[$uid[0]]['icon']))
{
if (isset($icons['single']) || $GLOBALS['egw']->accounts->get_type($uid) == 'g')
{
unset($icons['single']);
$icons['multiple'] = html::image('calendar','users');
}
elseif (!isset($icons['multiple']))
{
$icons['single'] = html::image('calendar','single');
}
}
elseif(!isset($icons[$uid[0]]) && isset($this->bo->resources[$uid[0]]) && isset($this->bo->resources[$uid[0]]['icon']))
{
$icons[$uid[0]] = html::image($this->bo->resources[$uid[0]]['app'],
($this->bo->resources[$uid[0]]['icon'] ? $this->bo->resources[$uid[0]]['icon'] : 'navbar'),
lang($this->bo->resources[$uid[0]]['app']),
'width="16px" height="16px"');
}
}
}
if($event['non_blocking'])
{
$icons[] = html::image('calendar','nonblocking',lang('non blocking'));
}
if($event['public'] == 0)
{
$icons[] = html::image('calendar','private',lang('private'));
}
if(isset($event['alarm']) && count($event['alarm']) >= 1 && !$is_private)
{
$icons[] = html::image('calendar','alarm',lang('alarm'));
}
if($event['participants'][$this->user][0] == 'U')
{
$icons[] = html::image('calendar','needs-action',lang('Needs action'));
}
return $icons;
}
/**
* Create a select-box item in the sidebox-menu
* @privat used only by sidebox_menu !
*/
function _select_box($title,$name,$options,$width='99%')
{
$select = " <select style=\"width: $width;\" name=\"".$name.'" id="calendar_'.$name.'" title="'.
lang('Select a %1',lang($title)).'">'.
$options."</select>\n";
return array(
'text' => $select,
'no_lang' => True,
'link' => False,
'icon' => false,
);
}
/**
* Generate a link to add an event, incl. the necessary popup
*
* @param string $content content of the link
* @param string $date which date should be used as start- and end-date, default null=$this->date
* @param int $hour which hour should be used for the start, default null=$this->hour
* @param int $minute start-minute
* @param array $vars
* @return string the link incl. content
*/
function add_link($content,$date=null,$hour=null,$minute=0,array $vars=null)
{
$vars['menuaction'] = 'calendar.calendar_uiforms.edit';
$vars['date'] = $date ? $date : $this->date;
if (!is_null($hour))
{
$vars['hour'] = $hour;
$vars['minute'] = $minute;
}
return html::a_href($content,'',$vars,' data-date="' .$vars['date'].'|'.$vars['hour'].'|'.$vars['minute']
. '" title="'.html::htmlspecialchars(lang('Add')).'"');
}
/**
* returns javascript to open a popup window: window.open(...)
*
* @param string $link link or this.href
* @param string $target name of target or this.target
* @param int $width width of the window
* @param int $height height of the window
* @return string javascript (using single quotes)
*/
function popup($link,$target='_blank',$width=750,$height=410)
{
return 'egw_openWindowCentered2('.($link == 'this.href' ? $link : "'".$link."'").','.
($target == 'this.target' ? $target : "'".$target."'").",$width,$height,'yes')";
}
/**
* creates the content for the sidebox-menu, called as hook
*/
function sidebox_menu()
{
$link_vars = array();
// Magic etemplate2 favorites menu (from framework)
display_sidebox('calendar', lang('Favorites'), egw_framework::favorite_list('calendar'));
$file = array('menuOpened' => true); // menu open by default
// Target for etemplate
$file[] = array(
'no_lang' => true,
'text'=>'<span id="calendar-et2_target" />',
'link'=>false,
'icon' => false
);
// Merge print placeholders (selectbox in etemplate)
if ($GLOBALS['egw_info']['user']['preferences']['calendar']['document_dir'])
{
$file['Placeholders'] = egw::link('/index.php','menuaction=calendar.calendar_merge.show_replacements');
}
$appname = 'calendar';
$menu_title = lang('Calendar Menu');
display_sidebox($appname,$menu_title,$file);
$this->sidebox_etemplate();
// resources menu hooks
foreach ($this->bo->resources as $resource)
{
if(!is_array($resource['cal_sidebox'])) continue;
$menu_title = $resource['cal_sidebox']['menu_title'] ? $resource['cal_sidebox']['menu_title'] : lang($resource['app']);
$file = ExecMethod($resource['cal_sidebox']['file'],array(
'menuaction' => $this->view_menuaction,
'owner' => $this->owner,
));
display_sidebox($appname,$menu_title,$file);
}
if ($GLOBALS['egw_info']['user']['apps']['admin'])
{
$file = Array(
'Configuration'=>egw::link('/index.php','menuaction=admin.uiconfig.index&appname=calendar'),
'Custom Fields'=>egw::link('/index.php','menuaction=admin.customfields.index&appname=calendar'),
'Holiday Management'=>egw::link('/index.php','menuaction=calendar.uiholiday.admin'),
'Global Categories' =>egw::link('/index.php','menuaction=admin.admin_categories.index&appname=calendar'),
);
$GLOBALS['egw']->framework->sidebox($appname,lang('Admin'),$file,'admin');
}
}
/**
* Makes the sidebox content with etemplate, after hook is processed
*/
function sidebox_etemplate($content = array())
{
if($content['merge'])
{
// View from sidebox is JSON encoded
$this->manage_states(array_merge($content,json_decode($content['view'],true)));
if($content['first'])
{
$this->first = egw_time::to($content['first'],'ts');
}
if($content['last'])
{
$this->last = new egw_time($content['last']);
}
$this->last->setTime(23, 59, 59);
$this->last = $this->last->format('ts');
$_GET['merge'] = $content['merge'];
$this->merge();
return;
}
$sidebox = new etemplate_new('calendar.sidebox');
$content = $this->cal_prefs['saved_states'];
$content['view'] = $this->view ? $this->view : 'week';
$content['date'] = $this->date ? $this->date : egw_time();
$owners = $this->owner ? is_array($this->owner) ? array($this->owner) : explode(',',$this->owner) : array($GLOBALS['egw_info']['user']['account_id']);
$sel_options = array();
// Add external owners that a select account widget will not find
foreach($owners as $owner)
{
if(!is_numeric(substr($owner, 0,1)))
{
$resource = $this->bo->resources[substr($owner, 0,1)];
$sel_options['owner'][] = array('value' => $owner, 'label' => egw_link::title($resource['app'], substr($owner,1)));
}
}
$readonlys = array();
foreach(array(
array(
'text' => lang('dayview'),
'value' => '{"view":"day"}',
'selected' => $this->view == 'day',
),
array(
'text' => lang('four days view'),
'value' => '{"view":"day4","days":4}',
'selected' => $this->view == 'day4',
),
array(
'text' => lang('weekview'),
'value' => '{"view":"week"}',
'selected' => $this->view == 'week',
),
array(
'text' => lang('Multiple week view'),
'value' => '{"view":"weekN"}',
'selected' => $this->view == 'weekN',
),
array(
'text' => lang('monthview'),
'value' => '{"view":"month"}',
'selected' => $this->view == 'month',
),
array(
'text' => lang('planner by category'),
'value' => '{"view":"planner", "sortby":"category"}',
'selected' => $this->view == 'planner' && $this->sortby != 'user',
),
array(
'text' => lang('planner by user'),
'value' => '{"view":"planner","sortby":"user"}',
'selected' => $this->view == 'planner' && $this->sortby == 'user',
),
array(
'text' => lang('yearly planner'),
'value' => '{"view":"planner","sortby":"month"}',
'selected' => $this->view == 'planner' && $this->sortby == 'month',
),
array(
'text' => lang('listview'),
'value' => '{"view":"listview"}',
'selected' => $this->view == 'listview',
),
)as $data)
{
if($data['selected'])
{
$content['view'] = $data['value'];
}
$sel_options['view'][] = array(
'label' => $data['text'],
'value' => $data['value']
);
}
$sel_options['filter'] = array(
array('value' => 'default', 'label' => lang('Not rejected'), 'title' => lang('Show all status, but rejected')),
array('value' => 'accepted', 'label' => lang('Accepted'), 'title' => lang('Show only accepted events')),
array('value' => 'unknown', 'label' => lang('Invitations'), 'title' => lang('Show only invitations, not yet accepted or rejected')),
array('value' => 'tentative', 'label' => lang('Tentative'), 'title' => lang('Show only tentative accepted events')),
array('value' => 'delegated', 'label' => lang('Delegated'), 'title' => lang('Show only delegated events')),
array('value' => 'rejected', 'label' => lang('Rejected'),'title' => lang('Show only rejected events')),
array('value' => 'owner', 'label' => lang('Owner too'),'title' => lang('Show also events just owned by selected user')),
array('value' => 'all', 'label' => lang('All incl. rejected'),'title' => lang('Show all status incl. rejected events')),
array('value' => 'hideprivate', 'label' => lang('Hide private infos'),'title' => lang('Show all events, as if they were private')),
array('value' => 'showonlypublic', 'label' => lang('Hide private events'),'title' => lang('Show only events flagged as public, (not checked as private)')),
array('value' => 'no-enum-groups', 'label' => lang('only group-events'),'title' => lang('Do not include events of group members')),
array('value' => 'not-unknown', 'label' => lang('No meeting requests'),'title' => lang('Show all status, but unknown')),
);
if($GLOBALS['egw_info']['server']['calendar_delete_history'])
{
$sel_options['filter'][] = array('value' => 'deleted', 'label' => lang('Deleted'), 'title' => lang('Show events that have been deleted'));
}
// Merge print
if ($GLOBALS['egw_info']['user']['preferences']['calendar']['document_dir'])
{
$sel_options['merge'] = calendar_merge::get_documents($GLOBALS['egw_info']['user']['preferences']['calendar']['document_dir'], '', null,'calendar');
}
else
{
$readonlys['merge'] = true;
}
// Sidebox?
$sidebox->exec('calendar.calendar_ui.sidebox_etemplate', $content, $sel_options, $readonlys);
}
/**
* Prepare an array of event information for sending to the client
*
* This involves changing timestamps into strings with timezone
*
* @param type $event
*/
public function to_client(&$event)
{
if (!$this->bo->check_perms(EGW_ACL_EDIT,$event))
{
$event['class'] .= 'rowNoEdit ';
}
// Delete disabled for other applications
if (!$this->bo->check_perms(EGW_ACL_DELETE,$event) || !is_numeric($event['id']))
{
$event['class'] .= 'rowNoDelete ';
}
// mark deleted events
if ($event['deleted'])
{
$event['class'] .= 'rowDeleted ';
}
$event['recure'] = $this->bo->recure2string($event);
if (empty($event['description'])) $event['description'] = ' '; // no description screws the titles horz. alignment
if (empty($event['location'])) $event['location'] = ' '; // no location screws the owner horz. alignment
// respect category permissions
if(!empty($event['category']))
{
$event['category'] = $this->categories->check_list(EGW_ACL_READ, $event['category']);
}
$event['non_blocking'] = (bool)$event['non_blocking'];
if(!(int)$event['id'] && preg_match('/^([a-z_-]+)([0-9]+)$/i',$event['id'],$matches))
{
$app = $matches[1];
$app_id = $matches[2];
$icons = array();
if(!($is_private = calendar_bo::integration_get_private($app,$app_id,$event)))
{
$icons = calendar_uiviews::integration_get_icons($app,$app_id,$event);
}
$event['app'] = $app;
$event['app_id'] = $app_id;
}
else
{
$is_private = !$this->bo->check_perms(EGW_ACL_READ,$event);
}
if ($is_private)
{
$event['is_private'] = true;
$event['class'] .= 'rowNoView ';
}
if(!$event['app'])
{
$event['app'] = 'calendar';
}
if(!$event['app_id'])
{
$event['app_id'] = $event['id'];
}
if ($event['recur_type'] != MCAL_RECUR_NONE)
{
$event['app_id'] .= ':'.($event['recur_date'] ? $event['recur_date'] : $event['start']);
}
$event['parts'] = implode(",\n",$this->bo->participants($event,false));
$event['date'] = $this->bo->date2string($event['start']);
// Change dates
foreach(calendar_egw_record::$types['date-time'] as $field)
{
if(is_int($event[$field]))
{
$event[$field] = egw_time::to($event[$field], egw_time::ET2);
}
}
}
public function merge($timespan = array())
{
// Merge print
if($_GET['merge'])
{
if(!$timespan)
{
// Try to make time span into appropriate ranges to match
if(stripos($_GET['merge'],'month') !== false || stripos($_GET['merge'],lang('month')) !== false) $template = 'month';
if(stripos($_GET['merge'],'week') !== false || stripos($_GET['merge'],lang('week')) !== false) $template = 'week';
//error_log("Detected template $template");
switch ($template)
{
case 'month':
// Trim to _only_ the month, do not pad to week start / end
$time = new egw_time($this->date);
$timespan = array(array(
'start' => egw_time::to($time->format('Y-m-01 00:00:00'),'ts'),
'end' => egw_time::to($time->format('Y-m-t 23:59:59'),'ts')
));
break;
case 'week':
$timespan = array();
$start = new egw_time($this->first);
$t = clone $start;
$t->modify('+1 week')->modify('-1 second');
if($t->format('ts') < egw_time::to($this->last,'ts'))
{
do
{
$timespan[] = array(
'start' => $start->format('ts'),
'end' => $t->format('ts')
);
$start->modify('+1 week');
$t->modify('+1 week');
} while( $start->format('ts') < $this->last);
break;
}
// Fall through
default:
$timespan = array(array(
'start' => is_array($this->first) ? $this->bo->date2ts($this->first) : $this->first,
'end' => is_array($this->last) ? $this->bo->date2ts($this->last) : $this->last
));
}
}
$merge = new calendar_merge();
//error_log($_GET['merge'] . ' Timespan: ');foreach($timespan as $t) error_log(egw_time::to($t['start']) . ' - ' . egw_time::to($t['end']));
$error = $merge->download($_GET['merge'], $timespan, '', $GLOBALS['egw_info']['user']['preferences']['calendar']['document_dir']);
// Here? Doesn't actually give the message
egw_framework::refresh_opener($error, 'calendar');
}
unset($_GET['merge']);
if($error)
{
// This doesn't give message either, but at least it doesn't give a blank screen
egw_framework::redirect_link('/index.php', array(
'msg' => $error,
'cd' => 'yes'
));
}
}
}