2 /************************************************************************/
4 /************************************************************************/
5 /* Copyright (c) 2010 */
6 /* Inclusive Design Institute */
8 /* This program is free software. You can redistribute it and/or */
9 /* modify it under the terms of the GNU General Public License */
10 /* as published by the Free Software Foundation. */
11 /************************************************************************/
13 if (!defined('TR_INCLUDE_PATH')) exit;
15 require_once(TR_INCLUDE_PATH. 'classes/DAO/DAO.class.php');
16 require_once(TR_INCLUDE_PATH. 'classes/DAO/ContentDAO.class.php');
17 require_once(TR_INCLUDE_PATH. 'classes/Utility.class.php');
44 function ContentManager($course_id) {
45 if (!($course_id > 0)) {
48 $this->course_id = $course_id;
49 $this->dao = new DAO();
50 $this->contentDAO = new ContentDAO();
52 /* x could be the ordering or even the content_id */
53 /* don't really need the ordering anyway. */
54 /* $_menu[content_parent_id][x] = array('content_id', 'ordering', 'title') */
57 /* number of content sections */
61 $_menu_info = array();
63 // $sql = "SELECT content_id, content_parent_id, ordering, title, UNIX_TIMESTAMP(release_date) AS u_release_date, content_type
64 // FROM ".TABLE_PREFIX."content
65 // WHERE course_id=$this->course_id
66 // ORDER BY content_parent_id, ordering";
67 // $result = mysql_query($sql, $this->db);
69 $rows = $this->contentDAO->getContentByCourseID($this->course_id);
71 if (is_array($rows)) {
72 foreach ($rows as $row) {
74 $_menu[$row['content_parent_id']][] = array('content_id'=> $row['content_id'],
75 'ordering' => $row['ordering'],
76 'title' => htmlspecialchars($row['title']),
77 'content_type' => $row['content_type']);
79 $_menu_info[$row['content_id']] = array('content_parent_id' => $row['content_parent_id'],
80 'title' => htmlspecialchars($row['title']),
81 'ordering' => $row['ordering'],
82 'content_type' => $row['content_type']);
85 * add test content asscioations
86 * find associations per content page, and add it as a sublink.
89 $test_rows = $this->getContentTestsAssoc($row['content_id']);
90 if (is_array($test_rows)) {
91 foreach ($test_rows as $test_row){
92 $_menu[$row['content_id']][] = array( 'test_id' => $test_row['test_id'],
93 'title' => htmlspecialchars($test_row['title']),
94 'content_type' => CONTENT_TYPE_CONTENT);
97 /* End of add test content asscioations */
99 if ($row['content_parent_id'] == 0) {
100 $max_depth[$row['content_id']] = 1;
102 $max_depth[$row['content_id']] = $max_depth[$row['content_parent_id']]+1;
107 $this->_menu = $_menu;
109 $this->_menu_info = $_menu_info;
111 $this->num_sections = $num_sections;
113 if (count($max_depth) > 1) {
114 $this->max_depth = max($max_depth);
116 $this->max_depth = 0;
119 // generate array of all the content ids in the same order that they appear in "content navigation"
120 if ($this->getNextContentID(0) > 0) {
121 $this->_menu_in_order[] = $next_content_id = $this->getNextContentID(0);
123 while ($next_content_id > 0)
125 $next_content_id = $this->getNextContentID($next_content_id);
127 if (in_array($next_content_id, $this->_menu_in_order)) break;
128 else if ($next_content_id > 0) $this->_menu_in_order[] = $next_content_id;
131 $this->content_length = count($_menu[0]);
134 // This function is called by initContent to construct $this->_menu_in_order, an array to
135 // holds all the content ids in the same order that they appear in "content navigation"
136 function getNextContentID($content_id, $order=0) {
137 // return first root content when $content_id is not given
139 return $this->_menu[0][0]['content_id'];
142 $myParent = $this->_menu_info[$content_id]['content_parent_id'];
143 $myOrder = $this->_menu_info[$content_id]['ordering'];
145 // calculate $myOrder, add in the number of tests in front of this content page
146 if (is_array($this->_menu[$myParent])) {
148 foreach ($this->_menu[$myParent] as $menuContent) {
149 if ($menuContent['content_id'] == $content_id) break;
150 if (isset($menuContent['test_id'])) $num_of_tests++;
153 $myOrder += $num_of_tests;
154 // end of calculating $myOrder
156 /* if this content has children, then take the first one. */
157 if ( isset($this->_menu[$content_id]) && is_array($this->_menu[$content_id]) && ($order==0) ) {
159 // if the child is a test, keep searching for the content id
160 foreach ($this->_menu[$content_id] as $menuID => $menuContent)
162 if (!empty($menuContent['test_id'])) continue;
165 $nextMenu = $this->_menu[$content_id][$menuID]['content_id'];
170 // all children are tests
171 if (!isset($nextMenu))
173 if (isset($this->_menu[$myParent][$myOrder]['content_id'])) {
175 return $this->_menu[$myParent][$myOrder]['content_id'];
178 $nextMenu = $this->getNextContentID($myParent, 1);
184 if (isset($this->_menu[$myParent][$myOrder]) && $this->_menu[$myParent][$myOrder] != '') {
186 return $this->_menu[$myParent][$myOrder]['content_id'];
188 /* No more siblings */
189 if ($myParent != 0) {
190 return $this->getNextContentID($myParent, 1);
196 function getContent($parent_id=-1, $length=-1) {
197 if ($parent_id == -1) {
198 $my_menu_copy = $this->_menu;
200 $my_menu_copy[0] = array_slice($my_menu_copy[0], 0, $length);
202 return $my_menu_copy;
204 return $this->_menu[$parent_id];
208 function &getContentPath($content_id) {
211 $path[] = array('content_id' => $content_id, 'title' => $this->_menu_info[$content_id]['title']);
213 $this->getContentPathRecursive($content_id, $path);
215 $path = array_reverse($path);
220 function getContentPathRecursive($content_id, &$path) {
221 $parent_id = $this->_menu_info[$content_id]['content_parent_id'];
223 if ($parent_id > 0) {
224 $path[] = array('content_id' => $parent_id, 'title' => $this->_menu_info[$parent_id]['title']);
225 $this->getContentPathRecursive($parent_id, $path);
229 function addContent($course_id, $content_parent_id, $ordering, $title, $text, $keywords,
230 $related, $formatting, $head = '', $use_customized_head = 0,
231 $test_message = '', $content_type = CONTENT_TYPE_CONTENT) {
232 global $_current_user, $_course_id;
234 if (!isset($_current_user) || !$_current_user->isAuthor($this->course_id)) {
238 // shift the new neighbouring content down
239 $sql = "UPDATE ".TABLE_PREFIX."content SET ordering=ordering+1
240 WHERE ordering>=$ordering
241 AND content_parent_id=$content_parent_id
242 AND course_id=$_course_id";
243 $this->contentDAO->execute($sql);
245 /* main topics all have minor_num = 0 */
246 $cid = $this->contentDAO->Create($_course_id, $content_parent_id, $ordering, 0, $formatting,
247 $keywords, '', $title, $text, $head, $use_customized_head,
248 $test_message, $content_type);
252 function editContent($content_id, $title, $text, $keywords, $formatting,
253 $head, $use_customized_head, $test_message) {
254 global $_current_user;
256 if (!isset($_current_user) || !$_current_user->isAuthor($this->course_id)) {
260 $this->contentDAO->Update($content_id, $title, $text, $keywords, $formatting, $head, $use_customized_head,
264 function moveContent($content_id, $new_content_parent_id, $new_content_ordering) {
265 global $msg, $_current_user, $_course_id;
267 if (!isset($_current_user) || !$_current_user->isAuthor($this->course_id)) {
271 /* first get the content to make sure it exists */
272 // $sql = "SELECT ordering, content_parent_id FROM ".TABLE_PREFIX."content WHERE content_id=$content_id AND course_id=$_SESSION[course_id]";
273 // $result = mysql_query($sql, $this->db);
274 if (!($row = $this->getContentPage($content_id)) ) {
277 $old_ordering = $row['ordering'];
278 $old_content_parent_id = $row['content_parent_id'];
280 $sql = "SELECT max(ordering) max_ordering FROM ".TABLE_PREFIX."content WHERE content_parent_id=$old_content_parent_id AND course_id=$_course_id";
281 // $result = mysql_query($sql, $this->db);
282 // $row = mysql_fetch_assoc($result);
283 $row = $this->contentDAO->execute($sql);
284 $max_ordering = $row[0]['max_ordering'];
286 if ($content_id == $new_content_parent_id) {
287 $msg->addError("NO_SELF_AS_PARENT");
291 if ($old_content_parent_id == $new_content_parent_id && $old_ordering == $new_content_ordering) {
292 $msg->addError("SAME_LOCATION");
296 $content_path = $this->getContentPath($new_content_parent_id);
297 foreach ($content_path as $parent){
298 if ($parent['content_id'] == $content_id) {
299 $msg->addError("NO_CHILD_AS_PARENT");
304 // if the new_content_ordering is greater than the maximum ordering of the parent content,
305 // set the $new_content_ordering to the maximum ordering. This happens when move the content
306 // to the last element under the same parent content.
307 if ($old_content_parent_id == $new_content_parent_id && $new_content_ordering > $max_ordering)
308 $new_content_ordering = $max_ordering;
309 if (($old_content_parent_id != $new_content_parent_id) || ($old_ordering != $new_content_ordering)) {
310 // remove the gap left by the moved content
311 $sql = "UPDATE ".TABLE_PREFIX."content
312 SET ordering=ordering-1
313 WHERE ordering>$old_ordering
314 AND content_parent_id=$old_content_parent_id
315 AND content_id<>$content_id
316 AND course_id=$_course_id";
317 // $result = mysql_query($sql, $this->db);
318 $this->contentDAO->execute($sql);
320 // shift the new neighbouring content down
321 $sql = "UPDATE ".TABLE_PREFIX."content
322 SET ordering=ordering+1
323 WHERE ordering>=$new_content_ordering
324 AND content_parent_id=$new_content_parent_id
325 AND content_id<>$content_id
326 AND course_id=$_course_id";
327 // $result = mysql_query($sql, $this->db);
328 $this->contentDAO->execute($sql);
330 $sql = "UPDATE ".TABLE_PREFIX."content
331 SET content_parent_id=$new_content_parent_id, ordering=$new_content_ordering
332 WHERE content_id=$content_id AND course_id=$_course_id";
333 // $result = mysql_query($sql, $this->db);
334 $this->contentDAO->execute($sql);
338 function deleteContent($content_id) {
339 global $_current_user, $_course_id;
341 if (!isset($_current_user) || !$_current_user->isAuthor($this->course_id)) {
345 /* check if exists */
346 // $sql = "SELECT ordering, content_parent_id FROM ".TABLE_PREFIX."content WHERE content_id=$content_id AND course_id=$_SESSION[course_id]";
347 // $result = mysql_query($sql, $this->db);
348 // if (!($row = @mysql_fetch_assoc($result)) ) {
349 if (!($row = $this->getContentPage($content_id)) ) {
352 $ordering = $row['ordering'];
353 $content_parent_id = $row['content_parent_id'];
355 /* check if this content has sub content */
356 $children = $this->_menu[$content_id];
358 if (is_array($children) && (count($children)>0) ) {
359 /* delete its children recursively first*/
360 foreach ($children as $x => $info) {
361 if ($info['content_id'] > 0) {
362 $this->deleteContentRecursive($info['content_id']);
367 $this->contentDAO->Delete($content_id);
369 /* re-order the rest of the content */
370 $sql = "UPDATE ".TABLE_PREFIX."content SET ordering=ordering-1 WHERE ordering>=$ordering AND content_parent_id=$content_parent_id AND course_id=$_course_id";
371 $this->contentDAO->execute($sql);
373 // unset last-visited content id
374 require_once(TR_INCLUDE_PATH.'classes/DAO/UserCoursesDAO.class.php');
375 $userCoursesDAO = new UserCoursesDAO();
376 $userCoursesDAO->UpdateLastCid($_SESSION['user_id'], $_course_id, 0);
378 unset($_SESSION['s_cid']);
379 unset($_SESSION['from_cid']);
381 /* delete this content page */
382 // $sql = "DELETE FROM ".TABLE_PREFIX."content WHERE content_id=$content_id AND course_id=$_SESSION[course_id]";
383 // $result = mysql_query($sql, $this->db);
385 /* delete this content from member tracking page */
386 // $sql = "DELETE FROM ".TABLE_PREFIX."member_track WHERE content_id=$content_id AND course_id=$_SESSION[course_id]";
387 // $result = mysql_query($sql, $this->db);
389 // $sql = "DELETE FROM ".TABLE_PREFIX."related_content WHERE content_id=$content_id OR related_content_id=$content_id";
390 // $result = mysql_query($sql, $this->db);
392 /* delete the content tests association */
393 // $sql = "DELETE FROM ".TABLE_PREFIX."content_tests_assoc WHERE content_id=$content_id";
394 // $result = mysql_query($sql, $this->db);
396 /* delete the content forum association */
397 // $sql = "DELETE FROM ".TABLE_PREFIX."content_forums_assoc WHERE content_id=$content_id";
398 // $result = mysql_query($sql, $this->db);
400 /* Delete all AccessForAll contents */
401 // require_once(TR_INCLUDE_PATH.'classes/A4a/A4a.class.php');
402 // $a4a = new A4a($content_id);
403 // $a4a->deleteA4a();
405 /* remove the "resume" to this page, b/c it was deleted */
406 // $sql = "UPDATE ".TABLE_PREFIX."course_enrollment SET last_cid=0 WHERE course_id=$_SESSION[course_id] AND last_cid=$content_id";
407 // $result = mysql_query($sql, $this->db);
413 /* private. call from deleteContent only. */
414 function deleteContentRecursive($content_id) {
415 /* check if this content has sub content */
416 $children = $this->_menu[$content_id];
418 if (is_array($children) && (count($children)>0) ) {
419 /* delete its children recursively first*/
420 foreach ($children as $x => $info) {
421 if ($info['content_id'] > 0) {
422 $this->deleteContent($info['content_id']);
427 // delete this content page
428 $this->contentDAO->Delete($content_id);
429 // $sql = "DELETE FROM ".TABLE_PREFIX."content WHERE content_id=$content_id AND course_id=$_SESSION[course_id]";
430 // $result = mysql_query($sql, $this->db);
432 /* delete this content from member tracking page */
433 // $sql = "DELETE FROM ".TABLE_PREFIX."member_track WHERE content_id=$content_id";
434 // $result = mysql_query($sql, $this->db);
436 /* delete the content tests association */
437 // $sql = "DELETE FROM ".TABLE_PREFIX."content_tests_assoc WHERE content_id=$content_id";
438 // $result = mysql_query($sql, $this->db);
441 function getContentPage($content_id) {
442 include_once(TR_INCLUDE_PATH.'classes/DAO/ContentDAO.class.php');
443 $contentDAO = new ContentDAO();
444 return $contentDAO->get($content_id);
448 * Return a list of tests associated with the selected content
449 * @param int the content id that all tests are associated with it.
450 * @return array list of tests
454 function & getContentTestsAssoc($content_id){
455 $sql = "SELECT ct.test_id, t.title
456 FROM (SELECT * FROM ".TABLE_PREFIX."content_tests_assoc
457 WHERE content_id=$content_id) AS ct
458 LEFT JOIN ".TABLE_PREFIX."tests t ON ct.test_id=t.test_id
460 return $this->dao->execute($sql);
463 function & cleanOutput($value) {
464 return stripslashes(htmlspecialchars($value));
468 /* @See include/html/editor_tabs/properties.inc.php */
470 function getNumSections() {
471 return $this->num_sections;
475 function getMaxDepth() {
476 return $this->max_depth;
480 function getContentLength() {
481 return $this->content_length;
484 /* @See include/html/dropdowns/local_menu.inc.php */
485 function getLocationPositions($parent_id, $content_id) {
486 $siblings = $this->getContent($parent_id);
487 for ($i=0;$i<count($siblings); $i++){
488 if ($siblings[$i]['content_id'] == $content_id) {
495 /* Access: Private */
496 function getNumbering($content_id) {
497 $path = $this->getContentPath($content_id);
500 foreach ($path as $page) {
501 $num = $this->getLocationPositions($parent, $page['content_id']) +1;
502 $parent = $page['content_id'];
503 $numbering .= $num.'.';
505 $numbering = substr($numbering, 0, -1);
510 function getPreviousContent($content_id) {
511 if (is_array($this->_menu_in_order))
513 foreach ($this->_menu_in_order as $content_location => $this_content_id)
515 if ($this_content_id == $content_id) break;
518 for ($i=$content_location-1; $i >= 0; $i--)
520 $content_type = $this->_menu_info[$this->_menu_in_order[$i]]['content_type'];
522 if ($content_type == CONTENT_TYPE_CONTENT || $content_type == CONTENT_TYPE_WEBLINK)
523 return array('content_id' => $this->_menu_in_order[$i],
524 'ordering' => $this->_menu_info[$this->_menu_in_order[$i]]['ordering'],
525 'title' => $this->_menu_info[$this->_menu_in_order[$i]]['title']);
532 * return the array of the next content node of the given $content_id
533 * when $content_id = 0 or is not set, return the first content node
535 * @return an array of the next content node
537 function getNextContent($content_id) {
538 if (is_array($this->_menu_in_order))
540 // find out the location of the $content_id
541 if (!$content_id) $content_location = 0; // the first content location when $content_id = 0 or is not set
544 foreach ($this->_menu_in_order as $content_location => $this_content_id)
546 if ($this_content_id == $content_id)
554 // the next content node must be at or after the $content_location
555 // and with the content type CONTENT or WEBLINK
556 for ($i=$content_location; $i < count($this->_menu_in_order); $i++)
558 $content_type = $this->_menu_info[$this->_menu_in_order[$i]]['content_type'];
560 if ($content_type == CONTENT_TYPE_CONTENT || $content_type == CONTENT_TYPE_WEBLINK)
561 return(array('content_id' => $this->_menu_in_order[$i],
562 'ordering' => $this->_menu_info[$this->_menu_in_order[$i]]['ordering'],
563 'title' => $this->_menu_info[$this->_menu_in_order[$i]]['title']));
569 /* @See include/header.inc.php */
570 function generateSequenceCrumbs($cid) {
573 $sequence_links = array();
575 $first = $this->getNextContent(0); // get first
577 if ($_SESSION['prefs']['PREF_NUMBERING'] && $first) {
578 $first['title'] = $this->getNumbering($first['content_id']).' '.$first['title'];
581 $first['url'] = $_base_path.'home/course/content.php?_cid='.$first['content_id'];
582 $sequence_links['first'] = $first;
585 if (!$cid && $_SESSION['s_cid']) {
586 $resume['title'] = $this->_menu_info[$_SESSION['s_cid']]['title'];
588 if ($_SESSION['prefs']['PREF_NUMBERING']) {
589 $resume['title'] = $this->getNumbering($_SESSION['s_cid']).' ' . $resume['title'];
592 $resume['url'] = $_base_path.'home/course/content.php?_cid='.$_SESSION['s_cid'];
594 $sequence_links['resume'] = $resume;
597 $previous = $this->getPreviousContent($cid);
599 $next = $this->getNextContent($cid ? $cid : 0);
601 if ($_SESSION['prefs']['PREF_NUMBERING']) {
602 $previous['title'] = $this->getNumbering($previous['content_id']).' '.$previous['title'];
603 $next['title'] = $this->getNumbering($next['content_id']).' '.$next['title'];
606 $next['url'] = $_base_path.'home/course/content.php?_cid='.$next['content_id'];
607 if (isset($previous['content_id'])) {
608 $previous['url'] = $_base_path.'home/course/content.php?_cid='.$previous['content_id'];
611 if (isset($previous['content_id'])) {
612 $sequence_links['previous'] = $previous;
614 // $previous['url'] = $_base_path . url_rewrite('index.php');
615 // $previous['url'] = $_base_path . 'home/course/index.php';
616 // $previous['title'] = _AT('home');
617 // $sequence_links['previous'] = $previous;
619 if (!empty($next['content_id'])) {
620 $sequence_links['next'] = $next;
624 return $sequence_links;
627 /** Generate javascript to hide all root content folders, except the one with current content page
629 * @return print out javascript function initContentMenu()
632 global $_base_path, $_course_id;
635 function initContentMenu() {
636 tree_collapse_icon = "'.$_base_path.'images/tree/tree_collapse.gif";
637 tree_expand_icon = "'.$_base_path.'images/tree/tree_expand.gif";
641 $sql = "SELECT content_id
642 FROM ".TABLE_PREFIX."content
643 WHERE course_id=$this->course_id
644 AND content_type = ".CONTENT_TYPE_FOLDER;
645 $rows = $this->dao->execute($sql);
647 // collapse all root content folders
648 if (is_array($rows)) {
649 foreach ($rows as $row) {
651 if (trans.utility.getcookie("t.c'.$_course_id.'_'.$row['content_id'].'") == "1")
653 jQuery("#folder"+'.$row['content_id'].').show();
654 jQuery("#tree_icon"+'.$row['content_id'].').attr("src", tree_collapse_icon);
655 jQuery("#tree_icon"+'.$row['content_id'].').attr("alt", "'._AT("collapse").'");
656 jQuery("#tree_icon"+'.$row['content_id'].').attr("title", "'._AT("collapse").'");
660 jQuery("#folder"+'.$row['content_id'].').hide();
661 jQuery("#tree_icon"+'.$row['content_id'].').attr("src", tree_expand_icon);
662 jQuery("#tree_icon"+'.$row['content_id'].').attr("alt", "'._AT("expand").'");
663 jQuery("#tree_icon"+'.$row['content_id'].').attr("title", "'._AT("expand").'");
669 // expand the content folder that has current content
670 if (isset($_SESSION['s_cid']) && $_SESSION['s_cid'] > 0) {
671 $current_content_path = $this->getContentPath($_SESSION['s_cid']);
673 for ($i=0; $i < count($current_content_path)-1; $i++)
675 jQuery("#folder"+'.$current_content_path[$i]['content_id'].').show();
676 jQuery("#tree_icon"+'.$current_content_path[$i]['content_id'].').attr("src", tree_collapse_icon);
677 jQuery("#tree_icon"+'.$current_content_path[$i]['content_id'].').attr("alt", "'._AT("collapse").'");
678 trans.utility.setcookie("t.c'.$_course_id.'_'.$current_content_path[$i]['content_id'].'", "1", 1);
681 echo '}'; // end of javascript function initContentMenu()
684 /* @See include/html/dropdowns/menu_menu.inc.php */
685 function printMainMenu( ) {
686 global $_current_user, $_course_id;
688 if (!($this->course_id > 0)) {
699 $ignore_state = true;
703 // if change the location of this line, change function switchEditMode(), else condition accordingly
704 echo '<div id="editable_table">';
706 if (isset($_current_user) && $_current_user->isAuthor($this->course_id) && !Utility::isMobileTheme())
709 <div class="menuedit">
710 <a href="'.$_base_path.'home/editor/edit_content_folder.php?_course_id='.$_course_id.'">
711 <img id="img_create_top_folder" src="'.$_base_path.'images/mfolder.gif" alt="'._AT("add_top_folder").'" title="'._AT("add_top_folder").'" style="border:0;height:1.2em" />
713 <a href="'.$_base_path.'home/editor/edit_content.php?_course_id='.$_course_id.'">
714 <img id="img_create_top_content" src="'.$_base_path.'images/mpage.gif" alt="'._AT("add_top_page").'" title="'._AT("add_top_page").'" style="border:0;height:1.2em" />
716 <a href="javascript:void(0)" onclick="javascript:switchEditMode();">
717 <img id="img_switch_edit_mode" src="'.$_base_path.'images/medit.gif" alt="'._AT("enter_edit_mode").'" title="'._AT("enter_edit_mode").'" style="border:0;height:1.2em" />
721 $this->printMenu($parent_id, $depth, $path, $children, $truncate, $ignore_state);
723 // javascript for inline editor
725 <script type="text/javascript">
727 // only expand the content folder that has the current content page
731 function switchEditMode() {
732 title_edit = "'._AT("enter_edit_mode").'";
733 img_edit = "'.$_base_path.'images/medit.gif";
735 title_view = "'._AT("exit_edit_mode").'";
736 img_view = "'.$_base_path.'images/mlock.gif";
738 if (jQuery("#img_switch_edit_mode").attr("src") == img_edit)
740 jQuery("#img_switch_edit_mode").attr("src", img_view);
741 jQuery("#img_switch_edit_mode").attr("alt", title_view);
742 jQuery("#img_switch_edit_mode").attr("title", title_view);
746 { // refresh the content navigation to exit the edit mode
747 jQuery.post("'. TR_BASE_HREF. 'home/course/refresh_content_nav.php?_course_id='.$_course_id.'", {},
748 function(data) {jQuery("#editable_table").replaceWith(data); initContentMenu();});
752 function inlineEditsSetup() {
753 jQuery("#editable_table").find(".inlineEdits").each(function() {
754 jQuery(this).text(jQuery(this).attr("title"));
757 var tableEdit = fluid.inlineEdits("#editable_table", {
759 text : ".inlineEdits",
760 editables : "span:has(span.inlineEdits)"
763 applyEditPadding: false,
766 afterFinishEdit : function (newValue, oldValue, editNode, viewNode) {
767 if (newValue != oldValue)
769 rtn = jQuery.post("'. TR_BASE_HREF. 'home/course/content_nav_inline_editor_submit.php", { "field":viewNode.id, "value":newValue },
770 function(data) {}, "json");
776 jQuery(".fl-inlineEdit-edit").css("width", "80px")
785 /* @See tools/sitemap/index.php */
786 function printSiteMapMenu() {
792 $ignore_state = true;
795 $this->printMenu($parent_id, $depth, $path, $children, $truncate, $ignore_state, 'sitemap');
799 function printTOCMenu($cid, $top_num) {
802 $path = $top_num.'.';
805 $ignore_state = false;
808 $this->printMenu($parent_id, $depth, $path, $children, $truncate, $ignore_state);
811 /* @See index.php include/html/dropdowns/local_menu.inc.php */
812 function printSubMenu($cid, $top_num) {
815 $path = $top_num.'.';
818 $ignore_state = false;
821 $this->printMenu($parent_id, $depth, $path, $children, $truncate, $ignore_state);
824 /* @See include/html/menu_menu.inc.php */
825 /* Access: PRIVATE */
826 function printMenu($parent_id, $depth, $path, $children, $truncate, $ignore_state, $from = '') {
827 global $cid, $_my_uri, $_base_path, $rtl, $substr, $strlen, $_current_user;
830 if (!isset($temp_path)) {
832 $temp_path = $this->getContentPath($cid);
834 $temp_path = $this->getContentPath($_SESSION['s_cid']);
838 $highlighted = array();
839 if (is_array($temp_path)) {
840 foreach ($temp_path as $temp_path_item) {
841 $_SESSION['menu'][$temp_path_item['content_id']] = 1;
842 $highlighted[$temp_path_item['content_id']] = true;
848 $this->start = false;
851 if ( isset($this->_menu[$parent_id]) && is_array($this->_menu[$parent_id]) ) {
852 $top_level = $this->_menu[$parent_id];
854 $num_items = count($top_level);
856 // if ($parent_id <> 0) echo '<li>';
858 // echo '<ul id="folder'.$parent_id.$from.'">'."\n";
859 echo '<div id="folder'.$parent_id.$from.'">'."\n";
861 foreach ($top_level as $garbage => $content) {
863 //tests do not have content id
864 $content['content_id'] = isset($content['content_id']) ? $content['content_id'] : '';
866 if (!$ignore_state) {
867 $link .= '<a name="menu'.$content['content_id'].'"></a>';
872 if ( (($_SESSION['s_cid'] != $content['content_id']) || ($_SESSION['s_cid'] != $cid)) && ($content['content_type'] == CONTENT_TYPE_CONTENT || $content['content_type'] == CONTENT_TYPE_WEBLINK))
873 { // non-current content nodes with content type "CONTENT_TYPE_CONTENT"
874 if (isset($highlighted[$content['content_id']])) {
879 //content test extension @harris
880 //if this is a test link.
881 if (isset($content['test_id'])){
882 $title_n_alt = $content['title'];
883 $in_link = $_base_path.'tests/preview.php?tid='.$content['test_id'].'&_cid='.$parent_id;
884 $img_link = ' <img src="'.$_base_path.'images/check.gif" title="'.$title_n_alt.'" alt="'.$title_n_alt.'" />';
886 $in_link = $_base_path.'home/course/content.php?_cid='.$content['content_id'];
890 $full_title = $content['title'];
891 // $link .= $img_link . ' <a href="'.$_base_path.url_rewrite($in_link).'" title="';
892 $link .= $img_link . ' <a href="'.$in_link.'" title="';
893 $base_title_length = 29;
894 if ($_SESSION['prefs']['PREF_NUMBERING']) {
895 // $link .= $path.$counter.' ';
896 $base_title_length = 24;
899 $link .= $content['title'].'">';
901 if ($truncate && ($strlen($content['title']) > ($base_title_length-$depth*4)) ) {
902 $content['title'] = htmlspecialchars(rtrim($substr(htmlspecialchars_decode($content['title']), 0, ($base_title_length-$depth*4)-4))).'...';
904 // $content['title'] = htmlspecialchars(rtrim($substr(htmlspecialchars_decode($content['title']), 0, $base_title_length-4))).'...';
906 if (isset($content['test_id']))
907 $link .= $content['title'];
909 $link .= '<span class="inlineEdits" id="menu-'.$content['content_id'].'" title="'.$full_title.'">'.
910 ($_SESSION['prefs']['PREF_NUMBERING'] ? $path.$counter.' ' : '').
911 $content['title'].'</span>';
915 $link .= '</strong>';
918 // instructors have privilege to delete content
919 if (isset($_current_user) && $_current_user->isAuthor($this->course_id) && !isset($content['test_id']) && !Utility::isMobileTheme()) {
920 $link .= '<a href="'.$_base_path.'home/editor/delete_content.php?_cid='.$content['content_id'].'"><img src="'.TR_BASE_HREF.'images/x.gif" alt="'._AT("delete_content").'" title="'._AT("delete_content").'" style="border:0" height="10" /></a>';
924 { // current content page & nodes with content type "CONTENT_TYPE_FOLDER"
925 $base_title_length = 26;
926 if ($_SESSION['prefs']['PREF_NUMBERING']) {
927 $base_title_length = 21;
930 if (isset($highlighted[$content['content_id']])) {
935 if ($content['content_type'] == CONTENT_TYPE_CONTENT || $content['content_type'] == CONTENT_TYPE_WEBLINK)
936 { // current content page
937 $full_title = $content['title'];
938 $link .= '<a href="'.$_my_uri.'"><img src="'.$_base_path.'images/clr.gif" alt="'._AT('you_are_here').': '.
939 ($_SESSION['prefs']['PREF_NUMBERING'] ? $path.$counter : '').
940 $content['title'].'" height="1" width="1" border="0" /></a><strong style="color:red" title="'.$content['title'].'">'."\n";
942 if ($truncate && ($strlen($content['title']) > ($base_title_length-$depth*4)) ) {
943 $content['title'] = htmlspecialchars(rtrim($substr(htmlspecialchars_decode($content['title']), 0, ($base_title_length-$depth*4)-4))).'...';
945 // $content['title'] = htmlspecialchars(rtrim($substr(htmlspecialchars_decode($content['title']), 0, $base_title_length-4))).'...';
946 $link .= '<a name="menu'.$content['content_id'].'"></a><span class="inlineEdits" id="menu-'.$content['content_id'].'" title="'.$full_title.'">'.
947 ($_SESSION['prefs']['PREF_NUMBERING'] ? $path.$counter.' ' : '').
948 $content['title'].'</span></strong>';
950 // instructors have privilege to delete content
951 if (isset($_current_user) && $_current_user->isAuthor($this->course_id) && !Utility::isMobileTheme()) {
952 $link .= '<a href="'.$_base_path.'home/editor/delete_content.php?_cid='.$content['content_id'].'"><img src="'.TR_BASE_HREF.'images/x.gif" alt="'._AT("delete_content").'" title="'._AT("delete_content").'" style="border:0" height="10" /></a>';
956 { // nodes with content type "CONTENT_TYPE_FOLDER"
957 // $link .= '<a href="javascript:void(0)" onclick="javascript: trans.utility.toggleFolder(\''.$content['content_id'].$from.'\'); "><img src="'.$_base_path.'images/clr.gif" alt="'._AT('content_folder').': '.$content['title'].'" height="1" width="1" border="0" /></a>'."\n";
959 $full_title = $content['title'];
960 if (isset($_current_user) && $_current_user->isAuthor($this->course_id) && !Utility::isMobileTheme()) {
961 // $link .= '<a href="'.$_base_path.url_rewrite("editor/edit_content_folder.php?_cid=".$content['content_id']).'" title="'.$full_title. _AT('click_edit').'">'."\n";
962 $link .= '<a href="'.$_base_path.'home/editor/edit_content_folder.php?_cid='.$content['content_id'].'" title="'.$full_title. _AT('click_edit').'">'."\n";
965 $link .= '<span style="cursor:pointer" onclick="javascript: trans.utility.toggleFolder(\''.$content['content_id'].$from.'\', \''._AT("expand").'\', \''._AT('collapse').'\', '.$this->course_id.'); ">'."\n";
968 if ($truncate && ($strlen($content['title']) > ($base_title_length-$depth*4)) ) {
969 $content['title'] = htmlspecialchars(rtrim($substr(htmlspecialchars_decode($content['title']), 0, ($base_title_length-$depth*4)-4))).'...';
971 // $content['title'] = htmlspecialchars(rtrim($substr(htmlspecialchars_decode($content['title']), 0, $base_title_length-4))).'...';
972 if (isset($content['test_id']))
973 $link .= $content['title'];
975 $link .= '<span class="inlineEdits" id="menu-'.$content['content_id'].'" title="'.$full_title.'">'.
976 ($_SESSION['prefs']['PREF_NUMBERING'] ? $path.$counter.' ' : '').
977 $content['title'].'</span>';
979 if (isset($_current_user) && $_current_user->isAuthor($this->course_id) && !Utility::isMobileTheme()) {
980 $link .= '</a>'."\n";
983 $link .= '</span>'."\n";
986 // instructors have privilege to delete content
987 if (isset($_current_user) && $_current_user->isAuthor($this->course_id) && !Utility::isMobileTheme()) {
988 $link .= '<a href="'.$_base_path.'home/editor/delete_content.php?_cid='.$content['content_id'].'"><img src="'.TR_BASE_HREF.'images/x.gif" alt="'._AT("delete_content").'" title="'._AT("delete_content").'" style="border:0" height="10" /></a>';
990 // echo '<div id="folder_content_'.$content['content_id'].'">';
994 $link .= '</strong>';
1002 // echo '<li>'."\n";
1005 if ( isset($this->_menu[$content['content_id']]) && is_array($this->_menu[$content['content_id']]) ) {
1007 for ($i=0; $i<$depth; $i++) {
1008 if ($children[$i] == 1) {
1009 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_vertline.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1011 echo '<img src="'.$_base_path.'images/clr.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1015 if (($counter == $num_items) && ($depth > 0)) {
1016 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_end.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1017 $children[$depth] = 0;
1018 } else if ($counter == $num_items) {
1019 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_end.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1020 $children[$depth] = 0;
1022 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_split.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1023 $children[$depth] = 1;
1026 if ($_SESSION['s_cid'] == $content['content_id']) {
1027 if (is_array($this->_menu[$content['content_id']])) {
1028 $_SESSION['menu'][$content['content_id']] = 1;
1032 if (isset($_SESSION['menu'][$content['content_id']]) && $_SESSION['menu'][$content['content_id']] == 1) {
1034 // echo '<img src="'.$_base_path.'images/tree/tree_collapse.gif" id="tree_icon'.$content['content_id'].$from.'" alt="'._AT('collapse').'" border="0" width="16" height="16" title="'._AT('collapse').'" class="img-size-tree" onclick="javascript: trans.utility.toggleFolder(\''.$content['content_id'].$from.'\'); " />'."\n";
1035 echo '<a href="javascript:void(0)" onclick="javascript: trans.utility.toggleFolder(\''.$content['content_id'].$from.'\', \''._AT("expand").'\', \''._AT('collapse').'\', '.$this->course_id.'); "><img src="'.$_base_path.'images/tree/tree_collapse.gif" id="tree_icon'.$content['content_id'].$from.'" alt="'._AT('collapse').'" border="0" width="16" height="16" title="'._AT('collapse').'" class="img-size-tree" /></a>'."\n";
1038 echo '<a href="'.$_my_uri.'collapse='.$content['content_id'].'">'."\n";
1039 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_collapse.gif" id="tree_icon'.$content['content_id'].$from.'" alt="'._AT('collapse').'" border="0" width="16" height="16" title="'._AT('collapse').' '.$content['title'].'" class="img-size-tree" onclick="javascript: trans.utility.toggleFolder(\''.$content['content_id'].$from.'\', \''._AT("expand").'\', \''._AT('collapse').'\', '.$this->course_id.'); " />'."\n";
1044 // echo '<img src="'.$_base_path.'images/tree/tree_collapse.gif" id="tree_icon'.$content['content_id'].$from.'" alt="'._AT('collapse').'" border="0" width="16" height="16" title="'._AT('collapse').'" class="img-size-tree" />'."\n";
1045 echo '<a href="javascript:void(0)" onclick="javascript: trans.utility.toggleFolder(\''.$content['content_id'].$from.'\', \''._AT("expand").'\', \''._AT('collapse').'\', '.$this->course_id.'); "><img src="'.$_base_path.'images/tree/tree_collapse.gif" id="tree_icon'.$content['content_id'].$from.'" alt="'._AT('collapse').'" border="0" width="16" height="16" title="'._AT('collapse').'" class="img-size-tree" /></a>'."\n";
1048 echo '<a href="'.$_my_uri.'expand='.$content['content_id'].'">'."\n";
1049 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_expand.gif" id="tree_icon'.$content['content_id'].$from.'" alt="'._AT('expand').'" border="0" width="16" height="16" title="'._AT('expand').' '.$content['title'].'" class="img-size-tree" onclick="javascript: trans.utility.toggleFolder(\''.$content['content_id'].$from.'\', \''._AT("expand").'\', \''._AT('collapse').'\', '.$this->course_id.'); " />';
1055 /* doesn't have children */
1056 if ($counter == $num_items) {
1057 for ($i=0; $i<$depth; $i++) {
1058 if ($children[$i] == 1) {
1059 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_vertline.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1061 echo '<img src="'.$_base_path.'images/clr.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1064 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_end.gif" alt="" border="0" class="img-size-tree" />'."\n";
1066 for ($i=0; $i<$depth; $i++) {
1067 if ($children[$i] == 1) {
1068 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_vertline.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1070 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_space.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1073 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_split.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1075 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_horizontal.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1078 // if ($_SESSION['prefs']['PREF_NUMBERING']) {
1079 // echo $path.$counter;
1084 echo "\n<br /></span>\n\n";
1086 if ( $ignore_state || (isset($_SESSION['menu'][$content['content_id']]) && $_SESSION['menu'][$content['content_id']] == 1)) {
1090 $this->printMenu($content['content_id'],
1105 // if ($parent_id <> 0) print "</li>\n\n";
1110 /* @See include/html/editor_tabs/properties.inc.php
1111 @See editor/arrange_content.php
1112 $print_type: "movable" or "related_content"
1114 function printActionMenu($menu, $parent_id, $depth, $path, $children, $print_type = 'movable') {
1116 global $cid, $_my_uri, $_base_path, $rtl;
1120 $top_level = $menu[$parent_id];
1122 if ( is_array($top_level) ) {
1124 $num_items = count($top_level);
1125 foreach ($top_level as $current_num => $content) {
1126 if (isset($content['test_id'])){
1130 $link = $buttons = '';
1134 if ($print_type == 'movable')
1136 if ($content['content_id'] == $_POST['moved_cid']) {
1137 $radio_selected = ' checked="checked" ';
1140 $radio_selected = '';
1143 $buttons = '<td>'."\n".
1145 ' <input type="image" name="move['.$parent_id.'_'.$content['ordering'].']" src="'.$_base_path.'images/before.gif" alt="'._AT('before_topic', $content['title']).'" title="'._AT('before_topic', $content['title']).'" style="height:1.5em; width:1.9em;" />'."\n";
1147 if ($current_num + 1 == count($top_level))
1148 $buttons .= ' <input type="image" name="move['.$parent_id.'_'.($content['ordering']+1).']" src="'.$_base_path.'images/after.gif" alt="'._AT('after_topic', $content['title']).'" title="'._AT('after_topic', $content['title']).'" style="height:1.5em; width:1.9em;" />'."\n";
1150 $buttons .= ' </small>'."\n".
1154 if ($content['content_type'] == CONTENT_TYPE_FOLDER)
1155 $buttons .= '<input type="image" name="move['.$content['content_id'].'_1]" src="'.$_base_path.'images/child_of.gif" style="height:1.25em; width:1.7em;" alt="'._AT('child_of', $content['title']).'" title="'._AT('child_of', $content['title']).'" />';
1157 $buttons .= ' ';
1159 $buttons .= '</td>'."\n".
1160 '<td><input name="moved_cid" value="'.$content['content_id'].'" type="radio" id="r'.$content['content_id'].'" '.$radio_selected .'/></td>'."\n";
1163 $buttons .= '<td>'."\n";
1164 if ($print_type == "related_content")
1166 if ($content['content_type'] == CONTENT_TYPE_CONTENT || $content['content_type'] == CONTENT_TYPE_WEBLINK)
1168 $link .= '<input type="checkbox" name="related[]" value="'.$content['content_id'].'" id="r'.$content['content_id'].'" ';
1169 if (isset($_POST['related']) && in_array($content['content_id'], $_POST['related'])) {
1170 $link .= ' checked="checked"';
1172 $link .= ' />'."\n";
1176 if ($content['content_type'] == CONTENT_TYPE_FOLDER)
1178 $link .= '<img src="'.$_base_path.'images/folder.gif" />';
1180 $link .= ' <label for="r'.$content['content_id'].'">'.$content['title'].'</label>'."\n";
1182 if ( is_array($menu[$content['content_id']]) && !empty($menu[$content['content_id']]) ) {
1185 for ($i=0; $i<$depth; $i++) {
1186 if ($children[$i] == 1) {
1189 if ($end && ($i==0)) {
1190 echo '<img src="'.$_base_path.'images/clr.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />';
1192 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_vertline.gif" alt="" border="0" width="16" height="16" />';
1195 echo '<img src="'.$_base_path.'images/clr.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />';
1199 if (($counter == $num_items) && ($depth > 0)) {
1200 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_end.gif" alt="" border="0" width="16" height="16" />';
1201 $children[$depth] = 0;
1204 if (($num_items == $counter) && ($parent_id == 0)) {
1205 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_end.gif" alt="" border="0" width="16" height="16" />';
1208 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_split.gif" alt="" border="0" width="16" height="16" />';
1210 $children[$depth] = 1;
1213 if ($_SESSION['s_cid'] == $content['content_id']) {
1214 if (is_array($menu[$content['content_id']])) {
1215 $_SESSION['menu'][$content['content_id']] = 1;
1219 if ($_SESSION['menu'][$content['content_id']] == 1) {
1220 echo '<img src="'.$_base_path.'images/tree/tree_disabled.gif" alt="'._AT('toggle_disabled').'" border="0" width="16" height="16" title="'._AT('toggle_disabled').'" />';
1223 echo '<img src="'.$_base_path.'images/tree/tree_disabled.gif" alt="'._AT('toggle_disabled').'" border="0" width="16" height="16" title="'._AT('toggle_disabled').'" />';
1227 /* doesn't have children */
1228 if ($counter == $num_items) {
1231 for ($i=0; $i<$depth; $i++) {
1232 if ($children[$i] == 1) {
1233 if ($end && ($i == 0)) {
1234 echo '<img src="'.$_base_path.'images/clr.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />';
1236 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_vertline.gif" alt="" border="0" width="16" height="16" />';
1239 echo '<img src="'.$_base_path.'images/clr.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />';
1245 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_end.gif" alt="" border="0" />';
1250 for ($i=0; $i<$depth; $i++) {
1251 if ($children[$i] == 1) {
1252 if ($end && !$print) {
1254 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_space.gif" alt="" border="0" width="16" height="16" />';
1256 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_vertline.gif" alt="" border="0" width="16" height="16" />';
1259 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_space.gif" alt="" border="0" width="16" height="16" />';
1267 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_split.gif" alt="" border="0" width="16" height="16" />';
1269 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_horizontal.gif" alt="" border="0" width="16" height="16" />';
1272 echo '<small> '.($_SESSION['prefs']['PREF_NUMBERING'] ? $path.$counter : '');
1276 echo '</small></td>'."\n".'</tr>'."\n";
1278 $this->printActionMenu($menu,
1279 $content['content_id'],