From d2b6ba704ebf74787d793b24cf78ace2699d7bf5 Mon Sep 17 00:00:00 2001 From: moodler Date: Thu, 7 Aug 2003 16:01:31 +0000 Subject: [PATCH] Another big checkin. This includes some significant cleanups to the new course categories system. The basic idea is that the categories/course browser is now unified under one system, and admin features related to that have all been moved into the browser (as little icons). I'm much happier with this as a foundation that can scale and be built upon. Still to go: - searching - paging - polishing Also in here are a lot of little cleanups around the place, such as the initial setup process. --- admin/config.php | 2 +- admin/index.php | 7 +- admin/site.html | 8 +- admin/site.php | 12 +- admin/teacher.php | 46 ++--- course/categories.php | 318 ------------------------------ course/category.php | 300 +++++++++++++++++----------- course/edit.html | 22 +-- course/edit.php | 2 +- course/index.php | 368 ++++++++++++++++++++++++++++++++--- course/lib.php | 77 ++++---- lang/en/docs/release.html | 399 +------------------------------------- lang/en/forum.php | 2 + lang/en/moodle.php | 1 + lib/datalib.php | 71 +++---- lib/db/mysql.php | 14 ++ lib/db/mysql.sql | 3 +- lib/db/postgres7.php | 15 ++ lib/db/postgres7.sql | 3 +- lib/weblib.php | 33 +++- user/edit.php | 2 +- version.php | 2 +- 22 files changed, 697 insertions(+), 1010 deletions(-) delete mode 100644 course/categories.php diff --git a/admin/config.php b/admin/config.php index 05197f75bc..d84f911fb7 100644 --- a/admin/config.php +++ b/admin/config.php @@ -71,7 +71,7 @@ } else { print_header(); print_heading($strconfigvariables); - print_simple_box(get_string("configintro"), "center"); + print_simple_box(get_string("configintro"), "center", "50%"); echo "
"; } diff --git a/admin/index.php b/admin/index.php index 7fd01bdc45..4eeb958531 100644 --- a/admin/index.php +++ b/admin/index.php @@ -359,11 +359,8 @@ if (file_exists("$CFG->dirroot/admin/$CFG->dbtype")) { $table->data[0][0] .= "

dbtype/frame.php\">".get_string("managedatabase")."

"; } - $table->data[0][1] = "

".get_string("addnewcourse")."

". - "

".get_string("assignteachers")."

". - "

".get_string("deletecourse")."

". - "

".get_string("categories")."

"; - $table->data[0][1] .= "

".get_string("coursebackup")."

"; + $table->data[0][1] = "

".get_string("coursemanagement")."

". + "

".get_string("addnewcourse")."

"; $table->data[0][1] .= "

id\">".get_string("courserestore")."

"; if ($CFG->auth == "email" || $CFG->auth == "none" || $CFG->auth == "manual") { $table->data[0][2] = "

".get_string("addnewuser")."

"; diff --git a/admin/site.html b/admin/site.html index a013c47915..2c4dadcc30 100644 --- a/admin/site.html +++ b/admin/site.html @@ -54,28 +54,28 @@ -

: +

: () -

: +

: () -

: +

: () -

: +

: () diff --git a/admin/site.php b/admin/site.php index b2c4ec9c41..93ea4fc40f 100644 --- a/admin/site.php +++ b/admin/site.php @@ -31,7 +31,7 @@ if ($newid = insert_record("course", $form)) { $cat->name = get_string("miscellaneous"); if (insert_record("course_categories", $cat)) { - redirect("$CFG->wwwroot/", get_string("changessaved")); + redirect("$CFG->wwwroot/$CFG->admin/index.php", get_string("changessaved")); } else { error("Serious Error! Could not set up a default course category!"); } @@ -61,7 +61,10 @@ $form->id = ""; $form->category = 0; $form->format = "social"; - $form->newsitems = 0; + $form->teacher = get_string("defaultcourseteacher"); + $form->teachers = get_string("defaultcourseteachers"); + $form->student = get_string("defaultcoursestudent"); + $form->students = get_string("defaultcoursestudents"); $firsttime = true; } @@ -87,7 +90,7 @@ if ($firsttime) { print_header(); print_heading($strsitesettings); - print_simple_box(get_string("configintrosite"), "center"); + print_simple_box(get_string("configintrosite"), "center", "50%"); echo "
"; } else { print_header("$site->shortname: $strsitesettings", "$site->fullname", @@ -115,9 +118,6 @@ function validate_form(&$form, &$err) { if (empty($form->shortname)) $err["shortname"] = get_string("missingshortsitename"); - if (empty($form->summary)) - $err["summary"] = get_string("missingsitedescription"); - return; } diff --git a/admin/teacher.php b/admin/teacher.php index 2c4482671c..f2bb4e498c 100644 --- a/admin/teacher.php +++ b/admin/teacher.php @@ -5,7 +5,7 @@ define("MAX_USERS_PER_PAGE", 30); - optional_variable($id); // course id + require_variable($id); // course id optional_variable($add, ""); optional_variable($remove, ""); optional_variable($search, ""); // search string @@ -21,6 +21,7 @@ } $strassignteachers = get_string("assignteachers"); + $strcourses = get_string("courses"); $stradministration = get_string("administration"); $strexistingteachers = get_string("existingteachers"); $strnoexistingteachers = get_string("noexistingteachers"); @@ -40,36 +41,6 @@ } - if (!$id) { - print_header("$site->shortname: $strassignteachers", "$site->fullname", - "$stradministration -> $strassignteachers"); - - $isadmin = isadmin(); /// cache value - $courses = get_courses(); - - print_heading(get_string("choosecourse")); - print_simple_box_start("center"); - - if (!empty($courses)) { - foreach ($courses as $course) { - if ($isadmin or isteacher($course->id, $USER->id)){ - echo "id\">$course->fullname ($course->shortname)
\n"; - $coursesfound = TRUE; - } - } - } - - print_simple_box_end(); - - if ($coursesfound == FALSE) { - print_heading(get_string("nocoursesyet")); - print_continue("../$CFG->admin/index.php"); - } - - print_footer(); - exit; - } - if (! $course = get_record("course", "id", $id)) { error("Course ID was incorrect (can't find it)"); } @@ -77,8 +48,9 @@ print_header("$site->shortname: $course->shortname: $strassignteachers", "$site->fullname", - "$stradministration -> - $strassignteachers -> $course->shortname", ""); + "$strcourses -> ". + "id\">$course->fullname -> ". + "$strassignteachers", ""); print_heading("wwwroot/course/view.php?id=$course->id\">$course->fullname ($course->shortname)"); @@ -156,7 +128,9 @@ $teacherarray = array(); foreach ($teachers as $teacher) { $teacherarray[] = $teacher->id; - echo "

$teacher->firstname $teacher->lastname, $teacher->email    id&remove=$teacher->id\" title=\"$strremoveteacher\">

"; + echo "

$teacher->firstname $teacher->lastname, $teacher->email  "; + print_user_picture($teacher->id, $site->id, $teacher->picture, false, false, false); + echo "  id&remove=$teacher->id\" title=\"$strremoveteacher\">

"; } $teacherlist = implode(",",$teacherarray); unset($teacherarray); @@ -187,7 +161,9 @@ foreach ($users as $user) { echo "

id&add=$user->id\"". "title=\"$straddteacher\">  $user->firstname $user->lastname, $user->email"; + "border=0>  "; + print_user_picture($user->id, $site->id, $user->picture, false, false, false); + echo " $user->firstname $user->lastname, $user->email"; } } diff --git a/course/categories.php b/course/categories.php deleted file mode 100644 index 668466dc8b..0000000000 --- a/course/categories.php +++ /dev/null @@ -1,318 +0,0 @@ -shortname: $strcategories", "$site->fullname", - "admin/index.php\">$stradministration -> $strcategories", - "addform.addcategory"); - - -/// If data for a new category was submitted, then add it - if ($form = data_submitted()) { - if (!empty($form->addcategory)) { - unset($newcategory); - $newcategory->name = $form->addcategory; - $newcategory->sortorder = 999; - if (!insert_record("course_categories", $newcategory)) { - notify("Could not insert the new category '$newcategory->name'"); - } else { - notify(get_string("categoryadded", "", $newcategory->name)); - } - } - } - - -/// Delete a category if necessary - - if (isset($delete)) { - if ($tempcat = get_record("course_categories", "id", $delete)) { - if (delete_records("course_categories", "id", $tempcat->id)) { - notify(get_string("categorydeleted", "", $tempcat->name)); - } - if ($children = get_records("course_categories", "parent", $tempcat->id)) { - foreach ($children as $childcat) { - if (! set_field("course_categories", "parent", $tempcat->parent, "id", $childcat->id)) { - notify("Could not update a child category!"); - } - } - } - } - } - - -/// Create a default category if necessary - if (!$categories = get_categories()) { /// No category yet! - // Try and make one - unset($tempcat); - $tempcat->name = get_string("miscellaneous"); - if (!$tempcat->id = insert_record("course_categories", $tempcat)) { - error("Serious error: Could not create a default category!"); - } - } - - -/// Move a category to a new parent if required - - if (isset($move) and isset($moveto)) { - if ($tempcat = get_record("course_categories", "id", $move)) { - if ($tempcat->parent != $moveto) { - if (! set_field("course_categories", "parent", $moveto, "id", $tempcat->id)) { - notify("Could not update that category!"); - } - } - } - } - - -/// Hide or show a category - if (isset($hide) or isset($show)) { - if (isset($hide)) { - $tempcat = get_record("course_categories", "id", $hide); - $visible = 0; - } else { - $tempcat = get_record("course_categories", "id", $show); - $visible = 1; - } - if ($tempcat) { - if (! set_field("course_categories", "visible", $visible, "id", $tempcat->id)) { - notify("Could not update that category!"); - } - if (! set_field("course", "visible", $visible, "category", $tempcat->id)) { - notify("Could not hide/show any courses in this category !"); - } - } - } - - -/// Move a category up or down - - if (isset($moveup) or isset($movedown)) { - - $swapcategory = NULL; - $movecategory = NULL; - - if (isset($moveup)) { - if ($movecategory = get_record("course_categories", "id", $moveup)) { - $categories = get_categories("$movecategory->parent"); - - foreach ($categories as $category) { - if ($category->id == $movecategory->id) { - break; - } - $swapcategory = $category; - } - } - } - if (isset($movedown)) { - if ($movecategory = get_record("course_categories", "id", $movedown)) { - $categories = get_categories("$movecategory->parent"); - - $choosenext = false; - foreach ($categories as $category) { - if ($choosenext) { - $swapcategory = $category; - break; - } - if ($category->id == $movecategory->id) { - $choosenext = true; - } - } - } - } - if ($swapcategory and $movecategory) { // Renumber everything for robustness - $count=0; - foreach ($categories as $category) { - $count++; - if ($category->id == $swapcategory->id) { - $category = $movecategory; - } else if ($category->id == $movecategory->id) { - $category = $swapcategory; - } - if (! set_field("course_categories", "sortorder", $count, "id", $category->id)) { - notify("Could not update that category!"); - } - } - } - } - -/// Find the default category (the one with the lowest ID) - $categories = get_categories(); - $default = 99999; - foreach ($categories as $category) { - fix_category_courses($category->id); - if ($category->id < $default) { - $default = $category->id; - } - } - -/// Find any orphan courses that don't yet have a valid category and set to default - if ($courses = get_courses()) { - foreach ($courses as $course) { - if (!isset( $categories[$course->category] )) { - set_field("course", "category", $default, "id", $course->id); - } - } - } - -/// Print form for creating new categories - - print_simple_box_start("center"); - echo "

"; - echo "
"; - echo ""; - echo ""; - echo "
"; - echo "
"; - print_simple_box_end(); - - echo "
"; - - -/// Print out the categories with all the knobs - - $strcategories = get_string("categories"); - $strmovecategoryto = get_string("movecategoryto"); - $stredit = get_string("edit"); - - $displaylist = array(); - $parentlist = array(); - - $displaylist[0] = get_string("top"); - make_categories_list($displaylist, $parentlist, ""); - - echo ""; - echo ""; - echo ""; - echo ""; - - print_category_edit(NULL, $displaylist, $parentlist); - - echo "
$strcategories$stredit$strmovecategoryto
"; - - - print_footer(); - - - -function print_category_edit($category, $displaylist, $parentslist, $depth=-1, $up=false, $down=false) { -/// Recursive function to print all the categories ready for editing - - global $THEME, $CFG; - - static $str = ''; - static $pixpath = ''; - - if (empty($str)) { - $str->delete = get_string("delete"); - $str->moveup = get_string("moveup"); - $str->movedown = get_string("movedown"); - $str->edit = get_string("editthiscategory"); - $str->hide = get_string("hide"); - $str->show = get_string("show"); - } - - if (empty($pixpath)) { - if (empty($THEME->custompix)) { - $pixpath = "$CFG->wwwroot/pix"; - } else { - $pixpath = "$CFG->wwwroot/theme/$CFG->theme/pix"; - } - } - - if ($category) { - echo "cellcontent\">"; - echo "

"; - for ($i=0; $i<$depth;$i++) { - echo "      "; - } - $linkcss = $category->visible ? "" : " class=\"dimmed\" "; - echo "edit\" href=\"category.php?id=$category->id\">$category->name"; - echo "

"; - echo ""; - - echo ""; /// Print little icons - - if (!empty($category->visible)) { - echo "hide\" href=\"categories.php?hide=$category->id\"> "; - } else { - echo "show\" href=\"categories.php?show=$category->id\"> "; - } - - echo "delete\" href=\"categories.php?delete=$category->id\"> "; - - //echo "update\" href=\"category.php?id=$category->id\"> "; - - if ($up) { - echo "moveup\" href=\"categories.php?moveup=$category->id\"> "; - } - if ($down) { - echo "movedown\" href=\"categories.php?movedown=$category->id\"> "; - } - echo ""; - - echo ""; - $tempdisplaylist = $displaylist; - unset($tempdisplaylist[$category->id]); - foreach ($parentslist as $key => $parents) { - if (in_array($category->id, $parents)) { - unset($tempdisplaylist[$key]); - } - } - popup_form ("categories.php?move=$category->id&moveto=", $tempdisplaylist, "moveform$category->id", "$category->parent", "", "", "", false); - echo ""; - echo ""; - } else { - $category->id = "0"; - } - - if ($categories = get_categories($category->id)) { // Print all the children recursively - $countcats = count($categories); - $count = 0; - $first = true; - $last = false; - foreach ($categories as $cat) { - $count++; - if ($count == $countcats) { - $last = true; - } - $up = $first ? false : true; - $down = $last ? false : true; - $first = false; - - print_category_edit($cat, $displaylist, $parentslist, $depth+1, $up, $down); - } - } -} - - -?> diff --git a/course/category.php b/course/category.php index 35a6d68044..2ef167a139 100644 --- a/course/category.php +++ b/course/category.php @@ -1,16 +1,13 @@ editing = true; + } else if ($edit == "off") { + $USER->editing = false; + } + } + $updatebutton = update_category_button($category->id); -/// Print headings - - $stradministration = get_string("administration"); - $strcategories = get_string("categories"); - $strcategories = get_string("categories"); - $strcategory = get_string("category"); - $strcourses = get_string("courses"); + $creatorediting = !empty($USER->editing); + $adminediting = (isadmin() and $creatorediting); - print_header("$site->shortname: $strcategory", "$site->fullname", - "admin/index.php\">$stradministration -> ". - "$strcategories -> $strcategory"); + } else { + $updatebutton = ""; + $adminediting = false; + } -/// Rename the category +/// Rename the category if requested if (!empty($rename)) { $category->name = $rename; if (! set_field("course_categories", "name", $category->name, "id", $category->id)) { notify("An error occurred while renaming the category"); - } else { - notify("The category was renamed"); } } + +/// Print headings + + $numcategories = count_records("course_categories"); + + $stradministration = get_string("administration"); + $strcategories = get_string("categories"); + $strcategory = get_string("category"); + $strcourses = get_string("courses"); + $strcoursemanagement = get_string("coursemanagement"); + + if ($creatorediting) { + if ($adminediting) { + print_header("$site->shortname: $category->name", "$site->fullname", + "admin/index.php\">$stradministration -> ". + "$strcoursemanagement -> $category->name", + "", "", true, $updatebutton); + } else { + print_header("$site->shortname: $category->name", "$site->fullname", + "$strcourses -> $category->name", "", "", true, $updatebutton); + } + } else { + print_header("$site->shortname: $category->name", "$site->fullname", + "$strcourses -> $category->name", "", "", true, $updatebutton); + } + + /// Print the category selector $displaylist = array(); @@ -57,105 +84,137 @@ echo "
"; -/// Move a specified course to a new category - - if (isset($move) and isset($moveto)) { - if (! $course = get_record("course", "id", $move)) { - notify("Error finding the course"); - } else if (! $destcategory = get_record("course_categories", "id", $moveto)) { - notify("Error finding the category"); - } else { - if (!set_field("course", "category", $destcategory->id, "id", $course->id)) { - notify("An error occurred - course not moved!"); - } - fix_category_courses($destcategory->id); - fix_category_courses($category->id); - $category = get_record("course_categories", "id", $category->id); - } - } +/// Editing functions + if ($adminediting) { -/// Hide or show a course + /// Move a specified course to a new category - if (isset($hide) or isset($show)) { - if (isset($hide)) { - $course = get_record("course", "id", $hide); - $visible = 0; - } else { - $course = get_record("course", "id", $show); - $visible = 1; - } - if ($course) { - if (! set_field("course", "visible", $visible, "id", $course->id)) { - notify("Could not update that course!"); + if (isset($move) and isset($moveto)) { + if (! $course = get_record("course", "id", $move)) { + notify("Error finding the course"); + } else if (! $destcategory = get_record("course_categories", "id", $moveto)) { + notify("Error finding the category"); + } else { + if (!set_field("course", "category", $destcategory->id, "id", $course->id)) { + notify("An error occurred - course not moved!"); + } + fix_course_sortorder($destcategory->id); + fix_course_sortorder($category->id); + $category = get_record("course_categories", "id", $category->id); } } - } -/// Move a course up or down + /// Hide or show a course + + if (isset($hide) or isset($show)) { + if (isset($hide)) { + $course = get_record("course", "id", $hide); + $visible = 0; + } else { + $course = get_record("course", "id", $show); + $visible = 1; + } + if ($course) { + if (! set_field("course", "visible", $visible, "id", $course->id)) { + notify("Could not update that course!"); + } + } + } - if (isset($moveup) or isset($movedown)) { + /// Move a course up or down - $movecourse = isset($moveup) ? $moveup : $movedown; + if (isset($moveup) or isset($movedown)) { - fix_category_courses($category->id); - if (!$category = get_record("course_categories", "id", $category->id)) { // Fresh copy - error("Category not known!"); - } + $movecourse = NULL; + $swapcourse = NULL; - $courses = explode(',', $category->courseorder); - $key = array_search($movecourse, $courses); - if ($key === NULL or $key === false) { - notify("Could not find that course in the category list!"); + $courses = get_courses($category->id); - } else { if (isset($moveup)) { - $swapkey = $key-1; - } else { - $swapkey = $key+1; + if ($movecourse = get_record("course", "id", $moveup)) { + foreach ($courses as $course) { + if ($course->id == $movecourse->id) { + break; + } + $swapcourse = $course; + } + } } - $courses[$key] = $courses[$swapkey]; - $courses[$swapkey] = $movecourse; - $category->courseorder = implode(",", $courses); - - if (! set_field("course_categories", "courseorder", $category->courseorder, "id", $category->id)) { - notify("Database error while trying to update the category!"); + if (isset($movedown)) { + if ($movecourse = get_record("course", "id", $movedown)) { + $choosenext = false; + foreach ($courses as $course) { + if ($choosenext) { + $swapcourse = $course; + break; + } + if ($course->id == $movecourse->id) { + $choosenext = true; + } + } + } + } + if ($swapcourse and $movecourse) { // Renumber everything for robustness + $count=0; + foreach ($courses as $course) { + $count++; + if ($course->id == $swapcourse->id) { + $course = $movecourse; + } else if ($course->id == $movecourse->id) { + $course = $swapcourse; + } + if (! set_field("course", "sortorder", $count, "id", $course->id)) { + notify("Could not update that course!"); + } + } } } - } + + fix_course_sortorder($category->id); + + } // End of editing stuff -/// Print out the courses with all the knobs +/// Print out all the courses - fix_category_courses($category->id); - if (!$courses = get_courses($category)) { + if (!$courses = get_courses($category->id)) { print_heading(get_string("nocoursesyet")); } else { - $strcourses = get_string("courses"); + $strcourses = get_string("courses"); $strmovecourseto = get_string("movecourseto"); - $stredit = get_string("edit"); + $stredit = get_string("edit"); $strdelete = get_string("delete"); + $strbackup = get_string("backup"); $strmoveup = get_string("moveup"); $strmovedown = get_string("movedown"); $strupdate = get_string("update"); $strhide = get_string("hide"); $strshow = get_string("show"); + $strassignteachers = get_string("assignteachers"); if (empty($THEME->custompix)) { $pixpath = "$CFG->wwwroot/pix"; } else { $pixpath = "$CFG->wwwroot/theme/$CFG->theme/pix"; } + - echo ""; + echo "
"; echo ""; - echo ""; - echo ""; + if ($creatorediting) { + echo ""; + if ($adminediting) { + echo ""; + } + } + echo ""; + $numcourses = count($courses); $count = 0; @@ -168,53 +227,66 @@ $linkcss = $course->visible ? "" : " class=\"dimmed\" "; echo ""; echo ""; - echo ""; + echo ""; } - - echo ""; - echo ""; echo ""; } echo "
$strcourses$stredit$strmovecourseto
$stredit$strmovecourseto
id\">$course->fullname"; - if (!empty($course->visible)) { - echo "id&hide=$course->id\"> "; - } else { - echo "id&show=$course->id\"> "; - } - echo "id\"> "; + if ($creatorediting) { + echo ""; + echo "wwwroot/$CFG->admin/teacher.php?id=$course->id\"> "; + if ($adminediting) { + echo "id\"> "; + if (!empty($course->visible)) { + echo "id&hide=$course->id\"> "; + } else { + echo "id&show=$course->id\"> "; + } - if ($up) { - echo "id&moveup=$course->id\"> "; - } - - if ($down) { - echo "id&movedown=$course->id\"> "; + echo "id\"> "; + + + if ($up) { + echo "id&moveup=$course->id\"> "; + } + + if ($down) { + echo "id&movedown=$course->id\"> "; + } + } + + echo ""; + popup_form ("category.php?id=$category->id&move=$course->id&moveto=", $displaylist, + "moveform$course->id", "$course->category", "", "", "", false); + echo ""; - popup_form ("category.php?id=$category->id&move=$course->id&moveto=", $displaylist, - "moveform$course->id", "$course->category", "", "", "", false); - echo "
"; echo "
"; } - -/// Print form to rename the category - $strrename= get_string("rename"); + if ($adminediting) { + /// First print form to rename the category + $strrename= get_string("rename"); + print_simple_box_start("center"); + echo "
"; + echo "
"; + echo "id\">"; + echo "name\">"; + echo ""; + echo "
"; + echo "
"; + print_simple_box_end(); + echo "
"; + } - print_simple_box_start("center"); - echo "
"; - echo "
"; - echo "id\">"; - echo "name\">"; - echo ""; - echo "
"; - echo "
"; - print_simple_box_end(); + print_footer(); ?> diff --git a/course/edit.html b/course/edit.html index 979876d791..53fc0e4c50 100644 --- a/course/edit.html +++ b/course/edit.html @@ -1,5 +1,16 @@
+ + + + - - - -"; + + echo ""; + + echo ""; + + echo ""; + echo ""; } else { - print_courses($category, "80%"); + $category->id = "0"; } - print_footer(); + if ($categories = get_categories($category->id)) { // Print all the children recursively + $countcats = count($categories); + $count = 0; + $first = true; + $last = false; + foreach ($categories as $cat) { + $count++; + if ($count == $countcats) { + $last = true; + } + $up = $first ? false : true; + $down = $last ? false : true; + $first = false; -?> + print_category_edit($cat, $displaylist, $parentslist, $depth+1, $up, $down); + } + } +} +?> diff --git a/course/lib.php b/course/lib.php index ab1c8e7b2a..e7c52c3aaf 100644 --- a/course/lib.php +++ b/course/lib.php @@ -713,19 +713,13 @@ function print_admin_links ($siteid, $width=180) { $modicon[]=""; } if (iscreator()) { - $moddata[]="wwwroot/course/edit.php\">".get_string("addnewcourse").""; + $moddata[]="wwwroot/course/index.php\">".get_string("coursemanagement").""; $modicon[]=$icon; - $moddata[]="wwwroot/$CFG->admin/teacher.php\">".get_string("assignteachers").""; + $moddata[]="wwwroot/course/edit.php\">".get_string("addnewcourse").""; $modicon[]=$icon; $fulladmin = ""; } if (isadmin()) { - $moddata[]="wwwroot/course/categories.php\">".get_string("categories").""; - $modicon[]=$icon; - $moddata[]="wwwroot/course/delete.php\">".get_string("deletecourse").""; - $modicon[]=$icon; - $moddata[]="wwwroot/backup/backup.php\">".get_string("coursebackup").""; - $modicon[]=$icon; $moddata[]="wwwroot/files/index.php?id=$siteid\">".get_string("courserestore").""; $modicon[]=$icon; $moddata[]="
"; @@ -853,14 +847,15 @@ function print_whole_category_list($category=NULL, $displaylist=NULL, $parentsli if ($category) { if ($category->visible or isadmin()) { - print_category_box($category, $depth); + print_category_info($category, $depth); } else { return; // Don't bother printing children of invisible categories } } else { - print_simple_box_start("center", "100%"); $category->id = "0"; + echo "

:

category", ""); + helpbutton("coursecategory", get_string("category")); + ?> +

:

@@ -49,17 +60,6 @@ helpbutton("guestaccess", get_string("opentoguests")); ?>

:

category", ""); - helpbutton("coursecategory", get_string("category")); - ?> -

:

timemodified = time(); - fix_category_courses($form->category); + fix_course_sortorder($form->category); if (!empty($course)) { if (update_record("course", $form)) { diff --git a/course/index.php b/course/index.php index 946772e3fe..5cb57118bd 100644 --- a/course/index.php +++ b/course/index.php @@ -1,50 +1,362 @@ editing = true; + } else if ($edit == "off") { + $USER->editing = false; + } + } + } + + $adminediting = (isadmin() and !empty($USER->editing)); + + +/// Unless it's an editing admin, just print the regular listing of courses/categories + + if (!$adminediting) { + $countcategories = count_records("course_categories"); + + if ($countcategories > 1) { + $strcourses = get_string("courses"); + print_header($strcourses, $strcourses, $strcourses, "", "", true, update_categories_button()); + print_heading(get_string("categories")); + print_simple_box_start("center", "50%"); + print_whole_category_list(); + print_simple_box_end(); + } else { + $strfulllistofcourses = get_string("fulllistofcourses"); + print_header("$site->shortname: $strfulllistofcourses", $strfulllistofcourses, $strfulllistofcourses); + print_courses(0, "80%"); + } + + print_footer(); + exit; + } + +/// From now on is all the admin functions + + require_login(); + + if (!isadmin()) { + error("Only administrators can use this page!"); + } + +/// Print headings + + $stradministration = get_string("administration"); $strcategories = get_string("categories"); - $strmycourses = get_string("mycourses"); - $strfulllistofcourses = get_string("fulllistofcourses"); + $strcategory = get_string("category"); + $strcourses = get_string("courses"); + $strcoursemanagement = get_string("coursemanagement"); + $stredit = get_string("edit"); + $strdelete = get_string("delete"); + $straction = get_string("action"); + $straddnewcategory = get_string("addnewcategory"); - if ($category = get_record("course_categories", "id", $category)) { - print_header($strcourses, $strcourses, "$strcourses -> $category->name", - "", "", true, update_category_button($category->id)); + print_header("$site->shortname: $strcategories", "$site->fullname", + "admin/index.php\">$stradministration -> $strcoursemanagement", + "addform.addcategory", "", true, update_categories_button()); - } else { - print_header($strcourses, $strcourses, $strcourses); - $category->id = 0; + print_heading($strcategories); + + +/// If data for a new category was submitted, then add it + if ($form = data_submitted()) { + if (!empty($form->addcategory)) { + unset($newcategory); + $newcategory->name = $form->addcategory; + $newcategory->sortorder = 999; + if (!insert_record("course_categories", $newcategory)) { + notify("Could not insert the new category '$newcategory->name'"); + } else { + notify(get_string("categoryadded", "", $newcategory->name)); + } + } + } + + +/// Delete a category if necessary + + if (isset($delete)) { + if ($tempcat = get_record("course_categories", "id", $delete)) { + if (delete_records("course_categories", "id", $tempcat->id)) { + notify(get_string("categorydeleted", "", $tempcat->name)); + } + if ($children = get_records("course_categories", "parent", $tempcat->id)) { + foreach ($children as $childcat) { + if (! set_field("course_categories", "parent", $tempcat->parent, "id", $childcat->id)) { + notify("Could not update a child category!"); + } + } + } + } } -/// Print the category selector +/// Create a default category if necessary + if (!$categories = get_categories()) { /// No category yet! + // Try and make one + unset($tempcat); + $tempcat->name = get_string("miscellaneous"); + if (!$tempcat->id = insert_record("course_categories", $tempcat)) { + error("Serious error: Could not create a default category!"); + } + } + + +/// Move a category to a new parent if required + + if (isset($move) and isset($moveto)) { + if ($tempcat = get_record("course_categories", "id", $move)) { + if ($tempcat->parent != $moveto) { + if (! set_field("course_categories", "parent", $moveto, "id", $tempcat->id)) { + notify("Could not update that category!"); + } + } + } + } + + +/// Hide or show a category + if (isset($hide) or isset($show)) { + if (isset($hide)) { + $tempcat = get_record("course_categories", "id", $hide); + $visible = 0; + } else { + $tempcat = get_record("course_categories", "id", $show); + $visible = 1; + } + if ($tempcat) { + if (! set_field("course_categories", "visible", $visible, "id", $tempcat->id)) { + notify("Could not update that category!"); + } + if (! set_field("course", "visible", $visible, "category", $tempcat->id)) { + notify("Could not hide/show any courses in this category !"); + } + } + } + + +/// Move a category up or down + + if (isset($moveup) or isset($movedown)) { + + $swapcategory = NULL; + $movecategory = NULL; + + if (isset($moveup)) { + if ($movecategory = get_record("course_categories", "id", $moveup)) { + $categories = get_categories("$movecategory->parent"); + + foreach ($categories as $category) { + if ($category->id == $movecategory->id) { + break; + } + $swapcategory = $category; + } + } + } + if (isset($movedown)) { + if ($movecategory = get_record("course_categories", "id", $movedown)) { + $categories = get_categories("$movecategory->parent"); + $choosenext = false; + foreach ($categories as $category) { + if ($choosenext) { + $swapcategory = $category; + break; + } + if ($category->id == $movecategory->id) { + $choosenext = true; + } + } + } + } + if ($swapcategory and $movecategory) { // Renumber everything for robustness + $count=0; + foreach ($categories as $category) { + $count++; + if ($category->id == $swapcategory->id) { + $category = $movecategory; + } else if ($category->id == $movecategory->id) { + $category = $swapcategory; + } + if (! set_field("course_categories", "sortorder", $count, "id", $category->id)) { + notify("Could not update that category!"); + } + } + } + } + +/// Find the default category (the one with the lowest ID) $categories = get_categories(); - $multicategories = count($categories) > 1; + $default = 99999; + foreach ($categories as $category) { + fix_course_sortorder($category->id); + if ($category->id < $default) { + $default = $category->id; + } + } + +/// Find any orphan courses that don't yet have a valid category and set to default + if ($courses = get_courses()) { + foreach ($courses as $course) { + if ($course->category and !isset( $categories[$course->category] )) { + set_field("course", "category", $default, "id", $course->id); + } + } + } + +/// Print form for creating new categories + + print_simple_box_start("center"); + echo "
"; + echo ""; + echo ""; + echo ""; + echo ""; + echo "
"; + print_simple_box_end(); + + echo "
"; + + +/// Print out the categories with all the knobs + + $strcategories = get_string("categories"); + $strcourses = get_string("courses"); + $strmovecategoryto = get_string("movecategoryto"); + $stredit = get_string("edit"); + + $displaylist = array(); + $parentlist = array(); + + $displaylist[0] = get_string("top"); + make_categories_list($displaylist, $parentlist, ""); + + echo ""; + echo ""; + echo ""; + echo ""; + echo ""; + + print_category_edit(NULL, $displaylist, $parentlist); + + echo "
$strcategories$strcourses$stredit$strmovecategoryto
"; + - if (count($categories) > 1) { - $parentlist = array(); - $displaylist = array(); - $displaylist["0"] = $strfulllistofcourses; - make_categories_list($displaylist, $parentlist, ""); + print_footer(); + + + +function print_category_edit($category, $displaylist, $parentslist, $depth=-1, $up=false, $down=false) { +/// Recursive function to print all the categories ready for editing + + global $THEME, $CFG; + + static $str = ''; + static $pixpath = ''; + + if (empty($str)) { + $str->delete = get_string("delete"); + $str->moveup = get_string("moveup"); + $str->movedown = get_string("movedown"); + $str->edit = get_string("editthiscategory"); + $str->hide = get_string("hide"); + $str->show = get_string("show"); + } - echo "
"; - popup_form("index.php?category=", $displaylist, "switchcategory", "$category->id", "", "", "", false); - echo "

"; + if (empty($pixpath)) { + if (empty($THEME->custompix)) { + $pixpath = "$CFG->wwwroot/pix"; + } else { + $pixpath = "$CFG->wwwroot/theme/$CFG->theme/pix"; + } } - if (empty($category->id)) { - print_courses(0, "80%"); + if ($category) { + echo "
cellcontent\">"; + echo "

"; + for ($i=0; $i<$depth;$i++) { + echo "      "; + } + $linkcss = $category->visible ? "" : " class=\"dimmed\" "; + echo "edit\" href=\"category.php?id=$category->id&edit=on\">$category->name"; + echo "

"; + echo "
"; /// Print little icons + echo count_records("course", "category", $category->id); + echo ""; /// Print little icons + + echo "delete\" href=\"index.php?delete=$category->id\"> "; + + if (!empty($category->visible)) { + echo "hide\" href=\"index.php?hide=$category->id\"> "; + } else { + echo "show\" href=\"index.php?show=$category->id\"> "; + } + + if ($up) { + echo "moveup\" href=\"index.php?moveup=$category->id\"> "; + } + if ($down) { + echo "movedown\" href=\"index.php?movedown=$category->id\"> "; + } + echo ""; + $tempdisplaylist = $displaylist; + unset($tempdisplaylist[$category->id]); + foreach ($parentslist as $key => $parents) { + if (in_array($category->id, $parents)) { + unset($tempdisplaylist[$key]); + } + } + popup_form ("index.php?move=$category->id&moveto=", $tempdisplaylist, "moveform$category->id", "$category->parent", "", "", "", false); + echo "
"; + $toplevel = true; } if ($categories = get_categories($category->id)) { // Print all the children recursively @@ -881,14 +876,15 @@ function print_whole_category_list($category=NULL, $displaylist=NULL, $parentsli } } - if ($category->id == "0") { - print_simple_box_end(); + if (isset($toplevel)) { + echo "
"; } } -function print_category_box($category, $depth) { -/// Prints the category box in indented fashion +function print_category_info($category, $depth) { +/// Prints the category info in indented fashion +/// This function is only used by print_whole_category_list() above global $CFG; @@ -901,23 +897,21 @@ function print_category_box($category, $depth) { $pixpath = "$CFG->wwwroot/theme/$CFG->theme/pix"; } - $size = $depth * 40; - $catlinkcss = $category->visible ? "" : " class=\"dimmed\" "; - echo ""; echo ""; - echo ""; + echo ""; + } else { + for ($i=0; $i<$depth;$i++) { + echo ""; + } + echo ""; + echo ""; + echo ""; } - echo ""; - echo ""; - echo "
"; - echo print_spacer(1, $size); - echo ""; - echo "wwwroot/course/index.php?category=$category->id\">$category->name"; - echo "
"; - //echo "$category->name"; + echo "
"; + for ($i=0; $i<$depth;$i++) { + echo ""; + } + echo "
"; + if ($count = count_records("course", "category", $category->id)) { + echo $count; + } + echo "
"; - } function print_courses_sideblock($category=0, $width="100%") { @@ -954,12 +960,13 @@ function print_courses_sideblock($category=0, $width="100%") { if (count($categories) > 1) { // Just print top level category links foreach ($categories as $category) { $linkcss = $category->visible ? "" : " class=\"dimmed\" "; - $moddata[]="wwwroot/course/index.php?category=$category->id\">$category->name"; + $moddata[]="wwwroot/course/category.php?id=$category->id\">$category->name"; $modicon[]=$icon; } } else { // Just print course names of single category $category = array_shift($categories); - $courses = get_courses($category); + $courses = get_courses($category->id); + if ($courses) { foreach ($courses as $course) { $linkcss = $course->visible ? "" : " class=\"dimmed\" "; @@ -988,14 +995,14 @@ function print_courses($category, $width="100%") { $categories = get_categories(0); // Parent = 0 ie top-level categories only if (count($categories) == 1) { $category = array_shift($categories); - $courses = get_courses($category); + $courses = get_courses($category->id); } else { - $courses = get_courses(0); + $courses = get_courses("all"); } unset($categories); } else { $categories = get_categories($category->id); // sub categories - $courses = get_courses($category); + $courses = get_courses($category->id); } if ($categories) { diff --git a/lang/en/docs/release.html b/lang/en/docs/release.html index 317a7c23e4..22a0a6edd0 100644 --- a/lang/en/docs/release.html +++ b/lang/en/docs/release.html @@ -24,7 +24,7 @@
  • Languages can now have a parent language
  • Web links can be in pop-up windows
  • Courses can be hidden from students)
  • -
  • Improved course browser (handles large numbers of courses) (tbd)
  • +
  • Improved course browser (handles large numbers of courses)
  • Consistent grading scheme throughout all modules (tbd)
  • Better control over peer-grading in forums (tbd)
  • Ability to add text between activities in course display (tbd)
  • @@ -170,403 +170,8 @@
    -

    New in Moodle 1.0.8.1 (12th January, 2003) :

    - - -
    - - -

    New in Moodle 1.0.8 (6th January, 2003) :

    - - - -
    -

    New in Moodle 1.0.7 (10th December, 2002):

    - - - - -
    -

    New in Moodle 1.0.6.4 (24th November, 2002) :

    - - - -
    -

    New in Moodle 1.0.6.3 (14th November, 2002) :

    - - -
    - -

    New in Moodle 1.0.6.2 (11th November, 2002) :

    - - - -
    - -

    New in Moodle 1.0.6.1 (6th November, 2002) :

    - - - -
    -

    New in Moodle 1.0.6 (26th October, 2002) :

    - - -

    Older releases can be seen in the Moodle.com announcement forum. +

    Older releases can be seen in the Moodle.org announcement forum.

     

    diff --git a/lang/en/forum.php b/lang/en/forum.php index 6a2818746a..6e06a449c6 100644 --- a/lang/en/forum.php +++ b/lang/en/forum.php @@ -6,6 +6,7 @@ $string['modulenameplural'] = "Forums"; #------------------------------------------------------------ $string['addanewdiscussion'] = "Add a new discussion topic"; +$string['addanewtopic'] = "Add a new topic"; $string['allowchoice'] = "Allow everyone to choose"; $string['allowdiscussions'] = "Can a \$a post to this forum?"; $string['allowratings'] = "Allow posts to be rated?"; @@ -63,6 +64,7 @@ $string['nameteacher'] = "Teacher forum"; $string['newforumposts'] = "New forum posts"; $string['nodiscussions'] = "There are no discussion topics yet in this forum"; $string['noguestpost'] = "Sorry, guests are not allowed to post"; +$string['nonews'] = "No news has been posted yet"; $string['noposts'] = "No posts"; $string['nopostscontaining'] = "No posts containing '\$a' were found"; $string['nosubscribers'] = "There are no subscribers yet for this forum"; diff --git a/lang/en/moodle.php b/lang/en/moodle.php index 163477f5f7..6cedc8f9d0 100644 --- a/lang/en/moodle.php +++ b/lang/en/moodle.php @@ -129,6 +129,7 @@ $string['coursecreators'] = "Course Creators"; $string['courseinfo'] = "Course info"; $string['coursefiles'] = "Course Files"; $string['courseformats'] = "Course formats"; +$string['coursemanagement'] = "Course Management"; $string['courserestore'] = "Course Restore"; $string['courses'] = "Courses"; $string['courseupdates'] = "Course updates"; diff --git a/lib/datalib.php b/lib/datalib.php index c06a042523..9ffb472058 100644 --- a/lib/datalib.php +++ b/lib/datalib.php @@ -838,26 +838,13 @@ function get_site () { } } - -function get_courses($category=0, $sort="fullname ASC") { +function get_courses($categoryid="all", $sort="sortorder ASC", $fields="*") { /// Returns list of courses, for whole site, or category - if ($category === 0) { // Return all courses, except site - $courses = get_records_select("course", "category > 0", $sort); - - } else if ($category === -1) { // Return all courses, even the site - $courses = get_records("course", "", "", $sort); - - } else { // $category is an object - $courses = get_records("course", "category", $category->id); - if ($courses) { // Reorder them - $courselist = explode(',', $category->courseorder); - $outcourses = array(); - foreach ($courselist as $courseid) { - $outcourses[] = $courses[$courseid]; - } - $courses = $outcourses; - } + if ($categoryid == "all") { + $courses = get_records("course", "", "", $sort, $fields); + } else { + $courses = get_records("course", "category", "$categoryid", $sort, $fields); } if ($courses) { /// Remove unavailable courses from the list @@ -872,6 +859,7 @@ function get_courses($category=0, $sort="fullname ASC") { return $courses; } + function get_my_courses($userid, $sort="c.fullname ASC") { global $CFG; @@ -887,6 +875,8 @@ function get_my_courses($userid, $sort="c.fullname ASC") { function get_categories($parent="none", $sort="sortorder ASC") { +/// Returns a sorted list of categories + if ($parent == "none") { $categories = get_records("course_categories", "", "", $sort); } else { @@ -905,43 +895,30 @@ function get_categories($parent="none", $sort="sortorder ASC") { return $categories; } -function fix_category_courses($categoryid) { -/// Given a category, this function makes sure the courseorder + +function fix_course_sortorder($categoryid) { +/// Given a category object, this function makes sure the courseorder /// variable reflects the real world. - if (!$category = get_record("course_categories", "id", $categoryid)) { - return false; + if (!$courses = get_records("course", "category", "$categoryid", "sortorder ASC", "id, sortorder")) { + return true; } - $catcourseschanged = false; - - if (trim($category->courseorder)) { - $catcourses = explode(',', $category->courseorder); - } else { - $catcourses = array(); - } - $courses = get_records("course", "category", $category->id); + $count = 0; + $modified = false; - if ($catcourses) { - foreach ($catcourses as $key => $catcourse) { // Look for missing courses - if (!isset($courses[$catcourse])) { - $catcourseschanged = true; - unset($catcourses[$key]); - } - } - } - if ($courses) { - foreach ($courses as $course) { - if (!in_array($course->id, $catcourses)) { - $catcourseschanged = true; - $catcourses[] = $course->id; - } + foreach ($courses as $course) { + if ($course->sortorder != $count) { + set_field("course", "sortorder", $count, "id", $course->id); + $modified = true; } + $count++; } - if ($catcourseschanged) { - $category->courseorder = implode(',', $catcourses); - return set_field("course_categories", "courseorder", $category->courseorder, "id", $category->id); + + if ($modified) { + set_field("course_categories", "timemodified", time(), "id", $categoryid); } + return true; } diff --git a/lib/db/mysql.php b/lib/db/mysql.php index a2058df9b6..dca38c0343 100644 --- a/lib/db/mysql.php +++ b/lib/db/mysql.php @@ -422,6 +422,20 @@ function main_upgrade($oldversion=0) { table_column("course_categories", "", "timemodified", "integer", "10", "unsigned"); } + if ($oldversion < 2003080400) { + table_column("course_categories", "courseorder", "courseorder", "integer", "10", "unsigned"); + table_column("course", "", "sortorder", "integer", "10", "unsigned", "0", "", "category"); + } + + if ($oldversion < 2003080700) { + notify("Cleaning up categories and course ordering..."); + if ($categories = get_categories()) { + foreach ($categories as $category) { + fix_course_sortorder($category->id); + } + } + } + return $result; } diff --git a/lib/db/mysql.sql b/lib/db/mysql.sql index 66c0a33bd8..7b2dd896ab 100644 --- a/lib/db/mysql.sql +++ b/lib/db/mysql.sql @@ -30,6 +30,7 @@ CREATE TABLE `prefix_config` ( CREATE TABLE `prefix_course` ( `id` int(10) unsigned NOT NULL auto_increment, `category` int(10) unsigned NOT NULL default '0', + `sortorder` int(10) unsigned NOT NULL default '0', `password` varchar(50) NOT NULL default '', `fullname` varchar(254) NOT NULL default '', `shortname` varchar(15) NOT NULL default '', @@ -63,7 +64,7 @@ CREATE TABLE `prefix_course_categories` ( `description` text NOT NULL, `parent` int(10) unsigned NOT NULL default '0', `sortorder` int(10) unsigned NOT NULL default '0', - `courseorder` text NOT NULL, + `courseorder` int(10) unsigned NOT NULL default '0', `visible` tinyint(1) NOT NULL default '1', `timemodified` int(10) unsigned NOT NULL default '0', PRIMARY KEY (`id`), diff --git a/lib/db/postgres7.php b/lib/db/postgres7.php index 8e3c95986c..fe560589a1 100644 --- a/lib/db/postgres7.php +++ b/lib/db/postgres7.php @@ -193,6 +193,21 @@ function main_upgrade($oldversion=0) { table_column("course_categories", "", "timemodified", "integer", "10", "unsigned"); } + if ($oldversion < 2003080400) { + notice("If the following command fails you may want to change the type manually, from TEXT to INTEGER. Moodle should keep working even if you don't."); + table_column("course_categories", "courseorder", "courseorder", "integer", "10", "unsigned"); + table_column("course", "", "sortorder", "integer", "10", "unsigned", "0", "", "category"); + } + + if ($oldversion < 2003080700) { + notify("Cleaning up categories and course ordering..."); + if ($categories = get_categories()) { + foreach ($categories as $category) { + fix_course_sortorder($category->id); + } + } + } + return $result; } ?> diff --git a/lib/db/postgres7.sql b/lib/db/postgres7.sql index 3a8630f108..39ef50efe9 100644 --- a/lib/db/postgres7.sql +++ b/lib/db/postgres7.sql @@ -8,6 +8,7 @@ CREATE TABLE prefix_config ( CREATE TABLE prefix_course ( id SERIAL PRIMARY KEY, category integer NOT NULL default '0', + sortorder integer NOT NULL default '0', password varchar(50) NOT NULL default '', fullname varchar(254) NOT NULL default '', shortname varchar(15) NOT NULL default '', @@ -34,7 +35,7 @@ CREATE TABLE prefix_course_categories ( description text NOT NULL default '', parent integer NOT NULL default '0', sortorder integer NOT NULL default '0', - courseorder text NOT NULL default '', + courseorder integer NOT NULL default '0', visible integer NOT NULL default '1', timemodified` integer NOT NULL default '0' ); diff --git a/lib/weblib.php b/lib/weblib.php index 0121cd3dbb..5bed9f2544 100644 --- a/lib/weblib.php +++ b/lib/weblib.php @@ -1080,13 +1080,38 @@ function update_module_button($moduleid, $courseid, $string) { } function update_category_button($categoryid) { -// Prints the editing button on a module "view" page - global $CFG; +// Prints the editing button on a category page + global $CFG, $USER; - if (isadmin()) { - $string = get_string("editthiscategory"); + if (iscreator()) { + if (!empty($USER->editing)) { + $string = get_string("turneditingoff"); + $edit = "off"; + } else { + $string = get_string("turneditingon"); + $edit = "on"; + } return "
    wwwroot/course/category.php\">". "". + "". + "
    "; + } +} + +function update_categories_button() { +// Prints the editing button on categories listing + global $CFG, $USER; + + if (isadmin()) { + if (!empty($USER->editing)) { + $string = get_string("turneditingoff"); + $edit = "off"; + } else { + $string = get_string("turneditingon"); + $edit = "on"; + } + return "
    wwwroot/course/index.php\">". + "". "
    "; } } diff --git a/user/edit.php b/user/edit.php index 42d994d8a4..149b796802 100644 --- a/user/edit.php +++ b/user/edit.php @@ -154,7 +154,7 @@ print_heading( get_string("userprofilefor", "", "$userfullname") ); if (isset($USER->newadminuser)) { - print_simple_box(get_string("configintroadmin"), "center"); + print_simple_box(get_string("configintroadmin"), "center", "50%"); echo "
    "; } diff --git a/version.php b/version.php index 91d71a7e75..16554dd8fe 100644 --- a/version.php +++ b/version.php @@ -5,7 +5,7 @@ // database to determine whether upgrades should // be performed (see lib/db/*.php) -$version = 2003073000; // The current version is a date (YYYYMMDDXX) +$version = 2003080700; // The current version is a date (YYYYMMDDXX) $release = "1.1 development"; // User-friendly version number -- 2.39.5