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 /* delete this content page */
374 // $sql = "DELETE FROM ".TABLE_PREFIX."content WHERE content_id=$content_id AND course_id=$_SESSION[course_id]";
375 // $result = mysql_query($sql, $this->db);
377 /* delete this content from member tracking page */
378 // $sql = "DELETE FROM ".TABLE_PREFIX."member_track WHERE content_id=$content_id AND course_id=$_SESSION[course_id]";
379 // $result = mysql_query($sql, $this->db);
381 // $sql = "DELETE FROM ".TABLE_PREFIX."related_content WHERE content_id=$content_id OR related_content_id=$content_id";
382 // $result = mysql_query($sql, $this->db);
384 /* delete the content tests association */
385 // $sql = "DELETE FROM ".TABLE_PREFIX."content_tests_assoc WHERE content_id=$content_id";
386 // $result = mysql_query($sql, $this->db);
388 /* delete the content forum association */
389 // $sql = "DELETE FROM ".TABLE_PREFIX."content_forums_assoc WHERE content_id=$content_id";
390 // $result = mysql_query($sql, $this->db);
392 /* Delete all AccessForAll contents */
393 // require_once(TR_INCLUDE_PATH.'classes/A4a/A4a.class.php');
394 // $a4a = new A4a($content_id);
395 // $a4a->deleteA4a();
397 /* remove the "resume" to this page, b/c it was deleted */
398 // $sql = "UPDATE ".TABLE_PREFIX."course_enrollment SET last_cid=0 WHERE course_id=$_SESSION[course_id] AND last_cid=$content_id";
399 // $result = mysql_query($sql, $this->db);
405 /* private. call from deleteContent only. */
406 function deleteContentRecursive($content_id) {
407 /* check if this content has sub content */
408 $children = $this->_menu[$content_id];
410 if (is_array($children) && (count($children)>0) ) {
411 /* delete its children recursively first*/
412 foreach ($children as $x => $info) {
413 if ($info['content_id'] > 0) {
414 $this->deleteContent($info['content_id']);
419 // delete this content page
420 $this->contentDAO->Delete($content_id);
421 // $sql = "DELETE FROM ".TABLE_PREFIX."content WHERE content_id=$content_id AND course_id=$_SESSION[course_id]";
422 // $result = mysql_query($sql, $this->db);
424 /* delete this content from member tracking page */
425 // $sql = "DELETE FROM ".TABLE_PREFIX."member_track WHERE content_id=$content_id";
426 // $result = mysql_query($sql, $this->db);
428 /* delete the content tests association */
429 // $sql = "DELETE FROM ".TABLE_PREFIX."content_tests_assoc WHERE content_id=$content_id";
430 // $result = mysql_query($sql, $this->db);
433 function getContentPage($content_id) {
434 include_once(TR_INCLUDE_PATH.'classes/DAO/ContentDAO.class.php');
435 $contentDAO = new ContentDAO();
436 return $contentDAO->get($content_id);
440 * Return a list of tests associated with the selected content
441 * @param int the content id that all tests are associated with it.
442 * @return array list of tests
446 function & getContentTestsAssoc($content_id){
447 $sql = "SELECT ct.test_id, t.title
448 FROM (SELECT * FROM ".TABLE_PREFIX."content_tests_assoc
449 WHERE content_id=$content_id) AS ct
450 LEFT JOIN ".TABLE_PREFIX."tests t ON ct.test_id=t.test_id
452 return $this->dao->execute($sql);
455 function & cleanOutput($value) {
456 return stripslashes(htmlspecialchars($value));
460 /* @See include/html/editor_tabs/properties.inc.php */
462 function getNumSections() {
463 return $this->num_sections;
467 function getMaxDepth() {
468 return $this->max_depth;
472 function getContentLength() {
473 return $this->content_length;
476 /* @See include/html/dropdowns/local_menu.inc.php */
477 function getLocationPositions($parent_id, $content_id) {
478 $siblings = $this->getContent($parent_id);
479 for ($i=0;$i<count($siblings); $i++){
480 if ($siblings[$i]['content_id'] == $content_id) {
487 /* Access: Private */
488 function getNumbering($content_id) {
489 $path = $this->getContentPath($content_id);
492 foreach ($path as $page) {
493 $num = $this->getLocationPositions($parent, $page['content_id']) +1;
494 $parent = $page['content_id'];
495 $numbering .= $num.'.';
497 $numbering = substr($numbering, 0, -1);
502 function getPreviousContent($content_id) {
503 if (is_array($this->_menu_in_order))
505 foreach ($this->_menu_in_order as $content_location => $this_content_id)
507 if ($this_content_id == $content_id) break;
510 for ($i=$content_location-1; $i >= 0; $i--)
512 $content_type = $this->_menu_info[$this->_menu_in_order[$i]]['content_type'];
514 if ($content_type == CONTENT_TYPE_CONTENT || $content_type == CONTENT_TYPE_WEBLINK)
515 return array('content_id' => $this->_menu_in_order[$i],
516 'ordering' => $this->_menu_info[$this->_menu_in_order[$i]]['ordering'],
517 'title' => $this->_menu_info[$this->_menu_in_order[$i]]['title']);
524 * return the array of the next content node of the given $content_id
525 * when $content_id = 0 or is not set, return the first content node
527 * @return an array of the next content node
529 function getNextContent($content_id) {
530 if (is_array($this->_menu_in_order))
532 // find out the location of the $content_id
533 if (!$content_id) $content_location = 0; // the first content location when $content_id = 0 or is not set
536 foreach ($this->_menu_in_order as $content_location => $this_content_id)
538 if ($this_content_id == $content_id)
546 // the next content node must be at or after the $content_location
547 // and with the content type CONTENT or WEBLINK
548 for ($i=$content_location; $i < count($this->_menu_in_order); $i++)
550 $content_type = $this->_menu_info[$this->_menu_in_order[$i]]['content_type'];
552 if ($content_type == CONTENT_TYPE_CONTENT || $content_type == CONTENT_TYPE_WEBLINK)
553 return(array('content_id' => $this->_menu_in_order[$i],
554 'ordering' => $this->_menu_info[$this->_menu_in_order[$i]]['ordering'],
555 'title' => $this->_menu_info[$this->_menu_in_order[$i]]['title']));
561 /* @See include/header.inc.php */
562 function generateSequenceCrumbs($cid) {
565 $sequence_links = array();
567 $first = $this->getNextContent(0); // get first
569 if ($_SESSION['prefs']['PREF_NUMBERING'] && $first) {
570 $first['title'] = $this->getNumbering($first['content_id']).' '.$first['title'];
573 $first['url'] = $_base_path.'home/course/content.php?_cid='.$first['content_id'];
574 $sequence_links['first'] = $first;
577 if (!$cid && $_SESSION['s_cid']) {
578 $resume['title'] = $this->_menu_info[$_SESSION['s_cid']]['title'];
580 if ($_SESSION['prefs']['PREF_NUMBERING']) {
581 $resume['title'] = $this->getNumbering($_SESSION['s_cid']).' ' . $resume['title'];
584 $resume['url'] = $_base_path.'home/course/content.php?_cid='.$_SESSION['s_cid'];
586 $sequence_links['resume'] = $resume;
589 $previous = $this->getPreviousContent($cid);
591 $next = $this->getNextContent($cid ? $cid : 0);
593 if ($_SESSION['prefs']['PREF_NUMBERING']) {
594 $previous['title'] = $this->getNumbering($previous['content_id']).' '.$previous['title'];
595 $next['title'] = $this->getNumbering($next['content_id']).' '.$next['title'];
598 $next['url'] = $_base_path.'home/course/content.php?_cid='.$next['content_id'];
599 if (isset($previous['content_id'])) {
600 $previous['url'] = $_base_path.'home/course/content.php?_cid='.$previous['content_id'];
603 if (isset($previous['content_id'])) {
604 $sequence_links['previous'] = $previous;
606 // $previous['url'] = $_base_path . url_rewrite('index.php');
607 // $previous['url'] = $_base_path . 'home/course/index.php';
608 // $previous['title'] = _AT('home');
609 // $sequence_links['previous'] = $previous;
611 if (!empty($next['content_id'])) {
612 $sequence_links['next'] = $next;
616 return $sequence_links;
619 /** Generate javascript to hide all root content folders, except the one with current content page
621 * @return print out javascript function initContentMenu()
624 global $_base_path, $_course_id;
627 function initContentMenu() {
628 tree_collapse_icon = "'.$_base_path.'images/tree/tree_collapse.gif";
629 tree_expand_icon = "'.$_base_path.'images/tree/tree_expand.gif";
633 $sql = "SELECT content_id
634 FROM ".TABLE_PREFIX."content
635 WHERE course_id=$this->course_id
636 AND content_type = ".CONTENT_TYPE_FOLDER;
637 $rows = $this->dao->execute($sql);
639 // collapse all root content folders
640 if (is_array($rows)) {
641 foreach ($rows as $row) {
643 if (trans.utility.getcookie("t.c'.$_course_id.'_'.$row['content_id'].'") == "1")
645 jQuery("#folder"+'.$row['content_id'].').show();
646 jQuery("#tree_icon"+'.$row['content_id'].').attr("src", tree_collapse_icon);
647 jQuery("#tree_icon"+'.$row['content_id'].').attr("alt", "'._AT("collapse").'");
648 jQuery("#tree_icon"+'.$row['content_id'].').attr("title", "'._AT("collapse").'");
652 jQuery("#folder"+'.$row['content_id'].').hide();
653 jQuery("#tree_icon"+'.$row['content_id'].').attr("src", tree_expand_icon);
654 jQuery("#tree_icon"+'.$row['content_id'].').attr("alt", "'._AT("expand").'");
655 jQuery("#tree_icon"+'.$row['content_id'].').attr("title", "'._AT("expand").'");
661 // expand the content folder that has current content
662 if (isset($_SESSION['s_cid']) && $_SESSION['s_cid'] > 0) {
663 $current_content_path = $this->getContentPath($_SESSION['s_cid']);
665 for ($i=0; $i < count($current_content_path)-1; $i++)
667 jQuery("#folder"+'.$current_content_path[$i]['content_id'].').show();
668 jQuery("#tree_icon"+'.$current_content_path[$i]['content_id'].').attr("src", tree_collapse_icon);
669 jQuery("#tree_icon"+'.$current_content_path[$i]['content_id'].').attr("alt", "'._AT("collapse").'");
670 trans.utility.setcookie("t.c'.$_course_id.'_'.$current_content_path[$i]['content_id'].'", "1", 1);
673 echo '}'; // end of javascript function initContentMenu()
676 /* @See include/html/dropdowns/menu_menu.inc.php */
677 function printMainMenu( ) {
678 global $_current_user, $_course_id;
680 if (!($this->course_id > 0)) {
691 $ignore_state = true;
695 // if change the location of this line, change function switchEditMode(), else condition accordingly
696 echo '<div id="editable_table">';
698 if (isset($_current_user) && $_current_user->isAuthor($this->course_id) && !Utility::isMobileTheme())
701 <div class="menuedit">
702 <a href="'.$_base_path.'home/editor/edit_content_folder.php?_course_id='.$_course_id.'">
703 <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" />
705 <a href="'.$_base_path.'home/editor/edit_content.php?_course_id='.$_course_id.'">
706 <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" />
708 <a href="javascript:void(0)" onclick="javascript:switchEditMode();">
709 <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" />
713 $this->printMenu($parent_id, $depth, $path, $children, $truncate, $ignore_state);
715 // javascript for inline editor
717 <script type="text/javascript">
719 // only expand the content folder that has the current content page
723 function switchEditMode() {
724 title_edit = "'._AT("enter_edit_mode").'";
725 img_edit = "'.$_base_path.'images/medit.gif";
727 title_view = "'._AT("exit_edit_mode").'";
728 img_view = "'.$_base_path.'images/mlock.gif";
730 if (jQuery("#img_switch_edit_mode").attr("src") == img_edit)
732 jQuery("#img_switch_edit_mode").attr("src", img_view);
733 jQuery("#img_switch_edit_mode").attr("alt", title_view);
734 jQuery("#img_switch_edit_mode").attr("title", title_view);
738 { // refresh the content navigation to exit the edit mode
739 jQuery.post("'. TR_BASE_HREF. 'home/course/refresh_content_nav.php?_course_id='.$_course_id.'", {},
740 function(data) {jQuery("#editable_table").replaceWith(data); initContentMenu();});
744 function inlineEditsSetup() {
745 jQuery("#editable_table").find(".inlineEdits").each(function() {
746 jQuery(this).text(jQuery(this).attr("title"));
749 var tableEdit = fluid.inlineEdits("#editable_table", {
751 text : ".inlineEdits",
752 editables : "span:has(span.inlineEdits)"
755 applyEditPadding: false,
758 afterFinishEdit : function (newValue, oldValue, editNode, viewNode) {
759 if (newValue != oldValue)
761 rtn = jQuery.post("'. TR_BASE_HREF. 'home/course/content_nav_inline_editor_submit.php", { "field":viewNode.id, "value":newValue },
762 function(data) {}, "json");
768 jQuery(".fl-inlineEdit-edit").css("width", "80px")
777 /* @See tools/sitemap/index.php */
778 function printSiteMapMenu() {
784 $ignore_state = true;
787 $this->printMenu($parent_id, $depth, $path, $children, $truncate, $ignore_state, 'sitemap');
791 function printTOCMenu($cid, $top_num) {
794 $path = $top_num.'.';
797 $ignore_state = false;
800 $this->printMenu($parent_id, $depth, $path, $children, $truncate, $ignore_state);
803 /* @See index.php include/html/dropdowns/local_menu.inc.php */
804 function printSubMenu($cid, $top_num) {
807 $path = $top_num.'.';
810 $ignore_state = false;
813 $this->printMenu($parent_id, $depth, $path, $children, $truncate, $ignore_state);
816 /* @See include/html/menu_menu.inc.php */
817 /* Access: PRIVATE */
818 function printMenu($parent_id, $depth, $path, $children, $truncate, $ignore_state, $from = '') {
819 global $cid, $_my_uri, $_base_path, $rtl, $substr, $strlen, $_current_user;
822 if (!isset($temp_path)) {
824 $temp_path = $this->getContentPath($cid);
826 $temp_path = $this->getContentPath($_SESSION['s_cid']);
830 $highlighted = array();
831 if (is_array($temp_path)) {
832 foreach ($temp_path as $temp_path_item) {
833 $_SESSION['menu'][$temp_path_item['content_id']] = 1;
834 $highlighted[$temp_path_item['content_id']] = true;
840 $this->start = false;
843 if ( isset($this->_menu[$parent_id]) && is_array($this->_menu[$parent_id]) ) {
844 $top_level = $this->_menu[$parent_id];
846 $num_items = count($top_level);
848 // if ($parent_id <> 0) echo '<li>';
850 // echo '<ul id="folder'.$parent_id.$from.'">'."\n";
851 echo '<div id="folder'.$parent_id.$from.'">'."\n";
853 foreach ($top_level as $garbage => $content) {
855 //tests do not have content id
856 $content['content_id'] = isset($content['content_id']) ? $content['content_id'] : '';
858 if (!$ignore_state) {
859 $link .= '<a name="menu'.$content['content_id'].'"></a>';
864 if ( (($_SESSION['s_cid'] != $content['content_id']) || ($_SESSION['s_cid'] != $cid)) && ($content['content_type'] == CONTENT_TYPE_CONTENT || $content['content_type'] == CONTENT_TYPE_WEBLINK))
865 { // non-current content nodes with content type "CONTENT_TYPE_CONTENT"
866 if (isset($highlighted[$content['content_id']])) {
871 //content test extension @harris
872 //if this is a test link.
873 if (isset($content['test_id'])){
874 $title_n_alt = $content['title'];
875 $in_link = $_base_path.'tests/preview.php?tid='.$content['test_id'].'&_cid='.$parent_id;
876 $img_link = ' <img src="'.$_base_path.'images/check.gif" title="'.$title_n_alt.'" alt="'.$title_n_alt.'" />';
878 $in_link = $_base_path.'home/course/content.php?_cid='.$content['content_id'];
882 $full_title = $content['title'];
883 // $link .= $img_link . ' <a href="'.$_base_path.url_rewrite($in_link).'" title="';
884 $link .= $img_link . ' <a href="'.$in_link.'" title="';
885 $base_title_length = 29;
886 if ($_SESSION['prefs']['PREF_NUMBERING']) {
887 // $link .= $path.$counter.' ';
888 $base_title_length = 24;
891 $link .= $content['title'].'">';
893 if ($truncate && ($strlen($content['title']) > ($base_title_length-$depth*4)) ) {
894 $content['title'] = htmlspecialchars(rtrim($substr(htmlspecialchars_decode($content['title']), 0, ($base_title_length-$depth*4)-4))).'...';
896 // $content['title'] = htmlspecialchars(rtrim($substr(htmlspecialchars_decode($content['title']), 0, $base_title_length-4))).'...';
898 if (isset($content['test_id']))
899 $link .= $content['title'];
901 $link .= '<span class="inlineEdits" id="menu-'.$content['content_id'].'" title="'.$full_title.'">'.
902 ($_SESSION['prefs']['PREF_NUMBERING'] ? $path.$counter.' ' : '').
903 $content['title'].'</span>';
907 $link .= '</strong>';
910 // instructors have privilege to delete content
911 if (isset($_current_user) && $_current_user->isAuthor($this->course_id) && !isset($content['test_id']) && !Utility::isMobileTheme()) {
912 $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>';
916 { // current content page & nodes with content type "CONTENT_TYPE_FOLDER"
917 $base_title_length = 26;
918 if ($_SESSION['prefs']['PREF_NUMBERING']) {
919 $base_title_length = 21;
922 if (isset($highlighted[$content['content_id']])) {
927 if ($content['content_type'] == CONTENT_TYPE_CONTENT || $content['content_type'] == CONTENT_TYPE_WEBLINK)
928 { // current content page
929 $full_title = $content['title'];
930 $link .= '<a href="'.$_my_uri.'"><img src="'.$_base_path.'images/clr.gif" alt="'._AT('you_are_here').': '.
931 ($_SESSION['prefs']['PREF_NUMBERING'] ? $path.$counter : '').
932 $content['title'].'" height="1" width="1" border="0" /></a><strong style="color:red" title="'.$content['title'].'">'."\n";
934 if ($truncate && ($strlen($content['title']) > ($base_title_length-$depth*4)) ) {
935 $content['title'] = htmlspecialchars(rtrim($substr(htmlspecialchars_decode($content['title']), 0, ($base_title_length-$depth*4)-4))).'...';
937 // $content['title'] = htmlspecialchars(rtrim($substr(htmlspecialchars_decode($content['title']), 0, $base_title_length-4))).'...';
938 $link .= '<a name="menu'.$content['content_id'].'"></a><span class="inlineEdits" id="menu-'.$content['content_id'].'" title="'.$full_title.'">'.
939 ($_SESSION['prefs']['PREF_NUMBERING'] ? $path.$counter.' ' : '').
940 $content['title'].'</span></strong>';
942 // instructors have privilege to delete content
943 if (isset($_current_user) && $_current_user->isAuthor($this->course_id) && !Utility::isMobileTheme()) {
944 $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>';
948 { // nodes with content type "CONTENT_TYPE_FOLDER"
949 // $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";
951 $full_title = $content['title'];
952 if (isset($_current_user) && $_current_user->isAuthor($this->course_id) && !Utility::isMobileTheme()) {
953 // $link .= '<a href="'.$_base_path.url_rewrite("editor/edit_content_folder.php?_cid=".$content['content_id']).'" title="'.$full_title. _AT('click_edit').'">'."\n";
954 $link .= '<a href="'.$_base_path.'home/editor/edit_content_folder.php?_cid='.$content['content_id'].'" title="'.$full_title. _AT('click_edit').'">'."\n";
957 $link .= '<span style="cursor:pointer" onclick="javascript: trans.utility.toggleFolder(\''.$content['content_id'].$from.'\', \''._AT("expand").'\', \''._AT('collapse').'\', '.$this->course_id.'); ">'."\n";
960 if ($truncate && ($strlen($content['title']) > ($base_title_length-$depth*4)) ) {
961 $content['title'] = htmlspecialchars(rtrim($substr(htmlspecialchars_decode($content['title']), 0, ($base_title_length-$depth*4)-4))).'...';
963 // $content['title'] = htmlspecialchars(rtrim($substr(htmlspecialchars_decode($content['title']), 0, $base_title_length-4))).'...';
964 if (isset($content['test_id']))
965 $link .= $content['title'];
967 $link .= '<span class="inlineEdits" id="menu-'.$content['content_id'].'" title="'.$full_title.'">'.
968 ($_SESSION['prefs']['PREF_NUMBERING'] ? $path.$counter.' ' : '').
969 $content['title'].'</span>';
971 if (isset($_current_user) && $_current_user->isAuthor($this->course_id) && !Utility::isMobileTheme()) {
972 $link .= '</a>'."\n";
975 $link .= '</span>'."\n";
978 // instructors have privilege to delete content
979 if (isset($_current_user) && $_current_user->isAuthor($this->course_id) && !Utility::isMobileTheme()) {
980 $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>';
982 // echo '<div id="folder_content_'.$content['content_id'].'">';
986 $link .= '</strong>';
997 if ( isset($this->_menu[$content['content_id']]) && is_array($this->_menu[$content['content_id']]) ) {
999 for ($i=0; $i<$depth; $i++) {
1000 if ($children[$i] == 1) {
1001 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_vertline.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1003 echo '<img src="'.$_base_path.'images/clr.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1007 if (($counter == $num_items) && ($depth > 0)) {
1008 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_end.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1009 $children[$depth] = 0;
1010 } else if ($counter == $num_items) {
1011 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_end.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1012 $children[$depth] = 0;
1014 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_split.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1015 $children[$depth] = 1;
1018 if ($_SESSION['s_cid'] == $content['content_id']) {
1019 if (is_array($this->_menu[$content['content_id']])) {
1020 $_SESSION['menu'][$content['content_id']] = 1;
1024 if (isset($_SESSION['menu'][$content['content_id']]) && $_SESSION['menu'][$content['content_id']] == 1) {
1026 // 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";
1027 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";
1030 echo '<a href="'.$_my_uri.'collapse='.$content['content_id'].'">'."\n";
1031 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";
1036 // 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";
1037 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";
1040 echo '<a href="'.$_my_uri.'expand='.$content['content_id'].'">'."\n";
1041 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.'); " />';
1047 /* doesn't have children */
1048 if ($counter == $num_items) {
1049 for ($i=0; $i<$depth; $i++) {
1050 if ($children[$i] == 1) {
1051 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_vertline.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1053 echo '<img src="'.$_base_path.'images/clr.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1056 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_end.gif" alt="" border="0" class="img-size-tree" />'."\n";
1058 for ($i=0; $i<$depth; $i++) {
1059 if ($children[$i] == 1) {
1060 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_vertline.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1062 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_space.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1065 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_split.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1067 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_horizontal.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />'."\n";
1070 // if ($_SESSION['prefs']['PREF_NUMBERING']) {
1071 // echo $path.$counter;
1076 echo "\n<br /></span>\n\n";
1078 if ( $ignore_state || (isset($_SESSION['menu'][$content['content_id']]) && $_SESSION['menu'][$content['content_id']] == 1)) {
1082 $this->printMenu($content['content_id'],
1097 // if ($parent_id <> 0) print "</li>\n\n";
1102 /* @See include/html/editor_tabs/properties.inc.php
1103 @See editor/arrange_content.php
1104 $print_type: "movable" or "related_content"
1106 function printActionMenu($menu, $parent_id, $depth, $path, $children, $print_type = 'movable') {
1108 global $cid, $_my_uri, $_base_path, $rtl;
1112 $top_level = $menu[$parent_id];
1114 if ( is_array($top_level) ) {
1116 $num_items = count($top_level);
1117 foreach ($top_level as $current_num => $content) {
1118 if (isset($content['test_id'])){
1122 $link = $buttons = '';
1126 if ($print_type == 'movable')
1128 if ($content['content_id'] == $_POST['moved_cid']) {
1129 $radio_selected = ' checked="checked" ';
1132 $radio_selected = '';
1135 $buttons = '<td>'."\n".
1137 ' <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";
1139 if ($current_num + 1 == count($top_level))
1140 $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";
1142 $buttons .= ' </small>'."\n".
1146 if ($content['content_type'] == CONTENT_TYPE_FOLDER)
1147 $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']).'" />';
1149 $buttons .= ' ';
1151 $buttons .= '</td>'."\n".
1152 '<td><input name="moved_cid" value="'.$content['content_id'].'" type="radio" id="r'.$content['content_id'].'" '.$radio_selected .'/></td>'."\n";
1155 $buttons .= '<td>'."\n";
1156 if ($print_type == "related_content")
1158 if ($content['content_type'] == CONTENT_TYPE_CONTENT || $content['content_type'] == CONTENT_TYPE_WEBLINK)
1160 $link .= '<input type="checkbox" name="related[]" value="'.$content['content_id'].'" id="r'.$content['content_id'].'" ';
1161 if (isset($_POST['related']) && in_array($content['content_id'], $_POST['related'])) {
1162 $link .= ' checked="checked"';
1164 $link .= ' />'."\n";
1168 if ($content['content_type'] == CONTENT_TYPE_FOLDER)
1170 $link .= '<img src="'.$_base_path.'images/folder.gif" />';
1172 $link .= ' <label for="r'.$content['content_id'].'">'.$content['title'].'</label>'."\n";
1174 if ( is_array($menu[$content['content_id']]) && !empty($menu[$content['content_id']]) ) {
1177 for ($i=0; $i<$depth; $i++) {
1178 if ($children[$i] == 1) {
1181 if ($end && ($i==0)) {
1182 echo '<img src="'.$_base_path.'images/clr.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />';
1184 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_vertline.gif" alt="" border="0" width="16" height="16" />';
1187 echo '<img src="'.$_base_path.'images/clr.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />';
1191 if (($counter == $num_items) && ($depth > 0)) {
1192 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_end.gif" alt="" border="0" width="16" height="16" />';
1193 $children[$depth] = 0;
1196 if (($num_items == $counter) && ($parent_id == 0)) {
1197 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_end.gif" alt="" border="0" width="16" height="16" />';
1200 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_split.gif" alt="" border="0" width="16" height="16" />';
1202 $children[$depth] = 1;
1205 if ($_SESSION['s_cid'] == $content['content_id']) {
1206 if (is_array($menu[$content['content_id']])) {
1207 $_SESSION['menu'][$content['content_id']] = 1;
1211 if ($_SESSION['menu'][$content['content_id']] == 1) {
1212 echo '<img src="'.$_base_path.'images/tree/tree_disabled.gif" alt="'._AT('toggle_disabled').'" border="0" width="16" height="16" title="'._AT('toggle_disabled').'" />';
1215 echo '<img src="'.$_base_path.'images/tree/tree_disabled.gif" alt="'._AT('toggle_disabled').'" border="0" width="16" height="16" title="'._AT('toggle_disabled').'" />';
1219 /* doesn't have children */
1220 if ($counter == $num_items) {
1223 for ($i=0; $i<$depth; $i++) {
1224 if ($children[$i] == 1) {
1225 if ($end && ($i == 0)) {
1226 echo '<img src="'.$_base_path.'images/clr.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />';
1228 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_vertline.gif" alt="" border="0" width="16" height="16" />';
1231 echo '<img src="'.$_base_path.'images/clr.gif" alt="" border="0" width="16" height="16" class="img-size-tree" />';
1237 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_end.gif" alt="" border="0" />';
1242 for ($i=0; $i<$depth; $i++) {
1243 if ($children[$i] == 1) {
1244 if ($end && !$print) {
1246 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_space.gif" alt="" border="0" width="16" height="16" />';
1248 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_vertline.gif" alt="" border="0" width="16" height="16" />';
1251 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_space.gif" alt="" border="0" width="16" height="16" />';
1259 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_split.gif" alt="" border="0" width="16" height="16" />';
1261 echo '<img src="'.$_base_path.'images/'.$rtl.'tree/tree_horizontal.gif" alt="" border="0" width="16" height="16" />';
1264 echo '<small> '.($_SESSION['prefs']['PREF_NUMBERING'] ? $path.$counter : '');
1268 echo '</small></td>'."\n".'</tr>'."\n";
1270 $this->printActionMenu($menu,
1271 $content['content_id'],