course_search.module

  1. 7.x modules/course_search/course_search.module
  2. 6.x modules/course_search/course_search.module
  3. 5.x modules/course_search/course_search.module

This module allows users to search for courses, descriptions, and, if supported, rotation schedules and sample syllabi.

File

modules/course_search/course_search.module
View source
  1. <?php
  2. /**
  3. * @file
  4. * This module allows users to search for courses, descriptions, and, if supported, rotation schedules
  5. * and sample syllabi.
  6. */
  7. function course_search_menu() {
  8. $items = array();
  9. $items["tools/course-search"] = array(
  10. "title" => "Course Search",
  11. "description" => "Use this tool to view course descriptions, sample syllabi, and projected course offering schedules.",
  12. "page_callback" => "course_search_display_search",
  13. "access_arguments" => array('access_course_search'),
  14. "page_settings" => array(
  15. "page_hide_report_error" => TRUE,
  16. "target" => "_blank",
  17. "menu_icon" => fp_get_module_path('course_search') . "/icons/book_go.png",
  18. ),
  19. "type" => MENU_TYPE_NORMAL_ITEM,
  20. );
  21. $items["course-search/get-syllabus"] = array(
  22. "title" => "Course Search",
  23. "page_callback" => "course_search_download_syllabus",
  24. "access_arguments" => array('access_course_search'),
  25. "type" => MENU_TYPE_CALLBACK,
  26. );
  27. $items["admin/config/course-search"] = array(
  28. "title" => "Course Search settings",
  29. "description" => "Administer the Course Search module's settings",
  30. "page_callback" => "fp_render_form",
  31. "page_arguments" => array("course_search_settings_form", "system_settings"),
  32. "access_arguments" => array("administer_course_search"),
  33. "page_settings" => array(
  34. "page_hide_report_error" => TRUE,
  35. "menu_icon" => fp_get_module_path('course_search') . "/icons/book_go.png",
  36. "menu_links" => array(
  37. 0 => array(
  38. "text" => "Admin Console",
  39. "path" => "admin-tools/admin",
  40. "query" => "de_catalog_year=%DE_CATALOG_YEAR%",
  41. ),
  42. ),
  43. ),
  44. "type" => MENU_TYPE_NORMAL_ITEM,
  45. );
  46. $items["tools/course-search/courses"] = array(
  47. "title" => "Course Search",
  48. "page_callback" => "course_search_display_courses",
  49. "access_arguments" => array('access_course_search'),
  50. "page_settings" => array(
  51. "page_hide_report_error" => TRUE,
  52. ),
  53. "type" => MENU_TYPE_CALLBACK,
  54. );
  55. $items["tools/course-search/edit-list"] = array(
  56. "title" => "Update Course Information",
  57. "page_callback" => "course_search_display_edit_courses",
  58. "access_arguments" => array("can_update_course_info_details"),
  59. "page_settings" => array(
  60. "menu_links" => array(
  61. 0 => array(
  62. "text" => "Back to Course Search",
  63. "path" => "tools/course-search",
  64. ),
  65. ),
  66. ),
  67. "file" => menu_get_module_path("course_search") . "/course_search.edit.inc",
  68. "type" => MENU_TYPE_CALLBACK,
  69. );
  70. $items["tools/course-search/edit-info-details"] = array(
  71. "title" => "Edit Course Info Details",
  72. "page_callback" => "fp_render_form",
  73. "page_arguments" => array("course_search_edit_course_details_form"),
  74. "access_arguments" => array("can_update_course_info_details"),
  75. "page_settings" => array(
  76. "menu_links" => array(
  77. 0 => array(
  78. "text" => "Back to Course Search",
  79. "path" => "tools/course-search",
  80. ),
  81. 1 => array(
  82. "text" => "Back to Course Edit List",
  83. "path" => "tools/course-search/edit-list",
  84. "query" =>"school_id=%SCHOOL_ID%",
  85. ),
  86. ),
  87. ),
  88. "file" => menu_get_module_path("course_search") . "/course_search.edit.inc",
  89. "type" => MENU_TYPE_CALLBACK,
  90. );
  91. return $items;
  92. }
  93. /**
  94. * Implements hook
  95. */
  96. function course_search_menu_handle_replacement_pattern($str) {
  97. if (strpos($str, "%SCHOOL_ID%") !== 0) {
  98. if (!isset($_SESSION['last_saved_school_id'])) $_SESSION['last_saved_school_id'] = 0;
  99. // It contains this replacement pattern!
  100. $str = str_replace("%SCHOOL_ID%", intval($_SESSION['last_saved_school_id']), $str);
  101. unset($_SESSION['last_saved_school_id']);
  102. }
  103. if (strpos($str, "%SEV_FILTER%") !== 0) {
  104. // It contains this replacement pattern!
  105. $str = str_replace("%SEV_FILTER%", (@$_GET["sev_filter"] OR ""), $str);
  106. }
  107. if (strpos($str, "%TYPE_FILTER%") !== 0) {
  108. // It contains this replacement pattern!
  109. $str = str_replace("%TYPE_FILTER%", (@$_GET["type_filter"] OR ""), $str);
  110. }
  111. if (strpos($str, "%PAGE%") !== 0) {
  112. // It contains this replacement pattern!
  113. $str = str_replace("%PAGE%", (@$_GET["page"] OR ""), $str);
  114. }
  115. return $str;
  116. }
  117. function course_search_perm() {
  118. return array(
  119. "access_course_search" => array(
  120. 'title' => t('Access course search'),
  121. 'description' => t('Users with this setting are allowed to actually view the course search link,
  122. descriptions, syllabi, etc.'),
  123. ),
  124. "administer_course_search" => array(
  125. "title" => t("Administer course search"),
  126. "description" => t("Users with this setting will be able
  127. to modify settings for the Course Search module."),
  128. ),
  129. "can_update_course_info_details" => array(
  130. "title" => t("Can update course info details"),
  131. "description" => t("Allows users to update the 'course info' details,
  132. like the course's sample syllabus and rotation
  133. schedule."),
  134. ),
  135. );
  136. }
  137. /**
  138. * The system settins form for course_search settings.
  139. */
  140. function course_search_settings_form($school_id = 0) {
  141. $form = array();
  142. $school_id = intval($school_id);
  143. $fs = ""; // The field name suffix. We will add this to the end of all of our field names. If this is the default school, leave blank.
  144. if (module_enabled("schools")) {
  145. $school_name = schools_get_school_name_for_id($school_id);
  146. fp_set_title(t("Configure %school Course Search settings", array('%school' => $school_name)));
  147. if ($school_id !== 0) {
  148. $fs = "~~school_" . $school_id;
  149. }
  150. }
  151. $form['school_id'] = array(
  152. 'type' => 'hidden',
  153. 'value' => $school_id,
  154. );
  155. $form["course_search_avail_term_id_suffix_order" . $fs] = array(
  156. "type" => "textfield",
  157. "label" => t("Available Term ID Suffixes & Order"),
  158. "value" => variable_get_for_school("course_search_avail_term_id_suffix_order", "", $school_id, TRUE),
  159. "description" => t("Enter the order of term ID suffixes, so that they will display
  160. in the correct order in the table of available course
  161. offerings. Separate by comma.") . "
  162. <br>
  163. Ex: 60, 40, 41, 80, 81, mm",
  164. );
  165. $form["course_search_avail_term_headers" . $fs] = array(
  166. "type" => "textfield",
  167. "label" => t("Available Term Table Headers"),
  168. "value" => variable_get_for_school("course_search_avail_term_headers", "", $school_id, TRUE),
  169. "description" => t("Enter the table headers for the available table, in the same
  170. order as the suffix order above.") . "
  171. <br>
  172. Ex: Spring, May, Summer 1, Summer 2, Fall, Winter",
  173. );
  174. // TODO: I am not sure this is even used anymore. If not, get rid of it.
  175. $form["course_search_avail_term_mobile_headers" . $fs] = array(
  176. "type" => "textfield",
  177. "label" => t("Available Term Mobile Table Headers"),
  178. "value" => variable_get_for_school("course_search_avail_term_mobile_headers", "", $school_id, TRUE),
  179. "description" => t("Enter the table headers for the available table, in the same
  180. order as the suffix order above, as it should be displayed on
  181. a mobile device (with a smaller screen).") . "
  182. <br>
  183. Ex: Spr, May, Sum1, Sum2, Fall, Win",
  184. );
  185. return $form;
  186. }
  187. /**
  188. * This function will actually deliver a syllabus to the user's browser
  189. * for download.
  190. *
  191. */
  192. function course_search_download_syllabus() {
  193. // Get our global variables...
  194. $id = trim($_REQUEST["id"]);
  195. $db = get_global_database_handler();
  196. $query = "select * from course_syllabi
  197. where course_id = ? ";
  198. $params = array($id);
  199. $res = db_query($query, $params);
  200. $cur = db_fetch_array($res);
  201. $filename = $cur["filename"];
  202. $course_id = $cur["course_id"];
  203. $school_id = $db->get_school_id_for_course_id($course_id);
  204. // Get the latest subject_id and course_num for this course!
  205. $new_course = new Course();
  206. $new_course->course_id = $course_id;
  207. $new_course->school_id = $school_id;
  208. $new_course->catalog_year = variable_get_for_school("current_catalog_year", 2006, $school_id);
  209. $new_course->load_descriptive_data(false, false, true);
  210. $subject_id = $new_course->subject_id;
  211. $course_num = $new_course->course_num;
  212. $files_path = $GLOBALS["fp_system_settings"]["file_system_path"];
  213. if ($filename == "" || !file_exists("$files_path/custom/files/syllabi/$filename"))
  214. { // Check to make sure the src file actually exists.
  215. // Display a message, letting the user know it does not
  216. // exist.
  217. watchdog("syllabus", "fail,$course_id", array(), WATCHDOG_ERROR);
  218. fp_add_message(t("Sorry, the syllabus for @course could not be found.", array("@course" => "$subject_id $course_num")));
  219. // Just so admins can see:
  220. fpm("Admin: file path attempted: $files_path/custom/files/syllabi/$filename");
  221. return;
  222. }
  223. watchdog("syllabus", "get,$course_id");
  224. $content_type = "application/plain"; // default, save as generic binary file.
  225. $temp = explode("\.", $filename);
  226. $ext = $temp[count($temp) - 1]; // get the original file extension.
  227. // attempt to match to the correct content_type...
  228. if ($ext == "pdf"){ $content_type = "application/pdf"; }
  229. if ($ext == "doc") { $content_type = "application/msword"; }
  230. if ($ext == "docx") { $content_type = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; }
  231. if ($ext == "txt") { $content_type = "text/plain"; }
  232. if ($ext == "pot") { $content_type = "application/mspowerpoint"; }
  233. if ($ext == "ppt") { $content_type = "application/powerpoint"; }
  234. if (strstr($ext,"xl")) { $content_type = "application/excel"; }
  235. $fn = urlencode($subject_id . "_" . $course_num . "_SAMPLE_SYLLABUS") .".$ext"; // make it a safe filename.
  236. $fn = str_replace("+"," ",$fn); // restore spaces from + symbols...
  237. // Give it to the browser!
  238. header('Content-type: ' . $content_type . '');
  239. header('Content-Disposition: attachment; filename="' . $fn . '"');
  240. readfile("$files_path/custom/files/syllabi/" . $filename . "");
  241. die;
  242. }
  243. /**
  244. * Show the user their select of courses.
  245. */
  246. function course_search_display_courses() {
  247. $rtn = "";
  248. fp_add_css(fp_get_module_path("course_search") . "/css/course_search_style.css");
  249. fp_set_title('');
  250. $mode = "";
  251. // We are going to be setting up a render array for this screen, so other modules can alter it later.
  252. $render = array();
  253. $render["#id"] = "course_search_display_courses";
  254. $school_id = intval(@$_REQUEST["school_id"]);
  255. $current_catalog_year = variable_get_for_school("current_catalog_year",'', $school_id);
  256. // catalog_year is always just whatever the current year is.
  257. $catalog_year = $current_catalog_year;
  258. $subject_id = fp_trim(@$_REQUEST["subject_id"]);
  259. $render["#catalog_year"] = $catalog_year;
  260. $render["#school_id"] = $school_id;
  261. $render["#subject_id"] = $subject_id;
  262. $clean_urls = variable_get("clean_urls", FALSE);
  263. // Try to find out the title to this subject, if one exists
  264. // in our subjects table.
  265. $title = "";
  266. $res = db_query("SELECT * FROM subjects
  267. WHERE subject_id =?
  268. AND school_id = ? ", $subject_id, $school_id);
  269. $cur = db_fetch_array($res);
  270. if ($cur) {
  271. $title = $cur["title"];
  272. }
  273. if ($title == "") $title = strip_tags($subject_id);
  274. //$rtn .= t("Current catalog year:") . " <b>$catalog_year-" . ($catalog_year +1) . "</b>
  275. // ";
  276. if (module_enabled("schools")) {
  277. $render['selected_school_name'] = array(
  278. 'value' => "<div class='current-school'>" . t("Current school: ") . "<strong>" . schools_get_school_name_for_id($school_id) . "</strong>
  279. - " . l(t("Change?"), "tools/course-search") . "</div>",
  280. );
  281. }
  282. $render["current_cat_year"] = array(
  283. "value" => "<div class='current-cat-year-line'>" . t("Current catalog year:") . " <strong>$catalog_year-" . ($catalog_year +1) . "</strong></div>",
  284. );
  285. $render["subject_title"] = array(
  286. "value" => "<div class='subject-title'><h2>$title</h2></div>",
  287. );
  288. // Draw the term selector.
  289. $h_subject_id = htmlentities($subject_id);
  290. $html = "";
  291. $only_term = @strip_tags($_REQUEST["only_term"]);
  292. $html .= "<form id='term_form' action='" . fp_url("tools/course-search/courses") . "' method='GET'>
  293. <input type='hidden' name='mode' value='$h_subject_id'>
  294. <input type='hidden' name='subject_id' value='$h_subject_id'>
  295. <input type='hidden' name='school_id' value='$school_id'>
  296. ";
  297. if (!$clean_urls) {
  298. // Hack for if clean URLs isn't enabled
  299. $html .= "<input type='hidden' name='q' value='tools/course-search/courses'>";
  300. }
  301. $html .= "
  302. View courses offered:
  303. <select name='only_term' onChange='document.getElementById(\"term_form\").submit();'>
  304. <option value=''>Any term</option>
  305. ";
  306. $term_array = csv_to_array(variable_get_for_school("course_search_avail_term_id_suffix_order", '', $school_id));
  307. $schedule_text = "";
  308. for ($t = $catalog_year; $t <= $catalog_year + 4; $t++)
  309. {
  310. $html .= "<option value=''>---------------------</option>";
  311. foreach($term_array as $x)
  312. {
  313. $schedule_text .= "<td class='tenpt' align='center'>";
  314. $the_term_id = $t . $x;
  315. $temp_course = new Course();
  316. $temp_course->term_id = $the_term_id;
  317. $term_desc = $temp_course->get_term_description(false);
  318. $sel = "";
  319. if ($only_term != "" && $only_term == "$the_term_id") {
  320. $sel = " selected";
  321. }
  322. $html .= "<option value='$the_term_id' $sel>$term_desc</option> \n";
  323. }
  324. }
  325. $html .= "
  326. </select>
  327. </form>";
  328. $render["term_selector_form"] = array(
  329. "value" => $html,
  330. );
  331. if ($only_term != "") {
  332. $temp_course = new Course();
  333. $temp_course->term_id = $only_term;
  334. $term_desc = $temp_course->get_term_description(false);
  335. $render["term_selected_only_term"] = array(
  336. "value" => "<div style='font-weight: bold; padding-bottom: 20px;'>
  337. " . t("The following courses are currently scheduled to be offered during @termdesc", array("@termdesc" => $term_desc)) . "
  338. </div>",
  339. );
  340. }
  341. $term_structures = get_term_structures($school_id);
  342. $grad_notice_flag = false;
  343. $temp_course = new Course();
  344. $result = db_query("SELECT * FROM courses
  345. WHERE catalog_year = ?
  346. AND subject_id = ?
  347. AND exclude = 0
  348. AND delete_flag = 0
  349. AND school_id = ?
  350. ORDER BY course_num ", $catalog_year, $subject_id, $school_id);
  351. if ($result)
  352. {
  353. while ($cur = db_fetch_array($result))
  354. {
  355. $n_subject_id = trim($cur["subject_id"]);
  356. $n_course_num = trim($cur["course_num"]);
  357. $n_course_id = $cur["course_id"];
  358. $n_school_id = $cur['school_id'];
  359. $bool_hide = FALSE;
  360. $title = trim($cur["title"]);
  361. $title = $temp_course->fix_title($title);
  362. $description = trim($cur["description"]);
  363. if ($description == "") {
  364. $description = t("No description is available at this time. Consult
  365. the official course catalog for listings.");
  366. }
  367. $syllabus_text = "";
  368. $syllabus_array = course_search_get_course_syllabus_details($n_course_id);
  369. if (@$syllabus_array["url"] != "")
  370. {
  371. $syllabus_text = "<div class='course-search-sample-syllabus'>
  372. <a href='{$syllabus_array["url"]}' class='nounderline'>
  373. <i class='fa fa-file-text-o'></i>
  374. " . t("Sample Syllabus") . "</a>
  375. </div>
  376. ";
  377. }
  378. // Look for all 5 years.
  379. $long_schedule_array = course_search_get_course_rotation_schedule($n_course_id, $catalog_year, 100, TRUE);
  380. $schedule_array = course_search_get_course_rotation_schedule($n_course_id, $catalog_year);
  381. $full_schedule_array = course_search_get_course_rotation_schedule($n_course_id);
  382. $schedule_text = "";
  383. if (count($long_schedule_array) > 0) {
  384. $schedule_text .= "
  385. <div>
  386. <b>" . t("Anticipated availability:", array("@cat" => $catalog_year)) . "</b>
  387. ";
  388. $s_disp = "auto";
  389. if ($mode != "advanced")
  390. { // only show this in the basic mode, not advanced.
  391. foreach ($schedule_array as $term_id)
  392. {
  393. $temp_course = new Course();
  394. $temp_course->term_id = $term_id;
  395. $schedule_text .= " " . $temp_course->get_term_description(true) . ",";
  396. }
  397. $schedule_text = substr($schedule_text, 0, -1); // take off comma.
  398. $rnd_div_id = sha1(rand(1,999999) . time());
  399. $schedule_text .= "
  400. &nbsp; | &nbsp;
  401. <a href='javascript: toggleHideDiv(\"$rnd_div_id\");' class='nounderline'>
  402. <span id='SPAN$rnd_div_id'>
  403. " . t("more&raquo;") . "
  404. </span></a> ";
  405. $s_disp = "none";
  406. }
  407. // Consult our settings to find out what order our terms should be in.
  408. $term_array = csv_to_array(variable_get_for_school("course_search_avail_term_id_suffix_order", '', $school_id));
  409. // Get our table headers
  410. $avail_headers = variable_get_for_school("course_search_avail_term_headers", '', $school_id);
  411. $avail_mobile_headers = variable_get_for_school("course_search_avail_term_mobile_headers", '', $school_id);
  412. $th = explode(",", $avail_headers);
  413. $twidth = "90%";
  414. $mleft = "20px;";
  415. $schedule_text .= "
  416. </div>
  417. <div id='$rnd_div_id' style='display: $s_disp; margin-left: $mleft;'>
  418. <table border='1' width='$twidth' class='fp-course-search-avail'>
  419. <tr>
  420. <td>" . t("Year") . "</td>
  421. ";
  422. foreach ($th as $header_text) {
  423. $schedule_text .= "<td>" . trim($header_text) . "</td>";
  424. }
  425. $schedule_text .= " </tr>";
  426. for ($t = $catalog_year; $t <= $catalog_year + 4; $t++)
  427. {
  428. $schedule_text .= "<tr>
  429. <td class='tenpt' align='center'>
  430. <b>$t</b>
  431. </td>";
  432. foreach($term_array as $x)
  433. {
  434. $schedule_text .= "<td class='tenpt' align='center'>";
  435. $the_term_id = $t . $x;
  436. // Does the term suffix ($x) call for the year to be
  437. // subtracted by 1, or modified at all? This is the case at ULM for fall.
  438. // Ex: 201340 is Fall of *2012*, not 2013.
  439. // We can tell this because the term structure (from admin settings)
  440. if (strtoupper(@$term_structures[$x]["disp_adjust"] ?? '') == "[Y-1]" || strtoupper(@$term_structures[$x]["disp_adjust"] ?? '') == "[Y4-1]") {
  441. // It is subtracted by one. So the year for "XYZ of 2016" is actually recorded as 2017xyz
  442. $the_term_id = ($t + 1) . $x;
  443. }
  444. if (strtoupper(@$term_structures[$x]["disp_adjust"] ?? '') == "[Y+1]" || strtoupper(@$term_structures[$x]["disp_adjust"] ?? '') == "[Y4+1]") {
  445. // It is added by one. So the year for "XYZ of 2016" is actually recorded as 2015xyz
  446. $the_term_id = ($t - 1) . $x;
  447. }
  448. if (in_array($the_term_id, $full_schedule_array))
  449. {
  450. $schedule_text .= "<img src='" . fp_theme_location() . "/images/small_check.gif'>";
  451. }
  452. else {
  453. if ($only_term != "" && $only_term == $the_term_id) {
  454. // Meaning, the term that the user selected is NOT in this
  455. // course's schedule. So, we should hide it.
  456. $bool_hide = TRUE;
  457. }
  458. }
  459. $schedule_text .= "&nbsp;</td>";
  460. }
  461. $schedule_text .= "</tr>";
  462. }
  463. $schedule_text .= "
  464. </table>
  465. </div>
  466. ";
  467. }
  468. else if ($only_term != "") {
  469. // This is if there are NO schedule offerings, yet the user
  470. // selected to view a particular term.
  471. $bool_hide = TRUE;
  472. }
  473. if (course_search_get_course_rotation_schedule_not_anticipated($n_course_id))
  474. {
  475. // This course has no anticipated offerings!
  476. $schedule_text = "<div><b>" . t("Anticipated availability:") . "</b>
  477. " . t("There are no anticipated course offerings
  478. at this time.") . "</div>";
  479. if ($only_term != "") $bool_hide = TRUE;
  480. }
  481. $min_hours = trim($cur["min_hours"]*1);
  482. $max_hours = trim($cur["max_hours"]*1);
  483. if ($min_hours == $max_hours)
  484. {
  485. $hours = $min_hours;
  486. } else {
  487. $hours = "$min_hours to $max_hours";
  488. }
  489. $repeat = "";
  490. if (trim($cur["repeat_hours"]*1) > $min_hours)
  491. {
  492. $repeat = "<div class='course-search-repeat'>" . t("May be repeated for up to @repeat hours of credit.", array("@repeat" => $cur["repeat_hours"]*1)) . "</div>";
  493. if (trim($cur["repeat_hours"]*1) > 20) {
  494. $repeat = "<div class='course-search-repeat'>" . t("May be repeated for credit.") . "</div>";
  495. }
  496. }
  497. // Draw it on screen...
  498. if ($bool_hide != true) {
  499. $details = $schedule_text . $syllabus_text;
  500. $hyp1 = " - ";
  501. $on_click = "";
  502. $html = "";
  503. // Note, the HTML comments are so other modules, that wish to manipulate this block, have something easy to find/replace
  504. $html .= "<div class='course-search-course-block'>
  505. <!-- TITLE-ROW -->
  506. <div class='course-search-course-title-row'
  507. $on_click>
  508. <!-- COURSE-NAME -->
  509. <span class='course-search-course-name'>$n_subject_id $n_course_num</span>
  510. $hyp1
  511. <!-- END-COURSE-NAME ->
  512. <!-- COURSE-TITLE -->
  513. <span class='course-search-course-title'>$title</span> - $hours " . t("hrs.") . "$repeat
  514. <!-- END-COURSE-TITLE -->
  515. </div>
  516. <!-- END-TITLE-ROW -->
  517. <!-- COURSE-EXTRA -->
  518. <div class='course-search-course-extra'>
  519. <!-- DESC -->
  520. <div class='course-search-course-description'>$description</div>
  521. <!-- END-DESC -->
  522. <!-- DETAILS -->
  523. <div class='course-search-course-details'>$details</div>
  524. <!-- END-DETAILS -->
  525. ";
  526. $html .= "</div>
  527. <!-- END-COURSE-EXTRA -->"; // div course-search-course-extra
  528. $html .= "</div>"; // div course-search-course-block
  529. $render["course_search_course_block__$n_course_id"] = array(
  530. "value" => $html,
  531. );
  532. }
  533. }
  534. }
  535. watchdog("course_search", "User viewed courses in subject: @subject", array("@subject" => $subject_id));
  536. //$pC .= $screen->get_java_script_code();
  537. $html = '
  538. <script type="text/javascript">
  539. function toggleHideDiv(rndDivID)
  540. {
  541. var d = document.getElementById(rndDivID);
  542. if (d.style.display == "none")
  543. {
  544. d.style.display = "";
  545. document.getElementById("SPAN" + rndDivID).innerHTML = "&laquo;less";
  546. } else {
  547. d.style.display = "none";
  548. document.getElementById("SPAN" + rndDivID).innerHTML = "more&raquo;";
  549. }
  550. }
  551. function toggleCourseExtra(e) {
  552. $(e).siblings(".course-search-course-extra").slideToggle("medium");
  553. }
  554. </script>
  555. ';
  556. $render["extra_javascript"] = array(
  557. "value" => $html,
  558. );
  559. $rtn .= fp_render_content($render);
  560. // Let's set our breadcrumbs
  561. $crumbs = array();
  562. $crumbs[] = array(
  563. 'text' => 'Courses',
  564. 'path' => 'tools/course-search',
  565. );
  566. fp_set_breadcrumbs($crumbs);
  567. return $rtn;
  568. }
  569. function course_search_get_course_rotation_schedule_not_anticipated($course_id)
  570. {
  571. $rtn = FALSE;
  572. // Returns TRUE if not is NOT ANTICIPATED. False, if this
  573. // is a normal courses which has an offering, or a blank
  574. // offering. This will
  575. // only return true if NOTA is set as a term for this course.
  576. $res = db_query("SELECT * FROM course_rotation_schedule
  577. WHERE course_id = '?'
  578. AND term_id = 'NOTA'
  579. ", $course_id);
  580. if (db_num_rows($res) > 0) {
  581. $rtn = TRUE;
  582. }
  583. //////////////////////////////////////
  584. // Okay, now we invoke a hook, to see if any other modules
  585. // would like to add or alter our answer
  586. invoke_hook("course_search_get_course_rotation_schedule_not_anticipated", array(&$rtn, $course_id));
  587. return $rtn;
  588. }
  589. function course_search_get_course_capacity($course_id, $term_id) {
  590. // Return from cache if we already have it.
  591. if (isset($GLOBALS['fp_cache_course_capacity'][$course_id])) {
  592. return $GLOBALS['fp_cache_course_capacity'][$course_id];
  593. }
  594. $cap = db_result(db_query("SELECT capacity FROM course_rotation_schedule
  595. WHERE course_id = ?
  596. AND term_id = ?", array($course_id, $term_id)));
  597. $cap = intval($cap);
  598. $GLOBALS['fp_cache_course_capacity'][$course_id] = $cap; // save to simple globals cache
  599. return $cap;
  600. }
  601. function course_search_get_course_rotation_schedule($course_id, $year = 0, $limit = 20, $bool_include_next_five_years = FALSE)
  602. {
  603. // Has this already been saved to our globals cache? If so, just return that.
  604. if (isset($GLOBALS['cache_course_search_rotation_schedule'][$course_id][$year][$limit][intval($bool_include_next_five_years)])) {
  605. return $GLOBALS['cache_course_search_rotation_schedule'][$course_id][$year][$limit][intval($bool_include_next_five_years)];
  606. }
  607. $year = intval($year);
  608. $limit = intval($limit);
  609. // return an array containing the terms that this course
  610. // is going to be offered, if any.
  611. $rtn_array = array();
  612. $arr = array();
  613. $year_line = "";
  614. if ($year !== 0)
  615. { // if a year is entered, we will get the next few years, and the previous
  616. // one for good measure.
  617. $year_line = "and (`term_id` LIKE '$year%' or `term_id` LIKE '" . ($year+1) . "%') ";
  618. if ($bool_include_next_five_years)
  619. {
  620. $yearm1 = $year - 1;
  621. $year2 = $year + 1;
  622. $year3 = $year + 2;
  623. $year4 = $year + 3;
  624. $year5 = $year + 4;
  625. $year6 = $year + 5;
  626. $year_line = "and (`term_id` LIKE '$year%'
  627. or `term_id` LIKE '$yearm1%'
  628. or `term_id` LIKE '$year2%'
  629. or `term_id` LIKE '$year3%'
  630. or `term_id` LIKE '$year4%'
  631. or `term_id` LIKE '$year5%'
  632. or `term_id` LIKE '$year6%'
  633. ) ";
  634. }
  635. }
  636. $res = db_query("SELECT * FROM course_rotation_schedule
  637. WHERE course_id = ?
  638. $year_line
  639. ORDER BY term_id DESC
  640. LIMIT $limit", array($course_id));
  641. while($cur = db_fetch_array($res))
  642. {
  643. $t = $cur["term_id"];
  644. // Get the term from the end.
  645. $ss = trim(substr($t,4,1));
  646. if ($ss == "m"){$ss = "1.5";}
  647. if (is_numeric($ss)) {
  648. $ss = $ss * 10;
  649. }
  650. $year = trim(substr($t,0,4));
  651. // We do all this so we can establish an order to the terms
  652. // by using a sort() command later.
  653. $arr[] = $year . "~" . $ss . "~" . $t;
  654. }
  655. sort($arr);
  656. // Now we want to get out JUST the terms...
  657. foreach($arr as $line)
  658. {
  659. $temp = explode("~",$line);
  660. $rtn_array[] = trim($temp[2]);
  661. }
  662. //////////////////////////////////////
  663. // Okay, now we invoke a hook, to see if any other modules
  664. // would like to add or alter our rotation schedule (notice $rtn_array is passed by reference)
  665. invoke_hook("course_search_get_course_rotation_schedule", array(&$rtn_array, $course_id, $year, $limit, $bool_include_next_five_years));
  666. // Save to globals cache to make it faster lookup
  667. $GLOBALS['cache_course_search_rotation_schedule'][$course_id][$year][$limit][intval($bool_include_next_five_years)] = $rtn_array;
  668. return $rtn_array;
  669. }
  670. function course_search_get_course_syllabus_details($course_id)
  671. {
  672. // This will return an array containing information
  673. // about a course's syllabus, if it exists.
  674. $rtn_array = FALSE;
  675. // Does this course have a syllabus?
  676. $query = "SELECT * FROM course_syllabi
  677. WHERE course_id = ? ";
  678. $res = db_query($query, $course_id);
  679. $cur = db_fetch_array($res);
  680. if (isset($cur["filename"]) && $cur['filename'] != "") {
  681. $rtn_array = array();
  682. $rtn_array["url"] = $GLOBALS["fp_system_settings"]["base_url"] . "/" . fp_url("course-search/get-syllabus", "id=" . $course_id, FALSE);
  683. $rtn_array["filename"] = $cur["filename"];
  684. $rtn_array["posted"] = $cur["posted"];
  685. }
  686. return $rtn_array;
  687. }
  688. function course_search_select_school_form() {
  689. $form = array();
  690. $options = schools_get_schools_for_fapi(TRUE, FALSE); // we don't need special permissions to view.
  691. $form['school_id'] = array(
  692. 'type' => 'select',
  693. 'label' => t('Please begin by selecting a school:'),
  694. 'options' => $options,
  695. 'value' => @$_REQUEST['school_id'],
  696. 'hide_please_select' => TRUE,
  697. 'required' => TRUE,
  698. );
  699. $form['submit_btn'] = array(
  700. 'type' => 'submit',
  701. 'value' => t("Continue"),
  702. );
  703. return $form;
  704. }
  705. function course_search_select_school_form_submit($form, $form_state) {
  706. $values = $form_state['values'];
  707. fp_goto('tools/course-search', 'school_id=' . intval($values['school_id']));
  708. }
  709. /**
  710. * Displays the search pulldown for the user to use to find courses.
  711. */
  712. function course_search_display_search() {
  713. fp_add_css(fp_get_module_path("course_search") . "/css/course_search_style.css");
  714. // We are going to be setting up a render array for this screen, so other modules can alter it later.
  715. $render = array();
  716. $render["#id"] = "course_search_display_search";
  717. $school_id = 0;
  718. if (module_enabled("schools")) { // The schools module is enabled. We need to first ask what school we want to look at.
  719. if (!isset($_REQUEST['school_id'])) {
  720. $rtn .= fp_render_form('course_search_select_school_form');
  721. return $rtn;
  722. } // not isset school_id
  723. $school_id = intval($_REQUEST['school_id']);
  724. $render['current_school'] = array(
  725. 'value' => "<div class='current-school'>" . t("Current school: ") . "<strong>" . schools_get_school_name_for_id($school_id) . "</strong>
  726. - " . l(t("Change?"), "tools/course-search") . "</div>",
  727. 'weight' => 0,
  728. );
  729. }
  730. $clean_urls = variable_get("clean_urls", FALSE);
  731. $school_id = intval(@$_REQUEST['school_id']);
  732. $current_catalog_year = variable_get_for_school('current_catalog_year', 2006, $school_id);
  733. // catalog_year is always just whatever the current year is.
  734. $catalog_year = $current_catalog_year;
  735. $render['#school_id'] = $school_id;
  736. $render['#catalog_year'] = $catalog_year;
  737. if (user_has_permission("can_update_course_info_details")) {
  738. $html = "<div>" . t("Administrators:") . " " . l("<i class='fa fa-pencil'></i> " . t("Edit course schedules, capacity, and syllabi"), "tools/course-search/edit-list", "school_id=$school_id") . "</div>";
  739. $render['edit_course_schedules'] = array(
  740. 'value' => $html,
  741. 'weight' => 100,
  742. );
  743. }
  744. // Catalog year has been selected.
  745. $html = "<div class='current-cat-year-line'>" . t("Current catalog year: <strong>@cat</strong></div>", array('@cat' => "$catalog_year-" . ($catalog_year +1)));
  746. $render['current_catalog_line'] = array(
  747. 'value' => $html,
  748. 'weight' => 200,
  749. );
  750. $html = "";
  751. $html .= "<br><br>
  752. <label>Please select an available subject from the list below.</label>
  753. <form action='" . fp_url("tools/course-search/courses") . "' method='GET' name='mainform' id='myform'>
  754. <input type='hidden' name='school_id' value='$school_id'> ";
  755. if (!$clean_urls) {
  756. // Hack for if clean URLs isn't enabled
  757. $html .= "<input type='hidden' name='q' value='tools/course-search/courses'>";
  758. }
  759. $html .= "
  760. <div id='element-inner-wrapper-course-search-subject' class='form-element element-type-select '>
  761. <select class='course-search-subject' name='subject_id'>
  762. ";
  763. // We want to make a pull-down list of all available subjects.
  764. // Keep in mind with this join-- we may have courses who have
  765. // a subject_id, for which we don't have that subject in the subjects
  766. // table.
  767. $query = "SELECT DISTINCT b.subject_id, a.title FROM courses b LEFT JOIN subjects a
  768. ON (a.subject_id = b.subject_id)
  769. WHERE exclude = 0
  770. AND catalog_year = ?
  771. AND a.school_id = b.school_id
  772. AND b.school_id = ?
  773. ";
  774. $subjects = array();
  775. $result = db_query($query, $catalog_year, $school_id);
  776. while ($cur = db_fetch_array($result))
  777. {
  778. //fpm($cur);
  779. $title = trim($cur["title"]);
  780. $subject_id = trim($cur["subject_id"]);
  781. if ($title == "") {
  782. $title = $subject_id;
  783. }
  784. $subjects[$subject_id] = $title;
  785. }
  786. asort($subjects);
  787. foreach ($subjects as $subject_id => $title) {
  788. $html .= "<option value='$subject_id'>$title ($subject_id)</option>";
  789. }
  790. $html .= " </select>
  791. </div>
  792. <div class='course-search-buttons buttons form-element element-type-submit'>
  793. <input type='submit' value='Select'>
  794. </div>
  795. </form>";
  796. $render['selection_form'] = array(
  797. 'value' => $html,
  798. 'weight' => 300,
  799. );
  800. $rtn = fp_render_content($render);
  801. return $rtn;
  802. }

Functions