1<?php 2/* Copyright (c) 1998-2017 ILIAS open source, Extended GPL, see docs/LICENSE */ 3 4/** 5* Presentation day view 6* @author Stefan Meyer <smeyer.ilias@gmx.de> 7* @version $Id$ 8* 9* @ilCtrl_Calls ilCalendarDayGUI: ilCalendarAppointmentGUI 10* @ilCtrl_Calls ilCalendarDayGUI: ilCalendarAppointmentPresentationGUI 11* @ingroup ServicesCalendar 12*/ 13 14include_once('./Services/Calendar/classes/class.ilDate.php'); 15include_once('./Services/Calendar/classes/class.ilCalendarUtil.php'); 16include_once('./Services/Calendar/classes/class.ilCalendarHeaderNavigationGUI.php'); 17include_once('./Services/Calendar/classes/class.ilCalendarUserSettings.php'); 18include_once('./Services/Calendar/classes/class.ilCalendarAppointmentColors.php'); 19include_once './Services/Calendar/classes/class.ilCalendarViewGUI.php'; 20 21 22class ilCalendarDayGUI extends ilCalendarViewGUI 23{ 24 protected $seed_info = array(); 25 protected $user_settings = null; 26 27 /** 28 * @var ilLanguage 29 */ 30 protected $lng; 31 32 /** 33 * @var ilCtrl 34 */ 35 protected $ctrl; 36 37 /** 38 * @var ilTabsGUI 39 */ 40 protected $tabs_gui; 41 42 /** 43 * @var ilTemplate 44 */ 45 protected $tpl; 46 47 protected $num_appointments = 1; 48 49 protected $timezone = 'UTC'; 50 51 /** 52 * @var ilObjUser 53 */ 54 protected $user; 55 56 /** 57 * @var \ILIAS\DI\UIServices 58 */ 59 protected $ui; 60 61 /** 62 * @var ilToolbarGUI 63 */ 64 protected $toolbar; 65 66 /** 67 * Constructor 68 * 69 * @access public 70 * @param 71 * 72 * @todo make parent constructor (initialize) and init also seed and other common stuff 73 */ 74 public function __construct(ilDate $seed_date) 75 { 76 parent::__construct($seed_date, ilCalendarViewGUI::CAL_PRESENTATION_DAY); 77 78 $this->seed_info = $this->seed->get(IL_CAL_FKT_GETDATE); 79 80 $this->user_settings = ilCalendarUserSettings::_getInstanceByUserId($this->user->getId()); 81 $this->app_colors = new ilCalendarAppointmentColors($this->user->getId()); 82 83 $this->timezone = $this->user->getTimeZone(); 84 } 85 86 /** 87 * Execute command 88 * 89 * @access public 90 * 91 */ 92 public function executeCommand() 93 { 94 $ilCtrl = $this->ctrl; 95 $tpl = $this->tpl; 96 97 $next_class = $ilCtrl->getNextClass(); 98 switch ($next_class) { 99 case "ilcalendarappointmentpresentationgui": 100 $this->ctrl->setReturn($this, ""); 101 include_once("./Services/Calendar/classes/class.ilCalendarAppointmentPresentationGUI.php"); 102 $this->logger->debug("-ExecCommand - representation of ilDate: this->seed->get(IL_CAL_DATE) = " . $this->seed->get(IL_CAL_DATE)); 103 $gui = ilCalendarAppointmentPresentationGUI::_getInstance($this->seed, $this->getCurrentApp()); 104 $this->ctrl->forwardCommand($gui); 105 break; 106 case 'ilcalendarappointmentgui': 107 $this->ctrl->setReturn($this, ''); 108 $this->tabs_gui->setSubTabActive($_SESSION['cal_last_tab']); 109 110 // initial date for new calendar appointments 111 $idate = new ilDate($_REQUEST['idate'], IL_CAL_DATE); 112 113 include_once('./Services/Calendar/classes/class.ilCalendarAppointmentGUI.php'); 114 $app = new ilCalendarAppointmentGUI($this->seed, $idate, (int) $_GET['app_id']); 115 $this->ctrl->forwardCommand($app); 116 break; 117 118 default: 119 $cmd = $this->ctrl->getCmd("show"); 120 $this->$cmd(); 121 $tpl->setContent($this->tpl->get()); 122 break; 123 } 124 return true; 125 } 126 127 /** 128 * fill data section 129 * 130 * @access protected 131 * 132 */ 133 protected function show() 134 { 135 /** 136 * @var ILIAS\DI\Container $DIC 137 */ 138 global $DIC; 139 140 $ui_factory = $DIC->ui()->factory(); 141 $renderer = $DIC->ui()->renderer(); 142 143 $lng = $this->lng; 144 $ilUser = $this->user; 145 146 147 // config 148 $raster = 15; 149 if ($this->user_settings->getDayStart()) { 150 // push starting point to last "slot" of hour BEFORE morning aggregation 151 $morning_aggr = ($this->user_settings->getDayStart() - 1) * 60 + (60 - $raster); 152 } else { 153 $morning_aggr = 0; 154 } 155 $evening_aggr = $this->user_settings->getDayEnd() * 60; 156 157 158 $this->tpl = new ilTemplate('tpl.day_view.html', true, true, 'Services/Calendar'); 159 160 include_once('./Services/YUI/classes/class.ilYuiUtil.php'); 161 ilYuiUtil::initDragDrop(); 162 163 if (isset($_GET["bkid"])) { 164 $user_id = $_GET["bkid"]; 165 $no_add = true; 166 } elseif ($ilUser->getId() == ANONYMOUS_USER_ID) { 167 $user_id = $ilUser->getId(); 168 $no_add = true; 169 } else { 170 $user_id = $ilUser->getId(); 171 $no_add = false; 172 } 173 include_once('Services/Calendar/classes/class.ilCalendarSchedule.php'); 174 $this->scheduler = new ilCalendarSchedule($this->seed, ilCalendarSchedule::TYPE_DAY, $user_id); 175 $this->scheduler->addSubitemCalendars(true); 176 $this->scheduler->calculate(); 177 $daily_apps = $this->scheduler->getByDay($this->seed, $this->timezone); 178 179 //display the download files button. 180 if (count($daily_apps)) { 181 $this->view_with_appointments = true; 182 } 183 184 $hours = $this->parseInfoIntoRaster( 185 $daily_apps, 186 $morning_aggr, 187 $evening_aggr, 188 $raster 189 ); 190 191 $colspan = $this->calculateColspan($hours); 192 193 $navigation = new ilCalendarHeaderNavigationGUI($this, $this->seed, ilDateTime::DAY); 194 $this->ctrl->setParameterByClass('ilcalendarappointmentgui', 'seed', $this->seed->get(IL_CAL_DATE)); 195 196 // add milestone link 197 include_once('Services/Calendar/classes/class.ilCalendarSettings.php'); 198 $settings = ilCalendarSettings::_getInstance(); 199 200 if (!$no_add) { 201 $this->ctrl->setParameterByClass('ilcalendarappointmentgui', 'seed', $this->seed->get(IL_CAL_DATE)); 202 $this->ctrl->setParameterByClass('ilcalendarappointmentgui', 'idate', $this->seed->get(IL_CAL_DATE)); 203 $new_app_url = $this->ctrl->getLinkTargetByClass('ilcalendarappointmentgui', 'add'); 204 205 if ($settings->getEnableGroupMilestones()) { 206 $this->ctrl->setParameterByClass('ilcalendarappointmentgui', 'seed', $this->seed->get(IL_CAL_DATE)); 207 $this->ctrl->setParameterByClass('ilcalendarappointmentgui', 'idate', $this->seed->get(IL_CAL_DATE)); 208 $new_ms_url = $this->ctrl->getLinkTargetByClass('ilcalendarappointmentgui', 'addMilestone'); 209 210 $this->tpl->setCurrentBlock("new_ms"); 211 $this->tpl->setVariable('DD_ID', $this->seed->get(IL_CAL_UNIX)); 212 $this->tpl->setVariable('DD_TRIGGER', $renderer->render($ui_factory->glyph()->add())); 213 $this->tpl->setVariable('URL_DD_NEW_APP', $new_app_url); 214 $this->tpl->setVariable('TXT_DD_NEW_APP', $this->lng->txt('cal_new_app')); 215 $this->tpl->setVariable('URL_DD_NEW_MS', $new_ms_url); 216 $this->tpl->setVariable('TXT_DD_NEW_MS', $this->lng->txt('cal_new_ms')); 217 $this->tpl->parseCurrentBlock(); 218 } else { 219 $this->tpl->setCurrentBlock("new_app1"); 220 $this->tpl->setVariable('H_NEW_APP_GLYPH', $renderer->render($ui_factory->glyph()->add($new_app_url))); 221 $this->tpl->parseCurrentBlock(); 222 } 223 224 $this->ctrl->clearParametersByClass('ilcalendarappointmentgui'); 225 } 226 227 $this->tpl->setVariable('NAVIGATION', $navigation->getHTML()); 228 229 $this->tpl->setVariable('HEADER_DATE', $this->seed_info['mday'] . ' ' . ilCalendarUtil::_numericMonthToString($this->seed_info['mon'], false)); 230 $this->tpl->setVariable('HEADER_DAY', ilCalendarUtil::_numericDayToString($this->seed_info['wday'], true)); 231 $this->tpl->setVariable('HCOLSPAN', $colspan - 1); 232 233 $this->tpl->setVariable('TXT_TIME', $lng->txt("time")); 234 235 // show fullday events 236 foreach ($daily_apps as $event) { 237 if ($event['fullday']) { 238 $this->showFulldayAppointment($event); 239 } 240 } 241 $this->tpl->setCurrentBlock('fullday_apps'); 242 $this->tpl->setVariable('TXT_F_DAY', $lng->txt("cal_all_day")); 243 $this->tpl->setVariable('COLSPAN', $colspan - 1); 244 $this->tpl->parseCurrentBlock(); 245 246 // parse the hour rows 247 foreach ($hours as $numeric => $hour) { 248 if (!($numeric % 60) || ($numeric == $morning_aggr && $morning_aggr) || 249 ($numeric == $evening_aggr && $evening_aggr)) { 250 if (!$no_add) { 251 $this->tpl->setCurrentBlock("new_app2"); 252 $this->ctrl->clearParametersByClass('ilcalendarappointmentgui'); 253 $this->ctrl->setParameterByClass('ilcalendarappointmentgui', 'seed', $this->seed->get(IL_CAL_DATE)); 254 $this->ctrl->setParameterByClass('ilcalendarappointmentgui', 'idate', $this->seed->get(IL_CAL_DATE)); 255 $this->ctrl->setParameterByClass('ilcalendarappointmentgui', 'hour', floor($numeric / 60)); 256 $this->tpl->setVariable('NEW_APP_GLYPH', $renderer->render( 257 $ui_factory->glyph()->add( 258 $this->ctrl->getLinkTargetByClass('ilcalendarappointmentgui', 'add') 259 ) 260 )); 261 $this->tpl->parseCurrentBlock(); 262 } 263 264 // aggregation rows 265 if (($numeric == $morning_aggr && $morning_aggr) || 266 ($numeric == $evening_aggr && $evening_aggr)) { 267 $this->tpl->setVariable('TIME_ROWSPAN', 1); 268 } 269 // rastered hour 270 else { 271 $this->tpl->setVariable('TIME_ROWSPAN', 60 / $raster); 272 } 273 274 $this->tpl->setCurrentBlock('time_txt'); 275 276 $this->tpl->setVariable('TIME', $hour['txt']); 277 $this->tpl->parseCurrentBlock(); 278 } 279 280 foreach ($hour['apps_start'] as $app) { 281 $this->showAppointment($app); 282 } 283 284 if ($ilUser->prefs["screen_reader_optimization"]) { 285 // see #0022492 286 //$this->tpl->touchBlock('scrd_app_cell'); 287 } 288 289 for ($i = ($colspan - 1);$i > $hour['apps_num'];$i--) { 290 $this->tpl->setCurrentBlock('empty_cell'); 291 $this->tpl->setVariable('EMPTY_WIDTH', (100 / (int) ($colspan - 1)) . '%'); 292 293 // last "slot" of hour needs border 294 if ($numeric % 60 == 60 - $raster || 295 ($numeric == $morning_aggr && $morning_aggr) || 296 ($numeric == $evening_aggr && $evening_aggr)) { 297 $this->tpl->setVariable('EMPTY_STYLE', ' calempty_border'); 298 } 299 300 $this->tpl->parseCurrentBlock(); 301 } 302 303 $this->tpl->touchBlock('time_row'); 304 } 305 } 306 307 /** 308 * show fullday appointment 309 * 310 * @access protected 311 * @param array appointment 312 * @return 313 */ 314 protected function showFulldayAppointment($a_app) 315 { 316 $f = $this->ui_factory; 317 $r = $this->ui_renderer; 318 319 $event_tpl = new ilTemplate('tpl.day_event_view.html', true, true, 'Services/Calendar'); 320 321 // milestone icon 322 if ($a_app['event']->isMilestone()) { 323 $event_tpl->setCurrentBlock('fullday_ms_icon'); 324 $event_tpl->setVariable('ALT_FD_MS', $this->lng->txt("cal_milestone")); 325 $event_tpl->setVariable('SRC_FD_MS', ilUtil::getImagePath("icon_ms.svg")); 326 $event_tpl->parseCurrentBlock(); 327 } 328 329 $event_tpl->setCurrentBlock('fullday_app'); 330 331 $compl = ($a_app['event']->isMilestone() && $a_app['event']->getCompletion() > 0) 332 ? " (" . $a_app['event']->getCompletion() . "%)" 333 : ""; 334 335 $shy = $this->getAppointmentShyButton($a_app['event'], $a_app['dstart'], ""); 336 337 //$title = ($new_title = $this->getContentByPlugins($a_app['event'], $a_app['dstart'], $shy))? $new_title : $shy; 338 339 $content = $shy . $compl; 340 341 $event_tpl->setVariable('EVENT_CONTENT', $content); 342 343 $color = $this->app_colors->getColorByAppointment($a_app['event']->getEntryId()); 344 $event_tpl->setVariable('F_APP_BGCOLOR', $color); 345 $event_tpl->setVariable('F_APP_FONTCOLOR', ilCalendarUtil::calculateFontColor($color)); 346 347 $this->ctrl->clearParametersByClass('ilcalendarappointmentgui'); 348 $this->ctrl->setParameterByClass('ilcalendarappointmentgui', 'seed', $this->seed->get(IL_CAL_DATE)); 349 $this->ctrl->setParameterByClass('ilcalendarappointmentgui', 'app_id', $a_app['event']->getEntryId()); 350 $event_tpl->setVariable('F_APP_EDIT_LINK', $this->ctrl->getLinkTargetByClass('ilcalendarappointmentgui', 'edit')); 351 352 if ($event_html_by_plugin = $this->getContentByPlugins($a_app['event'], $a_app['dstart'], $content, $event_tpl)) { 353 $body_html = $event_html_by_plugin; 354 } else { 355 $event_tpl->parseCurrentBlock(); 356 $body_html = $event_tpl->get(); 357 } 358 359 $this->tpl->setCurrentBlock("content_fd"); 360 $this->tpl->setVariable("CONTENT_EVENT", $body_html); 361 $this->tpl->parseCurrentBlock(); 362 363 $this->num_appointments++; 364 } 365 366 /** 367 * show appointment 368 * 369 * @access protected 370 * @param array appointment 371 */ 372 protected function showAppointment($a_app) 373 { 374 $ilUser = $this->user; 375 376 $event_tpl = new ilTemplate('tpl.day_event_view.html', true, true, 'Services/Calendar'); 377 378 if (!$ilUser->prefs["screen_reader_optimization"]) { 379 $event_tpl->setCurrentBlock('app'); 380 } else { 381 $event_tpl->setCurrentBlock('scrd_app'); 382 } 383 384 $this->tpl->setVariable('APP_ROWSPAN', $a_app['rowspan']); 385 //$event_tpl->setVariable('APP_TITLE',$a_app['event']->getPresentationTitle(false)); 386 387 switch ($this->user_settings->getTimeFormat()) { 388 case ilCalendarSettings::TIME_FORMAT_24: 389 $time = $a_app['event']->getStart()->get(IL_CAL_FKT_DATE, 'H:i', $this->timezone); 390 break; 391 392 case ilCalendarSettings::TIME_FORMAT_12: 393 $time = $a_app['event']->getStart()->get(IL_CAL_FKT_DATE, 'h:ia', $this->timezone); 394 break; 395 } 396 397 // add end time for screen readers 398 if ($ilUser->prefs["screen_reader_optimization"]) { 399 switch ($this->user_settings->getTimeFormat()) { 400 case ilCalendarSettings::TIME_FORMAT_24: 401 $time .= "-" . $a_app['event']->getEnd()->get(IL_CAL_FKT_DATE, 'H:i', $this->timezone); 402 break; 403 404 case ilCalendarSettings::TIME_FORMAT_12: 405 $time .= "-" . $a_app['event']->getEnd()->get(IL_CAL_FKT_DATE, 'h:ia', $this->timezone); 406 break; 407 } 408 } 409 410 $shy = $this->getAppointmentShyButton($a_app['event'], $a_app['dstart'], ""); 411 412 $title = $shy; 413 $content = ($time != "")? $time . " " . $title : $title; 414 415 $event_tpl->setVariable('EVENT_CONTENT', $content); 416 417 $color = $this->app_colors->getColorByAppointment($a_app['event']->getEntryId()); 418 $event_tpl->setVariable('APP_BGCOLOR', $color); 419 //$this->tpl->setVariable('APP_BGCOLOR',$color); 420 $event_tpl->setVariable('APP_COLOR', ilCalendarUtil::calculateFontColor($color)); 421 //$this->tpl->setVariable('APP_COLOR',ilCalendarUtil::calculateFontColor($color)); 422 $event_tpl->setVariable('APP_ADD_STYLES', $a_app['event']->getPresentationStyle()); 423 //$this->tpl->setVariable('APP_ADD_STYLES',$a_app['event']->getPresentationStyle()); 424 425 $this->ctrl->clearParametersByClass('ilcalendarappointmentgui'); 426 $this->ctrl->setParameterByClass('ilcalendarappointmentgui', 'seed', $this->seed->get(IL_CAL_DATE)); 427 $this->ctrl->setParameterByClass('ilcalendarappointmentgui', 'app_id', $a_app['event']->getEntryId()); 428 $event_tpl->setVariable('APP_EDIT_LINK', $this->ctrl->getLinkTargetByClass('ilcalendarappointmentgui', 'edit')); 429 430 if ($event_html_by_plugin = $this->getContentByPlugins($a_app['event'], $a_app['dstart'], $content, $event_tpl)) { 431 $event_html = $event_html_by_plugin; 432 } else { 433 $event_tpl->parseCurrentBlock(); 434 $event_html = $event_tpl->get(); 435 } 436 437 $this->tpl->setCurrentBlock("event_nfd"); 438 $this->tpl->setVariable("CONTENT_EVENT_NFD", $event_html); 439 $this->tpl->parseCurrentBlock(); 440 441 $this->num_appointments++; 442 } 443 444 /** 445 * calculate overlapping hours 446 * 447 * @access protected 448 * @return array hours 449 */ 450 protected function parseInfoIntoRaster($daily_apps, $morning_aggr, $evening_aggr, $raster) 451 { 452 $ilUser = $this->user; 453 454 $hours = array(); 455 for ($i = $morning_aggr;$i <= $evening_aggr;$i += $raster) { 456 $hours[$i]['apps_start'] = array(); 457 $hours[$i]['apps_num'] = 0; 458 459 switch ($this->user_settings->getTimeFormat()) { 460 case ilCalendarSettings::TIME_FORMAT_24: 461 if ($morning_aggr > 0 && $i == $morning_aggr) { 462 $hours[$i]['txt'] = sprintf('%02d:00', 0) . ' - ' . 463 sprintf('%02d:00', ceil(($i + 1) / 60)); 464 } else { 465 $hours[$i]['txt'] .= sprintf('%02d:%02d', floor($i / 60), $i % 60); 466 } 467 if ($evening_aggr < 23 * 60 && $i == $evening_aggr) { 468 $hours[$i]['txt'] .= ' - ' . sprintf('%02d:00', 0); 469 } 470 break; 471 472 case ilCalendarSettings::TIME_FORMAT_12: 473 474 $this->logger->notice('Morning: ' . $morning_aggr . ' and $i:' . $i); 475 476 if ($morning_aggr > 0 && $i == $morning_aggr) { 477 $hours[$i]['txt'] = 478 date('h a', mktime(0, 0, 0, 1, 1, 2000)) . ' - ' . 479 date('h a', mktime($this->user_settings->getDayStart(), 0, 0, 1, 1, 2000)); 480 } else { 481 $hours[$i]['txt'] = date('h a', mktime(floor($i / 60), $i % 60, 0, 1, 1, 2000)); 482 } 483 if ($evening_aggr < 23 * 60 && $i == $evening_aggr) { 484 $hours[$i]['txt'] .= ' - ' . date('h a', mktime(0, 0, 0, 1, 1, 2000)); 485 } 486 break; 487 } 488 } 489 490 491 foreach ($daily_apps as $app) { 492 // fullday appointment are not relavant 493 if ($app['fullday']) { 494 continue; 495 } 496 // start hour for this day 497 #21132 #21636 498 if ($app['start_info']['mday'] != $this->seed_info['mday']) { 499 $start = 0; 500 } else { 501 $start = $app['start_info']['hours'] * 60 + $app['start_info']['minutes']; 502 } 503 #21636 504 //$start = $app['start_info']['hours']*60+$app['start_info']['minutes']; 505 506 // end hour for this day 507 #21132 508 if ($app['end_info']['mday'] != $this->seed_info['mday']) { 509 $end = 23 * 60; 510 } elseif ($app['start_info']['hours'] == $app['end_info']['hours']) { 511 $end = $start + $raster; 512 } else { 513 $end = $app['end_info']['hours'] * 60 + $app['end_info']['minutes']; 514 } 515 //$end = $app['end_info']['hours']*60+$app['end_info']['minutes']; 516 517 // set end to next hour for screen readers 518 if ($ilUser->prefs["screen_reader_optimization"]) { 519 $end = $start + $raster; 520 } 521 522 if ($start < $morning_aggr) { 523 $start = $morning_aggr; 524 } 525 if ($end <= $morning_aggr) { 526 $end = $morning_aggr + $raster; 527 } 528 if ($start > $evening_aggr) { 529 $start = $evening_aggr; 530 } 531 if ($end > $evening_aggr + $raster) { 532 $end = $evening_aggr + $raster; 533 } 534 if ($end <= $start) { 535 $end = $start + $raster; 536 } 537 538 // map start and end to raster 539 $start = floor($start / $raster) * $raster; 540 $end = ceil($end / $raster) * $raster; 541 542 $first = true; 543 for ($i = $start;$i < $end;$i += $raster) { 544 if ($first) { 545 if (!$ilUser->prefs["screen_reader_optimization"]) { 546 $app['rowspan'] = ceil(($end - $start) / $raster); 547 } else { // screen readers get always a rowspan of 1 548 $app['rowspan'] = 1; 549 } 550 $hours[$i]['apps_start'][] = $app; 551 $first = false; 552 } 553 $hours[$i]['apps_num']++; 554 } 555 } 556 557 return $hours; 558 } 559 560 /** 561 * calculate colspan 562 * 563 * @access protected 564 * @param 565 * @return 566 */ 567 protected function calculateColspan($hours) 568 { 569 $ilUser = $this->user; 570 571 572 $colspan = 1; 573 foreach ($hours as $hour) { 574 $colspan = max($colspan, $hour['apps_num'] + 1); 575 } 576 577 // screen reader: always two cols (time and event col) 578 if ($ilUser->prefs["screen_reader_optimization"]) { 579 $colspan = 2; 580 } 581 582 return max($colspan, 2); 583 } 584} 585