1<?php 2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */ 3require_once("./Services/UIComponent/Explorer2/classes/class.ilTreeExplorerGUI.php"); 4require_once("./Services/UIComponent/AdvancedSelectionList/classes/class.ilAdvancedSelectionListGUI.php"); 5require_once("./Services/UIComponent/Glyph/classes/class.ilGlyphGUI.php"); 6require_once("./Services/UIComponent/Button/classes/class.ilLinkButton.php"); 7require_once("./Modules/StudyProgramme/classes/class.ilObjStudyProgrammeSettingsGUI.php"); 8/** 9 * Class ilStudyProgrammeTreeGUI 10 * ilObjStudyProgrammeTreeExplorerGUI generates the tree output for StudyProgrammes 11 * This class builds the tree with drag & drop functionality and some additional buttons which triggers bootstrap-modals 12 * 13 * @author Michael Herren <mh@studer-raimann.ch> 14 * @version 1.0.0 15 */ 16class ilObjStudyProgrammeTreeExplorerGUI extends ilExplorerBaseGUI 17{ 18 protected $js_study_programme_path = "./Modules/StudyProgramme/templates/js/ilStudyProgramme.js"; 19 protected $css_study_programme_path = "./Modules/StudyProgramme/templates/css/ilStudyProgrammeTree.css"; 20 21 /** 22 * @var array 23 */ 24 //protected $stay_with_command = array( "", "render", "view", "infoScreen", "performPaste", "cut", "tree_view"); 25 26 /** 27 * @var int 28 */ 29 protected $tree_root_id; 30 31 /** 32 * @var ilAccessHandler 33 */ 34 protected $access; 35 /** 36 * @var ilLanguage 37 */ 38 protected $lng; 39 40 /** 41 * @var ilTemplate 42 */ 43 protected $tpl; 44 45 /** 46 * @var ilToolbarGUI 47 */ 48 protected $toolbar; 49 50 /** 51 * @var ilCtrl 52 */ 53 protected $ctrl; 54 55 /** 56 * @var string css-id of the bootstrap modal dialog 57 */ 58 protected $modal_id; 59 60 /** 61 * @var array js configuration for the tree 62 */ 63 protected $js_conf; 64 65 /** 66 * default classes of the tree [key=>class_name] 67 * @var array 68 */ 69 protected $class_configuration = array( 70 'node' => array( 71 'node_title' => 'title', 72 'node_point' => 'points', 73 'node_current' => 'ilHighlighted current_node', 74 'node_buttons' => 'tree_button' 75 ), 76 'lp_object' => 'lp-object', 77 ); 78 79 protected $node_template; 80 81 /** 82 * @param $a_expl_id 83 * @param $a_parent_obj 84 * @param $a_parent_cmd 85 * @param $a_tree 86 */ 87 public function __construct($a_tree_root_id, $modal_id, $a_expl_id, $a_parent_obj, $a_parent_cmd) 88 { 89 global $DIC; 90 $ilAccess = $DIC['ilAccess']; 91 $lng = $DIC['lng']; 92 $tpl = $DIC['tpl']; 93 $ilToolbar = $DIC['ilToolbar']; 94 $ilCtrl = $DIC['ilCtrl']; 95 96 parent::__construct($a_expl_id, $a_parent_obj, $a_parent_cmd); 97 98 $this->tree_root_id = $a_tree_root_id; 99 100 $this->access = $ilAccess; 101 $this->lng = $lng; 102 $this->tpl = $tpl; 103 $this->toolbar = $ilToolbar; 104 $this->ctrl = $ilCtrl; 105 $this->modal_id = $modal_id; 106 $this->js_conf = array(); 107 108 $lng->loadLanguageModule("prg"); 109 110 $this->setAjax(true); 111 112 if ($this->checkAccess('write', $a_tree_root_id)) { 113 $this->setEnableDnd(true); 114 } 115 } 116 117 118 /** 119 * Return node element 120 * 121 * @param ilObjStudyProgramme|ilObject $node 122 * 123 * @return string 124 */ 125 public function getNodeContent($node) 126 { 127 global $DIC; 128 $lng = $DIC['lng']; 129 $ilAccess = $DIC['ilAccess']; 130 131 $current_ref_id = (isset($_GET["ref_id"]))? $_GET["ref_id"] : -1; 132 133 $is_current_node = ($node->getRefId() == $current_ref_id); 134 $is_study_programme = ($node instanceof ilObjStudyProgramme); 135 $is_root_node = ($is_study_programme && $node->getRoot() == null); 136 137 // show delete only on not current elements and not root 138 $is_delete_enabled = ($is_study_programme && ($is_current_node || $is_root_node))? false : $this->checkAccess("delete", $current_ref_id); 139 140 $is_creation_enabled = ($this->checkAccess("create", $current_ref_id)); 141 142 $node_config = array( 143 'current_ref_id' => $current_ref_id, 144 'is_current_node' => $is_current_node, 145 'is_delete_enabled' => $is_delete_enabled, 146 'is_creation_enabled' => $is_creation_enabled, 147 'is_study_programme' => $is_study_programme, 148 'is_root_node' => $is_root_node 149 ); 150 151 // TODO: find way to remove a-tag around the content, to create valid html 152 $tpl = $this->getNodeTemplateInstance(); 153 154 // add the tree buttons 155 if ($this->checkAccess('write', $node->getRefId())) { 156 if ($is_study_programme) { 157 $this->parseStudyProgrammeNodeButtons($node, $node_config, $tpl); 158 } else { 159 $this->parseLeafNodeButtons($node, $node_config, $tpl); 160 } 161 } 162 163 $tpl->setCurrentBlock('node-content-block'); 164 $tpl->setVariable('NODE_TITLE_CLASSES', implode(' ', $this->getNodeTitleClasses($node_config))); 165 $tpl->setVariable('NODE_TITLE', $node->getTitle()); 166 167 if ($is_study_programme) { 168 $tpl->setVariable('NODE_POINT_CLASSES', $this->class_configuration['node']['node_point']); 169 $tpl->setVariable('NODE_POINTS', $this->formatPointValue($node->getPoints())); 170 } 171 172 $tpl->parseCurrentBlock('node-content-block'); 173 174 return $tpl->get(); 175 } 176 177 /** 178 * Returns array with all css classes of the title node element 179 * 180 * @param array $node_config 181 * 182 * @return array 183 */ 184 protected function getNodeTitleClasses($node_config) 185 { 186 $node_title_classes = array($this->class_configuration['node']['node_title']); 187 if ($node_config['is_study_programme']) { 188 if ($node_config['is_current_node']) { 189 array_push($node_title_classes, $this->class_configuration['node']['node_current']); 190 } 191 } else { 192 array_push($node_title_classes, $this->class_configuration['lp_object']); 193 } 194 195 return $node_title_classes; 196 } 197 198 199 /** 200 * Generates the buttons for a study-programme node 201 * 202 * @param ilObjStudyProgramme $node parsed node 203 * @param array $node_config configuration of current node 204 * @param ilTemplate $tpl current node template 205 */ 206 protected function parseStudyProgrammeNodeButtons($node, $node_config, $tpl) 207 { 208 $tpl->setCurrentBlock('enable-tree-buttons'); 209 210 // show info button only when it not the current node 211 $info_button = $this->getNodeButtonActionLink('ilObjStudyProgrammeSettingsGUI', 'view', array('ref_id' => $node->getRefId(), 'currentNode' => $node_config['is_current_node']), ilGlyphGUI::get(ilGlyphGUI::INFO)); 212 $tpl->setVariable('NODE_INFO_BUTTON', $info_button); 213 214 // only show add button when create permission is set 215 if ($node_config['is_creation_enabled']) { 216 $create_button = $this->getNodeButtonActionLink('ilObjStudyProgrammeTreeGUI', 'create', array('ref_id' => $node->getRefId()), ilGlyphGUI::get(ilGlyphGUI::ADD)); 217 $tpl->setVariable('NODE_CREATE_BUTTON', $create_button); 218 } 219 220 // only show delete button when its not the current node, not the root-node and delete permissions are set 221 if ($node_config['is_delete_enabled']) { 222 $delete_button = $this->getNodeButtonActionLink('ilObjStudyProgrammeTreeGUI', 'delete', array('ref_id' => $node->getRefId(), 'item_ref_id' => $node_config['current_ref_id']), ilGlyphGUI::get(ilGlyphGUI::REMOVE)); 223 $tpl->setVariable('NODE_DELETE_BUTTON', $delete_button); 224 } 225 226 $tpl->parseCurrentBlock('enable-tree-buttons'); 227 } 228 229 /** 230 * Generates the buttons for a study programme leaf 231 * 232 * @param ilObject $node parsed node 233 * @param array $node_config configuration of current node 234 * @param ilTemplate $tpl current node template 235 */ 236 protected function parseLeafNodeButtons($node, $node_config, $tpl) 237 { 238 $tpl->setCurrentBlock('enable-tree-buttons'); 239 240 // only show delete button when its not the current node 241 if ($node_config['is_delete_enabled']) { 242 $delete_button = $this->getNodeButtonActionLink('ilObjStudyProgrammeTreeGUI', 'delete', array('ref_id' => $node->getRefId(), 'item_ref_id' => $node_config['current_ref_id']), ilGlyphGUI::get(ilGlyphGUI::REMOVE)); 243 $tpl->setVariable('NODE_DELETE_BUTTON', $delete_button); 244 } 245 246 $tpl->parseCurrentBlock('enable-tree-buttons'); 247 } 248 249 /** 250 * Factory method for a new instance of a node template 251 * 252 * @return ilTemplate 253 */ 254 protected function getNodeTemplateInstance() 255 { 256 return new ilTemplate("tpl.tree_node_content.html", true, true, "Modules/StudyProgramme"); 257 } 258 259 /** 260 * Returns formatted point value 261 * 262 * @param $points 263 * 264 * @return string 265 */ 266 protected function formatPointValue($points) 267 { 268 return '(' . $points . " " . $this->lng->txt('prg_points') . ')'; 269 } 270 271 /** 272 * Generate link-element 273 * 274 * @param $target_class 275 * @param $cmd 276 * @param $params url-params send to the 277 * @param $content 278 * @param bool $async 279 * 280 * @return string 281 */ 282 protected function getNodeButtonActionLink($target_class, $cmd, $params, $content, $async = true) 283 { 284 foreach ($params as $param_name => $param_value) { 285 $this->ctrl->setParameterByClass($target_class, $param_name, $param_value); 286 } 287 288 $tpl = $this->getNodeTemplateInstance(); 289 //$tpl->free(); 290 $tpl->setCurrentBlock('tree-button-block'); 291 292 $classes = array($this->class_configuration['node']['node_buttons']); 293 $classes[] = 'cmd_' . $cmd; 294 295 $tpl->setVariable('LINK_HREF', $this->ctrl->getLinkTargetByClass($target_class, $cmd, '', true, false)); 296 $tpl->setVariable('LINK_CLASSES', implode(' ', $classes)); 297 298 if ($async) { 299 $tpl->touchBlock('enable-async-link'); 300 $tpl->setVariable('LINK_DATA_TARGET', '#' . $this->modal_id); 301 } 302 303 $tpl->setVariable('LINK_CONTENT', $content); 304 305 //$tpl->parseCurrentBlock('tree-button-block'); 306 307 return $tpl->get(); 308 } 309 310 /** 311 * Return root node of tree 312 * 313 * @return mixed 314 */ 315 public function getRootNode() 316 { 317 $node = ilObjStudyProgramme::getInstanceByRefId($this->tree_root_id); 318 if ($node->getRoot() != null) { 319 return $node->getRoot(); 320 } 321 return $node; 322 } 323 324 /** 325 * Get node icon 326 * Return custom icon of OrgUnit type if existing 327 * 328 * @param array $a_node 329 * 330 * @return string 331 */ 332 public function getNodeIcon($a_node) 333 { 334 global $DIC; 335 $ilias = $DIC['ilias']; 336 337 $obj_id = ilObject::_lookupObjId($a_node->getRefId()); 338 if ($ilias->getSetting('custom_icons')) { 339 //TODO: implement custom icon functionality 340 } 341 342 return ilObject::_getIcon($obj_id, "tiny"); 343 } 344 345 346 /** 347 * Returns node link target 348 * 349 * @param mixed $node 350 * 351 * @return string 352 */ 353 public function getNodeHref($node) 354 { 355 global $DIC; 356 $ilCtrl = $DIC['ilCtrl']; 357 358 if ($ilCtrl->getCmd() == "performPaste") { 359 $ilCtrl->setParameterByClass("ilObjStudyProgrammeGUI", "target_node", $node->getRefId()); 360 } 361 362 $ilCtrl->setParameterByClass("ilObjStudyProgrammeGUI", "ref_id", $node->getRefId()); 363 364 return '#'; 365 } 366 367 /** 368 * Get childs of node 369 * 370 * @param $a_parent_node_id 371 * 372 * @global ilAccess 373 * @internal param int $a_parent_id parent id 374 * @return array childs 375 */ 376 public function getChildsOfNode($a_parent_node_id) 377 { 378 global $DIC; 379 $ilAccess = $DIC['ilAccess']; 380 381 $parent_obj = ilObjectFactoryWrapper::singleton()->getInstanceByRefId($a_parent_node_id); 382 383 $children_with_permission = array(); 384 385 // its currently only possible to have children on StudyProgrammes 386 if ($parent_obj instanceof ilObjStudyProgramme) { 387 $children = ($parent_obj->hasChildren())? $parent_obj->getChildren() : $parent_obj->getLPChildren(); 388 389 if (is_array($children)) { 390 foreach ($children as $node) { 391 if ($this->checkAccess('visible', $node->getRefId())) { 392 $children_with_permission[] = $node; 393 } 394 } 395 } 396 } 397 398 return $children_with_permission; 399 } 400 401 /** 402 * Is node clickable? 403 * 404 * @param mixed $a_node node object/array 405 * 406 * @global ilAccessHandler $ilAccess 407 * @return boolean node clickable true/false 408 */ 409 public function isNodeClickable($a_node) 410 { 411 return true; 412 } 413 414 415 /** 416 * Get id of a node 417 * 418 * @param mixed $a_node node array or object 419 * 420 * @return string id of node 421 */ 422 public function getNodeId($a_node) 423 { 424 if (!is_null($a_node)) { 425 return $a_node->getRefId(); 426 } 427 return null; 428 } 429 430 /** 431 * List item start 432 * 433 * @param 434 * @return 435 */ 436 public function listItemStart($tpl, $a_node) 437 { 438 $tpl->setCurrentBlock("list_item_start"); 439 440 if ($this->getAjax() && $this->nodeHasVisibleChilds($a_node) || ($a_node instanceof ilStudyProgramme && $a_node->getParent() === null)) { 441 $tpl->touchBlock("li_closed"); 442 } 443 $tpl->setVariable( 444 "DOM_NODE_ID", 445 $this->getDomNodeIdForNodeId($this->getNodeId($a_node)) 446 ); 447 $tpl->parseCurrentBlock(); 448 $tpl->touchBlock("tag"); 449 } 450 451 452 /** 453 * Returns the output of the complete tree 454 * There are added some additional javascripts before output the parent::getHTML() 455 * 456 * @return string 457 */ 458 public function getHTML() 459 { 460 $this->tpl->addJavascript($this->js_study_programme_path); 461 $this->tpl->addCss($this->css_study_programme_path); 462 463 $this->tpl->addOnLoadCode('$("#' . $this->getContainerId() . '").study_programme_tree(' . json_encode($this->js_conf) . ');'); 464 465 return parent::getHTML(); 466 } 467 468 469 /** 470 * Closes certain node in the tree session 471 * The open nodes of a tree are stored in a session. This function closes a certain node by its id. 472 * 473 * @param int $node_id 474 */ 475 public function closeCertainNode($node_id) 476 { 477 if (in_array($node_id, $this->open_nodes)) { 478 $k = array_search($node_id, $this->open_nodes); 479 unset($this->open_nodes[$k]); 480 } 481 $this->store->set("on_" . $this->id, serialize($this->open_nodes)); 482 } 483 484 /** 485 * Open certain node in the tree session 486 * The open nodes of a tree are stored in a session. This function opens a certain node by its id. 487 * 488 * @param int $node_id 489 */ 490 public function openCertainNode($node_id) 491 { 492 $id = $this->getNodeIdForDomNodeId($node_id); 493 if (!in_array($id, $this->open_nodes)) { 494 $this->open_nodes[] = $id; 495 } 496 $this->store->set("on_" . $this->id, serialize($this->open_nodes)); 497 } 498 499 500 /** 501 * Checks permission of current tree or certain child of it 502 * 503 * @param string $permission 504 * @param null $ref_id 505 * 506 * @return bool 507 */ 508 protected function checkAccess($permission, $ref_id) 509 { 510 $checker = $this->access->checkAccess($permission, '', $ref_id); 511 512 return $checker; 513 } 514 515 516 /** 517 * Checks permission of a object and throws an exception if they are not granted 518 * 519 * @param string $permission 520 * @param null $ref_id 521 * 522 * @throws ilException 523 */ 524 protected function checkAccessOrFail($permission, $ref_id) 525 { 526 if (!$this->checkAccess($permission, $ref_id)) { 527 throw new ilException("You have no permission for " . $permission . " Object with ref_id " . $ref_id . "!"); 528 } 529 } 530 531 /** 532 * Adds configuration to the study-programme-tree jquery plugin 533 * 534 * @param array $js_conf 535 */ 536 public function addJsConf($key, $value) 537 { 538 $this->js_conf[$key] = $value; 539 } 540 541 /** 542 * Returns setting of the study-programme-tree 543 * 544 * @param array $js_conf 545 */ 546 public function getJsConf($key) 547 { 548 return $this->js_conf[$key]; 549 } 550} 551