diff --git a/README.txt b/README.txt index d23372d1..bc50dc2e 100644 --- a/README.txt +++ b/README.txt @@ -11,6 +11,7 @@ Students are presented with a simple chart showing how far they have progressed ==Changes== +* 2016-09-09 - Major restructuring of checklist code, to aid future maintenance; dropping of pre-Moodle 2.7 support. * 2016-05-20 - Minor behat fixes for Moodle 3.1 compatibility * 2016-03-15 - Show/hide multiple activity items at once when editing the checklist (Tony Butler) * 2015-12-23 - Handle missing calendar events + fix deprecated 'get_referer' warning. diff --git a/classes/local/checklist_check.php b/classes/local/checklist_check.php new file mode 100644 index 00000000..7a1288cb --- /dev/null +++ b/classes/local/checklist_check.php @@ -0,0 +1,128 @@ +. + +/** + * Holds the checkmark information + * + * @package mod_checklist + * @copyright 2016 Davo Smith, Synergy Learning + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_checklist\local; + +use data_object; + +defined('MOODLE_INTERNAL') || die(); +global $CFG; +require_once($CFG->dirroot.'/completion/data_object.php'); + +class checklist_check extends data_object { + public $table = 'checklist_check'; + public $required_fields = [ + 'id', 'item', 'userid', 'usertimestamp', 'teachermark', 'teachertimestamp', 'teacherid' + ]; + + // DB fields. + public $item; + public $userid; + public $usertimestamp = 0; + public $teachermark = CHECKLIST_TEACHERMARK_UNDECIDED; + public $teachertimestamp = 0; + public $teacherid = null; + + public static function fetch($params) { + return self::fetch_helper('checklist_check', __CLASS__, $params); + } + + public static function fetch_all($params, $sort = false) { + $ret = self::fetch_all_helper('checklist_check', __CLASS__, $params); + if (!$ret) { + $ret = []; + } + return $ret; + } + + /** + * @param $userid + * @param $itemids + * @return checklist_check[] $itemid => $check + */ + public static function fetch_by_userid_itemids($userid, $itemids) { + global $DB; + + $ret = []; + if (!$itemids) { + return $ret; + } + + list($isql, $params) = $DB->get_in_or_equal($itemids, SQL_PARAMS_NAMED); + $params['userid'] = $userid; + $checks = $DB->get_records_select('checklist_check', "userid = :userid AND item $isql", $params); + foreach ($checks as $check) { + $ret[$check->item] = new checklist_check(); + self::set_properties($ret[$check->item], $check); + } + return $ret; + } + + public static function teachermark_valid($teachermark) { + return in_array($teachermark, [CHECKLIST_TEACHERMARK_YES, CHECKLIST_TEACHERMARK_NO, CHECKLIST_TEACHERMARK_UNDECIDED]); + } + + protected function check_fields_valid() { + if (!self::teachermark_valid($this->teachermark)) { + debugging('Unexpected teachermark value: '.$this->teachermark); + $this->teachermark = CHECKLIST_TEACHERMARK_UNDECIDED; + } + } + + public function save() { + if ($this->id) { + $this->update(); + } else { + $this->insert(); + } + } + + public function insert() { + $this->check_fields_valid(); + return parent::insert(); + } + + public function update() { + $this->check_fields_valid(); + return parent::update(); + } + + public function is_checked_student() { + return $this->usertimestamp > 0; + } + + public function is_checked_teacher() { + return ($this->teachermark == CHECKLIST_TEACHERMARK_YES); + } + + public function set_teachermark($teachermark, $teacherid) { + $this->teachermark = $teachermark; + $this->teacherid = $teacherid; + $this->teachertimestamp = time(); + } + + public function set_checked_student($checked) { + $this->usertimestamp = $checked ? time() : 0; + } +} diff --git a/classes/local/checklist_comment.php b/classes/local/checklist_comment.php new file mode 100644 index 00000000..f1014019 --- /dev/null +++ b/classes/local/checklist_comment.php @@ -0,0 +1,130 @@ +. + +/** + * A comment added, by a teacher, to a checklist item + * + * @package mod_checklist + * @copyright 2016 Davo Smith, Synergy Learning + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_checklist\local; + +use data_object; +use moodle_url; + +defined('MOODLE_INTERNAL') || die(); + +global $CFG; +require_once($CFG->dirroot.'/completion/data_object.php'); + +class checklist_comment extends data_object { + public $table = 'checklist_comment'; + public $required_fields = [ + 'id', 'itemid', 'userid', 'commentby', 'text' + ]; + + // DB fields. + public $itemid; + public $userid; + public $commentby; + public $text; + + // Extra data. + protected $commentbyname = null; + + protected static $courseid = null; + + public static function fetch($params) { + return self::fetch_helper('checklist_comment', __CLASS__, $params); + } + + public static function fetch_all($params, $sort = false) { + $ret = self::fetch_all_helper('checklist_comment', __CLASS__, $params); + if (!$ret) { + $ret = []; + } + return $ret; + } + + /** + * @param int $userid + * @param int[] $itemids + * @return checklist_comment[] $itemid => $check + */ + public static function fetch_by_userid_itemids($userid, $itemids) { + global $DB; + + $ret = []; + if (!$itemids) { + return $ret; + } + + list($isql, $params) = $DB->get_in_or_equal($itemids, SQL_PARAMS_NAMED); + $params['userid'] = $userid; + $comments = $DB->get_records_select('checklist_comment', "userid = :userid AND itemid $isql", $params); + foreach ($comments as $comment) { + $ret[$comment->itemid] = new checklist_comment(); + self::set_properties($ret[$comment->itemid], $comment); + } + return $ret; + } + + /** + * @return string|null + */ + public function get_commentby_name() { + return $this->commentbyname; + } + + /** + * @return moodle_url + */ + public function get_commentby_url() { + return new moodle_url('/user/view.php', ['id' => $this->commentby, 'course' => self::$courseid]); + } + + /** + * @param checklist_comment[] $comments + */ + public static function add_commentby_names($comments) { + global $DB; + + $userids = []; + foreach ($comments as $comment) { + if ($comment->commentby) { + $userids[] = $comment->commentby; + } + } + if (!$userids) { + return; + } + + $commentusers = $DB->get_records_list('user', 'id', $userids, '', 'id,'.get_all_user_name_fields(true)); + foreach ($comments as $comment) { + if ($comment->commentby) { + if (isset($commentusers[$comment->commentby])) { + $comment->commentbyname = fullname($commentusers[$comment->commentby]); + } + } + } + } + + public static function set_courseid($courseid) { + self::$courseid = $courseid; + } +} \ No newline at end of file diff --git a/classes/local/checklist_item.php b/classes/local/checklist_item.php new file mode 100644 index 00000000..ba093dfd --- /dev/null +++ b/classes/local/checklist_item.php @@ -0,0 +1,313 @@ +. + +/** + * Class to hold a checklist item. + * + * @package mod_checklist + * @copyright 2016 Davo Smith, Synergy Learning + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_checklist\local; + +use data_object; + +defined('MOODLE_INTERNAL') || die(); +global $CFG; +require_once($CFG->dirroot.'/completion/data_object.php'); + +class checklist_item extends data_object { + public $table = 'checklist_item'; + public $required_fields = [ + 'id', 'checklist', 'userid', 'displaytext', 'position', 'indent', 'itemoptional', 'duetime', + 'eventid', 'colour', 'moduleid', 'hidden', 'grouping' + ]; + + // DB fields. + public $checklist; + public $userid; + public $displaytext; + public $position; + public $indent = 0; + public $itemoptional = CHECKLIST_OPTIONAL_NO; + public $duetime = 0; + public $eventid = 0; + public $colour = 'black'; + public $moduleid = 0; + public $hidden = CHECKLIST_HIDDEN_NO; + public $grouping = 0; + + // Extra status fields (for a particular student). + public $usertimestamp = 0; + public $teachermark = CHECKLIST_TEACHERMARK_UNDECIDED; + public $teachertimestamp = 0; + public $teacherid = null; + + protected $teachername = null; + /** @var checklist_comment|null */ + protected $comment = null; + protected $editme = false; + + public static function fetch($params) { + return self::fetch_helper('checklist_item', __CLASS__, $params); + } + + public static function fetch_all($params, $sort = false) { + $ret = self::fetch_all_helper('checklist_item', __CLASS__, $params); + if (!$ret) { + $ret = []; + } + if ($sort) { + self::sort_items($ret); + } + return $ret; + } + + public static function sort_items(&$items) { + if (!$items) { + return; + } + uasort($items, function (checklist_item $a, checklist_item $b) { + if ($a->position < $b->position) { + return -1; + } + if ($a->position > $b->position) { + return 1; + } + // Sort by id, if the positions are the same. + if ($a->id < $b->id) { + return -1; + } + if ($a->id > $b->id) { + return 1; + } + return 0; + }); + } + + public function store_status($usertimestamp = null, $teachermark = null, $teachertimestamp = null, $teacherid = null) { + if ($usertimestamp !== null) { + $this->usertimestamp = $usertimestamp; + } + if ($teachermark !== null) { + if (!checklist_check::teachermark_valid($teachermark)) { + debugging('Unexpected teachermark value: '.$teachermark); + $teachermark = CHECKLIST_TEACHERMARK_UNDECIDED; + } + $this->teachermark = $teachermark; + } + if ($teachertimestamp !== null) { + $this->teachertimestamp = $teachertimestamp; + } + if ($teacherid !== null) { + $this->teacherid = $teacherid; + } + } + + public function is_checked($byteacher) { + if ($this->userid > 0 || !$byteacher) { + // User custom items are always checked-off by students (regardless of checklist settings). + return $this->usertimestamp > 0; + } else { + return ($this->teachermark == CHECKLIST_TEACHERMARK_YES); + } + } + + public function is_checked_teacher() { + return $this->is_checked(true); + } + + public function is_checked_student() { + return $this->is_checked(false); + } + + public function is_heading() { + return ($this->itemoptional == CHECKLIST_OPTIONAL_HEADING); + } + + public function is_required() { + return ($this->itemoptional == CHECKLIST_OPTIONAL_NO); + } + + public function is_optional() { + return ($this->itemoptional == CHECKLIST_OPTIONAL_YES); + } + + public function get_teachermark_image_url() { + global $OUTPUT; + static $images = null; + if ($images === null) { + $images = [ + CHECKLIST_TEACHERMARK_YES => $OUTPUT->pix_url('tick_box', 'mod_checklist'), + CHECKLIST_TEACHERMARK_NO => $OUTPUT->pix_url('cross_box', 'mod_checklist'), + CHECKLIST_TEACHERMARK_UNDECIDED => $OUTPUT->pix_url('empty_box', 'mod_checklist'), + ]; + } + return $images[$this->teachermark]; + } + + public function get_teachermark_text() { + static $text = null; + if ($text === null) { + $text = [ + CHECKLIST_TEACHERMARK_YES => get_string('teachermarkyes', 'mod_checklist'), + CHECKLIST_TEACHERMARK_NO => get_string('teachermarkno', 'mod_checklist'), + CHECKLIST_TEACHERMARK_UNDECIDED => get_string('teachermarkundecided', 'mod_checklist'), + ]; + } + return $text[$this->teachermark]; + } + + public function get_teachermark_class() { + static $classes = null; + if ($classes === null) { + $classes = [ + CHECKLIST_TEACHERMARK_YES => 'teachermarkyes', + CHECKLIST_TEACHERMARK_NO => 'teachermarkno', + CHECKLIST_TEACHERMARK_UNDECIDED => 'teachermarkundecided', + ]; + } + return $classes[$this->teachermark]; + } + + public function toggle_hidden() { + if ($this->hidden == CHECKLIST_HIDDEN_BYMODULE) { + return; // Do not override items linked to hidden Moodle activities. + } + if ($this->hidden == CHECKLIST_HIDDEN_NO) { + $this->hidden = CHECKLIST_HIDDEN_MANUAL; + } else { + $this->hidden = CHECKLIST_HIDDEN_NO; + } + $this->update(); + } + + public function hide_item() { + if (!$this->moduleid) { + return; + } + if ($this->hidden != CHECKLIST_HIDDEN_NO) { + return; + } + $this->hidden = CHECKLIST_HIDDEN_MANUAL; + $this->update(); + } + + public function show_item() { + if (!$this->moduleid) { + return; + } + if ($this->hidden != CHECKLIST_HIDDEN_MANUAL) { + return; + } + $this->hidden = CHECKLIST_HIDDEN_NO; + $this->update(); + } + + public function set_checked_student($userid, $checked) { + if ($checked == $this->is_checked_student()) { + return false; // No change. + } + + // Update checkmark in the database. + $check = new checklist_check(['item' => $this->id, 'userid' => $userid]); + $check->set_checked_student($checked); + $check->save(); + + // Update the stored value in this item. + $this->usertimestamp = $check->usertimestamp; + return true; + } + + public function set_teachermark($userid, $teachermark, $teacherid) { + if ($teachermark == $this->teachermark) { + return false; // No change. + } + + if (!checklist_check::teachermark_valid($teachermark)) { + throw new \coding_exception('Invalid teachermark '.$teachermark); + } + + // Update checkmark in the database. + $check = new checklist_check(['item' => $this->id, 'userid' => $userid]); + $check->set_teachermark($teachermark, $teacherid); + $check->save(); + + // Update the stored value in this item. + $this->teachertimestamp = $check->teachertimestamp; + $this->teachermark = $check->teachermark; + $this->teacherid = $check->teacherid; + + return true; + } + + public function get_teachername() { + return $this->teachername; + } + + public function get_comment() { + return $this->comment; + } + + public function set_editme($editme = true) { + $this->editme = $editme; + } + + public function is_editme() { + return $this->editme; + } + + /** + * Add links from the checklist items to the comments on them (for a particular user). + * @param checklist_item[] $items (indexed by id) + * @param checklist_comment[] $comments (indexed by itemid) + */ + public static function add_comments($items, $comments) { + foreach ($items as $item) { + if (isset($comments[$item->id])) { + $item->comment = $comments[$item->id]; + } + } + } + + /** + * Add the names of all the teachers who have updated the checklist items. + * @param checklist_item[] $items + */ + public static function add_teacher_names($items) { + global $DB; + + $userids = []; + foreach ($items as $item) { + if ($item->teacherid) { + $userids[] = $item->teacherid; + } + } + if (!$userids) { + return; + } + + $teachers = $DB->get_records_list('user', 'id', $userids, '', 'id,'.get_all_user_name_fields(true)); + foreach ($items as $item) { + if ($item->teacherid) { + if (isset($teachers[$item->teacherid])) { + $item->teachername = fullname($teachers[$item->teacherid]); + } + } + } + } +} diff --git a/classes/local/output_status.php b/classes/local/output_status.php new file mode 100644 index 00000000..3e5cc22f --- /dev/null +++ b/classes/local/output_status.php @@ -0,0 +1,359 @@ +. + +/** + * Stores fields that define the status of the checklist output + * + * @package mod_checklist + * @copyright 2016 Davo Smith, Synergy Learning + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_checklist\local; + +defined('MOODLE_INTERNAL') || die(); + +class output_status { + // All output. + protected $additemafter = 0; + + // View items only. + protected $viewother = false; + protected $userreport = false; + protected $teachercomments = false; + protected $editcomments = false; + protected $teachermarklocked = false; + protected $showcompletiondates = false; + protected $canupdateown = false; + protected $canaddown = false; + protected $addown = false; + protected $showprogressbar = false; + protected $showteachermark = false; + protected $showcheckbox = false; + protected $overrideauto = false; + protected $checkgroupings = false; + protected $updateform = false; + + // Edit items only. + protected $editdates = false; + protected $itemid = null; + protected $autopopulate = false; + protected $autoupdatewarning = null; + + /** + * Viewing another user (i.e. teacher report about a single user) + * @return boolean + */ + public function is_viewother() { + return $this->viewother; + } + + /** + * @param boolean $viewother + */ + public function set_viewother($viewother) { + $this->viewother = $viewother; + } + + /** + * Viewing complete user report (so no updating of checkmarks) + * @return boolean + */ + public function is_userreport() { + return $this->userreport; + } + + /** + * @param boolean $userreport + */ + public function set_userreport($userreport) { + $this->userreport = $userreport; + } + + /** + * Are teacher comments enabled for this instance? + * @return boolean + */ + public function is_teachercomments() { + return $this->teachercomments; + } + + /** + * @param boolean $teachercomments + */ + public function set_teachercomments($teachercomments) { + $this->teachercomments = $teachercomments; + } + + /** + * Is the user editing comments at the moment? + * @return boolean + */ + public function is_editcomments() { + return $this->editcomments; + } + + /** + * @param boolean $editcomments + */ + public function set_editcomments($editcomments) { + $this->editcomments = $editcomments; + } + + /** + * Are completed teacher marks locked (so the current user can't update them)? + * @return boolean + */ + public function is_teachermarklocked() { + return $this->teachermarklocked; + } + + /** + * @param boolean $teachermarklocked + */ + public function set_teachermarklocked($teachermarklocked) { + $this->teachermarklocked = $teachermarklocked; + } + + /** + * Should the completion dates be output? + * @return boolean + */ + public function is_showcompletiondates() { + return $this->showcompletiondates; + } + + /** + * @param boolean $showcompletiondates + */ + public function set_showcompletiondates($showcompletiondates) { + $this->showcompletiondates = $showcompletiondates; + } + + /** + * Can the user update their own checkmarks (students). + * @return boolean + */ + public function is_canupdateown() { + return $this->canupdateown; + } + + /** + * @param boolean $canupdateown + */ + public function set_canupdateown($canupdateown) { + $this->canupdateown = $canupdateown; + } + + /** + * Should the progress bar be shown? + * @return boolean + */ + public function is_showprogressbar() { + return $this->showprogressbar; + } + + /** + * @param boolean $showprogressbar + */ + public function set_showprogressbar($showprogressbar) { + $this->showprogressbar = $showprogressbar; + } + + /** + * Should the teacher mark be shown? + * @return boolean + */ + public function is_showteachermark() { + return $this->showteachermark; + } + + /** + * @param boolean $showteachermark + */ + public function set_showteachermark($showteachermark) { + $this->showteachermark = $showteachermark; + } + + /** + * Should the student mark be shown? + * @return boolean + */ + public function is_showcheckbox() { + return $this->showcheckbox; + } + + /** + * @param boolean $showcheckbox + */ + public function set_showcheckbox($showcheckbox) { + $this->showcheckbox = $showcheckbox; + } + + /** + * Can the user override automatically-calculated checkbox items (linked to activity completion)? + * @return boolean + */ + public function is_overrideauto() { + return $this->overrideauto; + } + + /** + * @param boolean $overrideauto + */ + public function set_overrideauto($overrideauto) { + $this->overrideauto = $overrideauto; + } + + /** + * Should items be checked against groupings, for visibility purposes? + * @return boolean + */ + public function is_checkgroupings() { + return $this->checkgroupings; + } + + /** + * @param boolean $checkgroupings + */ + public function set_checkgroupings($checkgroupings) { + $this->checkgroupings = $checkgroupings; + } + + /** + * Can the student add their own items? + * @return boolean + */ + public function is_canaddown() { + return $this->canaddown; + } + + /** + * @param boolean $canaddown + */ + public function set_canaddown($canaddown) { + $this->canaddown = $canaddown; + } + + /** + * Is the user currently adding/editing their own items? + * @return boolean + */ + public function is_addown() { + return $this->addown; + } + + /** + * @param boolean $addown + */ + public function set_addown($addown) { + $this->addown = $addown; + } + + /** + * Output 'add item' fields after this item. + * @return int + */ + public function get_additemafter() { + return $this->additemafter; + } + + /** + * @param int $additemafter + */ + public function set_additemafter($additemafter) { + $this->additemafter = $additemafter; + } + + /** + * Should an update form be output? + * @return boolean + */ + public function is_updateform() { + return $this->updateform; + } + + /** + * @param boolean $updateform + */ + public function set_updateform($updateform) { + $this->updateform = $updateform; + } + + /** + * Is date editing enabled? + * @return boolean + */ + public function is_editdates() { + return $this->editdates; + } + + /** + * @param boolean $editdates + */ + public function set_editdates($editdates) { + $this->editdates = $editdates; + } + + /** + * The ID of the item being edited (to generate the correct URLs). + * @return int|null + */ + public function get_itemid() { + return $this->itemid; + } + + /** + * @param null $itemid + */ + public function set_itemid($itemid) { + $this->itemid = $itemid; + } + + /** + * @return boolean + */ + public function is_autopopulate() { + return $this->autopopulate; + } + + /** + * @param boolean $autopopulate + */ + public function set_autopopulate($autopopulate) { + $this->autopopulate = $autopopulate; + } + + /** + * Should the autoupdate warning be shown and, if so, what type? + * @return int|null + */ + public function get_autoupdatewarning() { + return $this->autoupdatewarning; + } + + public function is_autoupdatewarning() { + return ($this->autoupdatewarning !== null); + } + + /** + * @param boolean $autoupdatewarning + */ + public function set_autoupdatewarning($autoupdatewarning) { + $this->autoupdatewarning = $autoupdatewarning; + } + +} \ No newline at end of file diff --git a/classes/local/progress_info.php b/classes/local/progress_info.php new file mode 100644 index 00000000..90c939f3 --- /dev/null +++ b/classes/local/progress_info.php @@ -0,0 +1,48 @@ +. + +/** + * Information about the student's progress, to pass on to the progress bar output + * + * @package mod_checklist + * @copyright 2016 Davo Smith, Synergy Learning + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mod_checklist\local; + +defined('MOODLE_INTERNAL') || die(); + +class progress_info { + public $totalitems; + public $requireditems; + public $allcompleteitems; + public $requiredcompleteitems; + + /** + * progress_info constructor. + * @param $totalitems + * @param $requireditems + * @param $allcompleteitems + * @param $requiredcompleteitems + */ + public function __construct($totalitems, $requireditems, $allcompleteitems, $requiredcompleteitems) { + $this->totalitems = $totalitems; + $this->requireditems = $requireditems; + $this->allcompleteitems = $allcompleteitems; + $this->requiredcompleteitems = $requiredcompleteitems; + } +} diff --git a/edit.php b/edit.php index 406c1567..fae036bb 100644 --- a/edit.php +++ b/edit.php @@ -22,7 +22,7 @@ $id = required_param('id', PARAM_INT); // Course_module ID. -$url = new moodle_url('/mod/checklist/view.php', array('id' => $id)); +$url = new moodle_url('/mod/checklist/edit.php', array('id' => $id)); $cm = get_coursemodule_from_id('checklist', $id, 0, false, MUST_EXIST); $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST); diff --git a/import.php b/import.php index 3dbdce14..6032cbb8 100644 --- a/import.php +++ b/import.php @@ -14,6 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . +use mod_checklist\local\checklist_item; + require_once(dirname(dirname(dirname(__FILE__))).'/config.php'); require_once(dirname(__FILE__).'/importexportfields.php'); global $CFG, $PAGE, $OUTPUT, $DB; @@ -159,7 +161,7 @@ function cleanrow($separator, $row) { } $itemfield = reset($item); - $newitem = new stdClass; + $newitem = new checklist_item(); $newitem->checklist = $checklist->id; $newitem->position = $position++; $newitem->userid = 0; @@ -214,7 +216,7 @@ function cleanrow($separator, $row) { } if ($newitem->displaytext) { // Don't insert items without any text in them. - if (!$DB->insert_record('checklist_item', $newitem)) { + if (!$newitem->insert()) { $ok = false; $errormsg = 'Unable to insert DB record for item'; break; diff --git a/lib.php b/lib.php index 53dbafc4..d2bb423a 100644 --- a/lib.php +++ b/lib.php @@ -185,14 +185,14 @@ function checklist_update_all_grades() { function checklist_update_grades($checklist, $userid = 0) { global $CFG, $DB; - $items = $DB->get_records('checklist_item', - array( - 'checklist' => $checklist->id, - 'userid' => 0, - 'itemoptional' => CHECKLIST_OPTIONAL_NO, - 'hidden' => CHECKLIST_HIDDEN_NO - ), - '', 'id, grouping'); + $params = array( + 'checklist' => $checklist->id, + 'userid' => 0, + 'itemoptional' => CHECKLIST_OPTIONAL_NO, + 'hidden' => CHECKLIST_HIDDEN_NO + ); + $items = \mod_checklist\local\checklist_item::fetch_all($params); + if (!$items) { return; } @@ -238,16 +238,17 @@ function checklist_update_grades($checklist, $userid = 0) { $groupings = checklist_class::get_user_groupings($userid, $course->id); $total = 0; - $itemlist = ''; + $itemlist = []; foreach ($items as $item) { if ($item->grouping) { if (!in_array($item->grouping, $groupings)) { continue; } } - $itemlist .= $item->id.','; + $itemlist[] = $item->id; $total++; } + $itemlist = implode(',', $itemlist); if (!$total) { // No items - set score to 0. $ugrade = new stdClass; @@ -256,8 +257,6 @@ function checklist_update_grades($checklist, $userid = 0) { $ugrade->date = time(); } else { - $itemlist = substr($itemlist, 0, -1); // Remove trailing ','. - $sql = 'SELECT (SUM(CASE WHEN '.$where.' THEN 1 ELSE 0 END) * ? / ? ) AS rawgrade'.$date; $sql .= " FROM {checklist_check} c "; $sql .= " WHERE c.item IN ($itemlist)"; diff --git a/locallib.php b/locallib.php index 7e695bd7..1aae194e 100644 --- a/locallib.php +++ b/locallib.php @@ -21,6 +21,11 @@ * @package mod/checklist */ +use mod_checklist\local\checklist_check; +use mod_checklist\local\checklist_comment; +use mod_checklist\local\checklist_item; +use mod_checklist\local\output_status; + require_once(dirname(dirname(dirname(__FILE__))).'/config.php'); require_once(dirname(__FILE__).'/lib.php'); @@ -41,13 +46,17 @@ class checklist_class { protected $strchecklist; protected $context; protected $userid; + /** @var checklist_item[] */ protected $items; + /** @var checklist_item[] */ protected $useritems; protected $useredit; protected $additemafter; protected $editdates; /** @var bool|int[] */ protected $groupings; + /** @var mod_checklist_renderer */ + protected $output; /** * @param int|string $cmid optional @@ -64,6 +73,8 @@ public function __construct($cmid = 'staticonly', $userid = 0, $checklist = null return; } + $this->output = self::get_renderer(); + $this->userid = $userid; if ($cm) { @@ -81,6 +92,7 @@ public function __construct($cmid = 'staticonly', $userid = 0, $checklist = null } else { $this->course = $DB->get_record('course', array('id' => $this->cm->course), '*', MUST_EXIST); } + checklist_comment::set_courseid($this->course->id); if ($checklist) { $this->checklist = $checklist; @@ -106,6 +118,14 @@ public function __construct($cmid = 'staticonly', $userid = 0, $checklist = null } } + /** + * @return mod_checklist_renderer + */ + private static function get_renderer() { + global $PAGE; + return $PAGE->get_renderer('mod_checklist'); + } + /** * Get an array of the items in a checklist * @@ -114,17 +134,14 @@ protected function get_items() { global $DB; // Load all shared checklist items. - $this->items = $DB->get_records('checklist_item', array('checklist' => $this->checklist->id, 'userid' => 0), 'position'); + $this->items = checklist_item::fetch_all(['checklist' => $this->checklist->id, 'userid' => 0], true); // Makes sure all items are numbered sequentially, starting at 1. $this->update_item_positions(); // Load student's own checklist items. if ($this->userid && $this->canaddown()) { - $this->useritems = $DB->get_records('checklist_item', array( - 'checklist' => $this->checklist->id, - 'userid' => $this->userid - ), 'position, id'); + $this->useritems = checklist_item::fetch_all(['checklist' => $this->checklist->id, 'userid' => $this->userid], true); } else { $this->useritems = false; } @@ -142,14 +159,10 @@ protected function get_items() { $id = $check->id; if (isset($this->items[$id])) { - $this->items[$id]->checked = $check->usertimestamp > 0; - $this->items[$id]->teachermark = $check->teachermark; - $this->items[$id]->usertimestamp = $check->usertimestamp; - $this->items[$id]->teachertimestamp = $check->teachertimestamp; - $this->items[$id]->teacherid = $check->teacherid; + $this->items[$id]->store_status($check->usertimestamp, $check->teachermark, + $check->teachertimestamp, $check->teacherid); } else if ($this->useritems && isset($this->useritems[$id])) { - $this->useritems[$id]->checked = $check->usertimestamp > 0; - $this->useritems[$id]->usertimestamp = $check->usertimestamp; + $this->useritems[$id]->store_status($check->usertimestamp); // User items never have a teacher mark to go with them. } } @@ -383,8 +396,6 @@ protected function removeauto() { * @param bool $end (optional) - where to stop offsetting positions */ protected function update_item_positions($move = 0, $start = 1, $end = false) { - global $DB; - $pos = 1; if (!$this->items) { @@ -398,10 +409,8 @@ protected function update_item_positions($move = 0, $start = 1, $end = false) { if ($item->position != $pos) { $oldpos = $item->position; $item->position = $pos; - $upditem = new stdClass; - $upditem->id = $item->id; - $upditem->position = $pos; - $DB->update_record('checklist_item', $upditem); + $item->update(); + if ($oldpos == $end) { break; } @@ -693,11 +702,9 @@ protected function view_tabs($currenttab) { print_tabs($tabs, $currenttab, $inactive, $activated); } - protected function view_progressbar() { - global $OUTPUT; - + protected function get_progress() { if (!$this->items) { - return; + return null; } $teacherprogress = ($this->checklist->teacheredit != CHECKLIST_MARKING_STUDENT); @@ -706,9 +713,9 @@ protected function view_progressbar() { $requireditems = 0; $completeitems = 0; $allcompleteitems = 0; - $checkgroupings = $this->checklist->autopopulate && ($this->groupings !== false); + $checkgroupings = ($this->groupings !== false); foreach ($this->items as $item) { - if (($item->itemoptional == CHECKLIST_OPTIONAL_HEADING) || ($item->hidden)) { + if (($item->is_heading()) || ($item->hidden)) { continue; } if ($checkgroupings && !empty($item->grouping)) { @@ -716,30 +723,23 @@ protected function view_progressbar() { continue; // Current user is not a member of this item's grouping. } } - if ($item->itemoptional == CHECKLIST_OPTIONAL_NO) { + if ($item->is_required()) { $requireditems++; - if ($teacherprogress) { - if ($item->teachermark == CHECKLIST_TEACHERMARK_YES) { - $completeitems++; - $allcompleteitems++; - } - } else if ($item->checked) { + if ($item->is_checked($teacherprogress)) { $completeitems++; $allcompleteitems++; } - } else if ($teacherprogress) { - if ($item->teachermark == CHECKLIST_TEACHERMARK_YES) { + } else { + if ($item->is_checked($teacherprogress)) { $allcompleteitems++; } - } else if ($item->checked) { - $allcompleteitems++; } $totalitems++; } if (!$teacherprogress) { if ($this->useritems) { foreach ($this->useritems as $item) { - if ($item->checked) { + if ($item->is_checked_student()) { $allcompleteitems++; } $totalitems++; @@ -747,617 +747,108 @@ protected function view_progressbar() { } } if ($totalitems == 0) { - return; + return null; } - $allpercentcomplete = ($allcompleteitems * 100) / $totalitems; - - if ($requireditems > 0 && $totalitems > $requireditems) { - $percentcomplete = ($completeitems * 100) / $requireditems; - echo '
'; - echo get_string('percentcomplete', 'checklist').': '; - echo '
'; - echo ''; - echo '
'; - echo '
 
'; - echo '
 
'; - echo '
'; - echo ' '.sprintf('%0d', $percentcomplete).'% '; - echo '
'; - echo '
'; - } - - echo '
'; - echo get_string('percentcompleteall', 'checklist').': '; - echo '
'; - echo ''; - echo '
'; - echo '
 
'; - echo '
 
'; - echo '
'; - echo ' '.sprintf('%0d', $allpercentcomplete).'% '; - echo '
'; - echo '
'; - } - - protected function get_teachermark($itemid) { - global $OUTPUT; - - if (!isset($this->items[$itemid])) { - return array('', ''); - } - switch ($this->items[$itemid]->teachermark) { - case CHECKLIST_TEACHERMARK_YES: - return array( - $OUTPUT->pix_url('tick_box', 'checklist'), - get_string('teachermarkyes', 'checklist'), - 'teachermarkyes' - ); - - case CHECKLIST_TEACHERMARK_NO: - return array( - $OUTPUT->pix_url('cross_box', 'checklist'), - get_string('teachermarkno', 'checklist'), - 'teachermarkno' - ); - - default: - return array( - $OUTPUT->pix_url('empty_box', 'checklist'), - get_string('teachermarkundecided', 'checklist'), - 'teachermarkundecided' - ); - } + return new \mod_checklist\local\progress_info($totalitems, $requireditems, $allcompleteitems, $completeitems); } + /** + * @param bool $viewother + * @param bool $userreport + */ protected function view_items($viewother = false, $userreport = false) { - global $DB, $OUTPUT, $PAGE, $CFG; - - echo $OUTPUT->box_start('generalbox boxwidthwide boxaligncenter checklistbox'); - - echo html_writer::tag('div', ' ', array('id' => 'checklistspinner')); - - $comments = $this->checklist->teachercomments; - $editcomments = false; - $thispage = new moodle_url('/mod/checklist/view.php', array('id' => $this->cm->id)); - - $teachermarklocked = false; - $showcompletiondates = false; - $strteachername = ''; - $struserdate = ''; - $strteacherdate = ''; - if ($viewother) { - if ($comments) { - $editcomments = optional_param('editcomments', false, PARAM_BOOL); - } - $thispage = new moodle_url('/mod/checklist/report.php', array('id' => $this->cm->id, 'studentid' => $this->userid)); - - if (!$student = $DB->get_record('user', array('id' => $this->userid))) { - error('No such user!'); - } - - echo '

'.get_string('checklistfor', 'checklist').' '.fullname($student, true).'

'; - echo ' '; - echo '
'; - echo html_writer::input_hidden_params($thispage, array('studentid')); - echo ''; - echo '
'; - - if (!$editcomments) { - echo '
'; - echo html_writer::input_hidden_params($thispage); - echo ''; - echo ' '; - echo '
'; - } - echo '
'; - echo html_writer::input_hidden_params($thispage); - echo ''; - echo ''; - echo ' '; - echo '
'; - - $teachermarklocked = $this->checklist->lockteachermarks - && !has_capability('mod/checklist:updatelocked', $this->context); - + global $DB, $PAGE; + + // Configure the status of the checklist output. + $status = new output_status(); + $status->set_viewother($viewother); + $status->set_userreport($userreport); + $status->set_teachercomments($this->checklist->teachercomments); + $status->set_canupdateown($this->canupdateown()); + $status->set_canaddown($this->canaddown()); + + if ($status->is_teachercomments()) { + if ($status->is_viewother()) { + $status->set_editcomments(optional_param('editcomments', false, PARAM_BOOL)); + } + $comments = checklist_comment::fetch_by_userid_itemids($this->userid, array_keys($this->items)); + checklist_comment::add_commentby_names($comments); + checklist_item::add_comments($this->items, $comments); + } + if ($status->is_canupdateown() || $status->is_viewother() || $status->is_userreport()) { + $status->set_showprogressbar(true); + $showteachermark = in_array($this->checklist->teacheredit, [CHECKLIST_MARKING_TEACHER, CHECKLIST_MARKING_BOTH]); + $status->set_showteachermark($showteachermark); + $showcheckbox = in_array($this->checklist->teacheredit, [CHECKLIST_MARKING_STUDENT, CHECKLIST_MARKING_BOTH]); + $status->set_showcheckbox($showcheckbox); + } + if ($status->is_showteachermark() && $this->checklist->lockteachermarks) { + $status->set_teachermarklocked(!has_capability('mod/checklist:updatelocked', $this->context)); + } + if ($status->is_viewother()) { $reportsettings = $this->get_report_settings(); - $showcompletiondates = $reportsettings->showcompletiondates; - - $strteacherdate = get_string('teacherdate', 'mod_checklist'); - $struserdate = get_string('userdate', 'mod_checklist'); - $strteachername = get_string('teacherid', 'mod_checklist'); - - if ($showcompletiondates) { - $teacherids = array(); - foreach ($this->items as $item) { - if ($item->teacherid) { - $teacherids[$item->teacherid] = $item->teacherid; - } - } - $fields = get_all_user_name_fields(true); - $teachers = $DB->get_records_list('user', 'id', $teacherids, '', 'id, '.$fields); - foreach ($this->items as $item) { - if (isset($teachers[$item->teacherid])) { - $item->teachername = fullname($teachers[$item->teacherid]); - } else { - $item->teachername = false; - } - } + $status->set_showcompletiondates($reportsettings->showcompletiondates); + if ($status->is_showcompletiondates()) { + checklist_item::add_teacher_names($this->items); } } - - $intro = file_rewrite_pluginfile_urls($this->checklist->intro, 'pluginfile.php', $this->context->id, - 'mod_checklist', 'intro', null); - $opts = array('trusted' => $CFG->enabletrusttext); - echo format_text($intro, $this->checklist->introformat, $opts); - echo '
'; - - $showteachermark = false; - $showcheckbox = true; - if ($this->canupdateown() || $viewother || $userreport) { - $this->view_progressbar(); - $showteachermark = ($this->checklist->teacheredit == CHECKLIST_MARKING_TEACHER) - || ($this->checklist->teacheredit == CHECKLIST_MARKING_BOTH); - $showcheckbox = ($this->checklist->teacheredit == CHECKLIST_MARKING_STUDENT) - || ($this->checklist->teacheredit == CHECKLIST_MARKING_BOTH); - $teachermarklocked = $teachermarklocked && $showteachermark; // Make sure this is OFF, if not showing teacher marks. - } - $overrideauto = ($this->checklist->autoupdate != CHECKLIST_AUTOUPDATE_YES); - $checkgroupings = $this->checklist->autopopulate && ($this->groupings !== false); - - if (!$this->items) { - print_string('noitems', 'checklist'); - } else { - $focusitem = false; - $updateform = ($showcheckbox && $this->canupdateown() && !$viewother && !$userreport) - || ($viewother && ($showteachermark || $editcomments)); - $addown = $this->canaddown() && $this->useredit; - if ($updateform) { - if ($this->canaddown() && !$viewother) { - echo '
'; - echo html_writer::input_hidden_params($thispage); - if ($addown) { - // Switch on for any other forms on this page (but off if this form submitted). - $thispage->param('useredit', 'on'); - echo ''; - } else { - echo ''; - echo ''; - } - echo '
'; - } - - if (!$viewother) { - // Load the Javascript required to send changes back to the server (without clicking 'save') - if ($CFG->version < 2012120300) { // < Moodle 2.4. - $jsmodule = array( - 'name' => 'mod_checklist', - 'fullpath' => new moodle_url('/mod/checklist/updatechecks.js') - ); - $PAGE->requires->yui2_lib('dom'); - $PAGE->requires->yui2_lib('event'); - $PAGE->requires->yui2_lib('connection'); - $PAGE->requires->yui2_lib('animation'); - } else { - $jsmodule = array( - 'name' => 'mod_checklist', - 'fullpath' => new moodle_url('/mod/checklist/updatechecks24.js') - ); - } - $updatechecksurl = new moodle_url('/mod/checklist/updatechecks.php'); - $updateprogress = $showteachermark ? 0 : 1; // Progress bars should be updated on 'student only' checklists. - $PAGE->requires->js_init_call('M.mod_checklist.init', array( - $updatechecksurl->out(), sesskey(), $this->cm->id, $updateprogress - ), true, $jsmodule); - } - - echo '
'; - echo html_writer::input_hidden_params($thispage); - echo ''; - echo ''; - } - - if ($this->useritems) { - reset($this->useritems); - } - - $commentusers = array(); - if ($comments) { - list($isql, $iparams) = $DB->get_in_or_equal(array_keys($this->items)); - $params = array_merge(array($this->userid), $iparams); - $commentsunsorted = $DB->get_records_select('checklist_comment', "userid = ? AND itemid $isql", $params); - $commentuserids = array(); - if (!empty($commentsunsorted)) { - $comments = array(); - foreach ($commentsunsorted as $comment) { - $comments[$comment->itemid] = $comment; - if ($comment->commentby) { - $commentuserids[] = $comment->commentby; - } - } - if (!empty($commentuserids)) { - list($csql, $cparams) = $DB->get_in_or_equal(array_unique($commentuserids, SORT_NUMERIC)); - $commentusers = $DB->get_records_select('user', 'id '.$csql, $cparams); - } - } else { - $comments = false; - } + $status->set_overrideauto($this->checklist->autoupdate !== CHECKLIST_AUTOUPDATE_YES); + if ($status->is_canaddown()) { + if ($this->useredit) { + $status->set_addown(true); + $status->set_additemafter($this->additemafter); } - - if ($teachermarklocked) { - echo '

'.get_string('lockteachermarkswarning', 'checklist').'

'; - } - - echo '
    '; - $currindent = 0; - foreach ($this->items as $item) { - - if ($item->hidden) { - continue; - } - - if ($checkgroupings && !empty($item->grouping)) { - if (!in_array($item->grouping, $this->groupings)) { - continue; // Current user is not a member of this item's grouping, so skip. - } - } - - while ($item->indent > $currindent) { - $currindent++; - echo '
      '; - } - while ($item->indent < $currindent) { - $currindent--; - echo '
    '; - } - $itemname = '"item'.$item->id.'"'; - $checked = (($updateform || $viewother || $userreport) && $item->checked) ? ' checked="checked" ' : ''; - if ($viewother || $userreport) { - $checked .= ' disabled="disabled" '; - } else if (!$overrideauto && $item->moduleid) { - $checked .= ' disabled="disabled" '; - } - switch ($item->colour) { - case 'red': - $itemcolour = 'itemred'; - break; - case 'orange': - $itemcolour = 'itemorange'; - break; - case 'green': - $itemcolour = 'itemgreen'; - break; - case 'purple': - $itemcolour = 'itempurple'; - break; - default: - $itemcolour = 'itemblack'; - } - - $checkclass = ''; - if ($item->itemoptional == CHECKLIST_OPTIONAL_HEADING) { - $optional = ' class="itemheading '.$itemcolour.'" '; - } else if ($item->itemoptional == CHECKLIST_OPTIONAL_YES) { - $optional = ' class="itemoptional '.$itemcolour.'" '; - $checkclass = ' itemoptional'; - } else { - $optional = ' class="'.$itemcolour.'" '; - } - - echo '
  1. '; - if ($showteachermark) { - if ($item->itemoptional != CHECKLIST_OPTIONAL_HEADING) { - if ($viewother) { - $lock = ($teachermarklocked && $item->teachermark == CHECKLIST_TEACHERMARK_YES); - $disabled = $lock ? 'disabled="disabled" ' : ''; - - $selu = ($item->teachermark == CHECKLIST_TEACHERMARK_UNDECIDED) ? 'selected="selected" ' : ''; - $sely = ($item->teachermark == CHECKLIST_TEACHERMARK_YES) ? 'selected="selected" ' : ''; - $seln = ($item->teachermark == CHECKLIST_TEACHERMARK_NO) ? 'selected="selected" ' : ''; - - $selectid = ' id='.$itemname.' '; - - echo ''; - } else { - list($imgsrc, $titletext, $class) = $this->get_teachermark($item->id); - echo ''.$titletext.''; - } - } - } - if ($showcheckbox) { - if ($item->itemoptional != CHECKLIST_OPTIONAL_HEADING) { - $id = ' id='.$itemname.' '; - if ($viewother && $showteachermark) { - $id = ''; - } - echo ''; - } - } - echo ''; - if (isset($item->modulelink)) { - echo ' '.
-                        get_string('linktomodule', 'checklist').''; - } - - if ($addown) { - echo ' '; - $title = '"'.get_string('additemalt', 'checklist').'"'; - echo '.$title.'; - } - - if ($item->duetime) { - if ($item->duetime > time()) { - echo ' '.userdate($item->duetime, get_string('strftimedate')).''; - } else { - echo ' '.userdate($item->duetime, get_string('strftimedate')).''; - } - } - - if ($showcompletiondates) { - if ($item->itemoptional != CHECKLIST_OPTIONAL_HEADING) { - if ($showteachermark && $item->teachermark != CHECKLIST_TEACHERMARK_UNDECIDED && $item->teachertimestamp) { - if ($item->teachername) { - echo ''.$item->teachername.''; - } - echo ''. - userdate($item->teachertimestamp, get_string('strftimedatetimeshort')).''; - } - if ($showcheckbox && $item->checked && $item->usertimestamp) { - echo ''. - userdate($item->usertimestamp, get_string('strftimedatetimeshort')).''; - } - } - } - - $foundcomment = false; - if ($comments) { - if (array_key_exists($item->id, $comments)) { - $comment = $comments[$item->id]; - $foundcomment = true; - echo '  '; - if ($comment->commentby) { - $userurl = new moodle_url('/user/view.php', array( - 'id' => $comment->commentby, 'course' => $this->course->id - )); - echo ''.fullname($commentusers[$comment->commentby]).': '; - } - if ($editcomments) { - $outid = ''; - if (!$focusitem) { - $focusitem = 'firstcomment'; - $outid = ' id="firstcomment" '; - } - echo ''; - } else { - echo s($comment->text); - } - echo ' '; - } - } - if (!$foundcomment && $editcomments) { - echo ' '; - } - - echo '
  2. '; - - // Output any user-added items. - if ($this->useritems) { - $useritem = current($this->useritems); - - if ($useritem && ($useritem->position == $item->position)) { - $thisitemurl = clone $thispage; - $thisitemurl->param('action', 'updateitem'); - $thisitemurl->param('sesskey', sesskey()); - - echo '
      '; - while ($useritem && ($useritem->position == $item->position)) { - $itemname = '"item'.$useritem->id.'"'; - $checked = ($updateform && $useritem->checked) ? ' checked="checked" ' : ''; - if (isset($useritem->editme)) { - $itemtext = explode("\n", $useritem->displaytext, 2); - $itemtext[] = ''; - $text = $itemtext[0]; - $note = $itemtext[1]; - $thisitemurl->param('itemid', $useritem->id); - - echo '
    1. '; - echo '
      '; - if ($showcheckbox) { - echo ''; - } - echo ''; - echo html_writer::input_hidden_params($thisitemurl); - echo ''; - echo ''; - echo '
      '; - echo ''; - echo ''; - echo '
      '; - - echo '
      '; - echo html_writer::input_hidden_params($thispage); - echo ''; - echo '
      '; - echo '
      '; - echo '
    2. '; - - $focusitem = 'updateitembox'; - } else { - echo '
    3. '; - if ($showcheckbox) { - echo ''; - } - $splittext = explode("\n", s($useritem->displaytext), 2); - $splittext[] = ''; - $text = $splittext[0]; - $note = str_replace("\n", '
      ', $splittext[1]); - echo ''; - - if ($addown) { - $baseurl = $thispage.'&itemid='.$useritem->id.'&sesskey='.sesskey().'&action='; - echo ' '; - $title = '"'.get_string('edititem', 'checklist').'"'; - echo '.$title.'; - - echo ' '; - $title = '"'.get_string('deleteitem', 'checklist').'"'; - echo '.$title.'; - } - if ($note != '') { - echo '
      '.$note.'
      '; - } - - echo '
    4. '; - } - $useritem = next($this->useritems); - } - echo '
    '; - } - } - - if ($addown && ($item->id == $this->additemafter)) { - $thisitemurl = clone $thispage; - $thisitemurl->param('action', 'additem'); - $thisitemurl->param('position', $item->position); - $thisitemurl->param('sesskey', sesskey()); - - echo '
    1. '; - echo '
      '; - echo '
      '; - echo html_writer::input_hidden_params($thisitemurl); - if ($showcheckbox) { - echo ''; - } - echo ''; - echo ''; - echo '
      '; - echo ''; - echo '
      '; - echo '
      '; - - echo '
      '; - echo html_writer::input_hidden_params($thispage); - echo ''; - echo '
      '; - echo '
      '; - echo '
    '; - - if (!$focusitem) { - $focusitem = 'additembox'; - } - } + } + $status->set_checkgroupings($this->groupings !== false); + if ($status->is_showcheckbox() && $status->is_canupdateown()) { + if (!$status->is_viewother() && !$status->is_userreport()) { + // Student checklist + can update + not viewing another user or overview report. + $status->set_updateform(true); } - echo '
'; - - if ($updateform) { - echo ''; - if ($viewother) { - echo ' '; - echo ' '; - echo ' '; - } - echo ''; + } + if ($status->is_viewother()) { + if ($status->is_showteachermark() || $status->is_editcomments()) { + // Viewing another user + teacher checklist or editing comments. + $status->set_updateform(true); } + } - if ($focusitem) { - echo ''; - } + // Gather some extra details needed in the output. + $intro = $this->formatted_intro(); + $progress = null; + if ($status->is_showprogressbar()) { + $progress = $this->get_progress(); + } + $student = null; + if ($status->is_viewother()) { + $student = $DB->get_record('user', ['id' => $this->userid], '*', MUST_EXIST); + } - if ($addown) { - echo ''; - } + // Add the javascript, if needed. + if (!$status->is_viewother()) { + // Load the Javascript required to send changes back to the server (without clicking 'save'). + $jsmodule = array( + 'name' => 'mod_checklist', + 'fullpath' => new moodle_url('/mod/checklist/updatechecks24.js') + ); + $updatechecksurl = new moodle_url('/mod/checklist/updatechecks.php'); + // Progress bars should be updated on 'student only' checklists. + $updateprogress = $status->is_showteachermark() ? 0 : 1; + $PAGE->requires->js_init_call('M.mod_checklist.init', array( + $updatechecksurl->out(), sesskey(), $this->cm->id, $updateprogress + ), true, $jsmodule); } - echo $OUTPUT->box_end(); + $this->output->checklist_items($this->items, $this->useritems, $this->groupings, $intro, $status, $progress, $student); } - protected function print_edit_date($ts = 0) { - // TODO - use fancy JS calendar instead. - - $id = rand(); - if ($ts == 0) { - $disabled = true; - $date = usergetdate(time()); - } else { - $disabled = false; - $date = usergetdate($ts); - } - $day = $date['mday']; - $month = $date['mon']; - $year = $date['year']; - - echo ''; - echo ''; - echo ''; - $checked = $disabled ? 'checked="checked" ' : ''; - echo ''."\n"; - echo ' - "; + protected function formatted_intro() { + global $CFG; + $intro = file_rewrite_pluginfile_urls($this->checklist->intro, 'pluginfile.php', $this->context->id, + 'mod_checklist', 'intro', null); + $opts = array('trusted' => $CFG->enabletrusttext); + return format_text($intro, $this->checklist->introformat, $opts); } protected function view_import_export() { @@ -1373,295 +864,16 @@ protected function view_import_export() { } protected function view_edit_items() { - global $OUTPUT; - - echo $OUTPUT->box_start('generalbox boxwidthwide boxaligncenter'); - - $currindent = 0; - $addatend = true; - $focusitem = false; - $hasauto = false; - - $thispage = new moodle_url('/mod/checklist/edit.php', array('id' => $this->cm->id, 'sesskey' => sesskey())); - if ($this->additemafter) { - $thispage->param('additemafter', $this->additemafter); + $status = new output_status(); + $status->set_additemafter($this->additemafter); + $status->set_editdates($this->editdates); + $status->set_itemid(optional_param('itemid', null, PARAM_INT)); + $status->set_autopopulate($this->checklist->autopopulate); + if ($this->checklist->autopopulate && $this->checklist->autoupdate) { + $status->set_autoupdatewarning($this->checklist->teacheredit); } - if ($this->editdates) { - $thispage->param('editdates', 'on'); - } - if ($itemid = optional_param('itemid', null, PARAM_INT)) { - $thispage->param('itemid', $itemid); - } - - if ($this->checklist->autoupdate && $this->checklist->autopopulate) { - if ($this->checklist->teacheredit == CHECKLIST_MARKING_STUDENT) { - echo '

'.get_string('autoupdatewarning_student', 'checklist').'

'; - } else if ($this->checklist->teacheredit == CHECKLIST_MARKING_TEACHER) { - echo '

'.get_string('autoupdatewarning_teacher', 'checklist').'

'; - } else { - echo '

'.get_string('autoupdatewarning_both', 'checklist').'

'; - } - } - - echo '
    '; - if ($this->items) { - $lastitem = count($this->items); - $lastindent = 0; - - echo html_writer::start_tag('form', array('action' => $thispage->out_omit_querystring(), 'method' => 'post')); - echo html_writer::input_hidden_params($thispage); - - if ($this->checklist->autopopulate) { - echo html_writer::empty_tag('input', array( - 'type' => 'submit', 'name' => 'showhideitems', - 'value' => get_string('showhidechecked', 'checklist') - )); - } - foreach ($this->items as $item) { - - while ($item->indent > $currindent) { - $currindent++; - echo '
      '; - } - while ($item->indent < $currindent) { - $currindent--; - echo '
    '; - } - - $itemname = '"item'.$item->id.'"'; - $thispage->param('itemid', $item->id); - - switch ($item->colour) { - case 'red': - $itemcolour = 'itemred'; - $nexticon = 'colour_orange'; - break; - case 'orange': - $itemcolour = 'itemorange'; - $nexticon = 'colour_green'; - break; - case 'green': - $itemcolour = 'itemgreen'; - $nexticon = 'colour_purple'; - break; - case 'purple': - $itemcolour = 'itempurple'; - $nexticon = 'colour_black'; - break; - default: - $itemcolour = 'itemblack'; - $nexticon = 'colour_red'; - } - - $autoitem = ($this->checklist->autopopulate) && ($item->moduleid != 0); - if ($autoitem) { - $autoclass = ' itemauto'; - } else { - $autoclass = ''; - } - $hasauto = $hasauto || ($item->moduleid != 0); - - echo '
  1. '; - - echo html_writer::start_span('', array('style' => 'display: inline-block; width: 16px;')); - if ($autoitem && $item->hidden != CHECKLIST_HIDDEN_BYMODULE) { - echo html_writer::checkbox('items['.$item->id.']', $item->id, false, '', - array('title' => $item->displaytext)); - } - echo html_writer::end_span(); - - if ($item->itemoptional == CHECKLIST_OPTIONAL_YES) { - $title = '"'.get_string('optionalitem', 'checklist').'"'; - echo ''; - echo '.$title. '; - $optional = ' class="itemoptional '.$itemcolour.$autoclass.'" '; - } else if ($item->itemoptional == CHECKLIST_OPTIONAL_HEADING) { - if ($item->hidden) { - $title = '"'.get_string('headingitem', 'checklist').'"'; - echo '.$title. '; - $optional = ' class="'.$itemcolour.$autoclass.' itemdisabled"'; - } else { - $title = '"'.get_string('headingitem', 'checklist').'"'; - if (!$autoitem) { - echo ''; - } - echo '.$title.'; - if (!$autoitem) { - echo ''; - } - echo ' '; - $optional = ' class="itemheading '.$itemcolour.$autoclass.'" '; - } - } else if ($item->hidden) { - $title = '"'.get_string('requireditem', 'checklist').'"'; - echo '.$title. '; - $optional = ' class="'.$itemcolour.$autoclass.' itemdisabled"'; - } else { - $title = '"'.get_string('requireditem', 'checklist').'"'; - echo ''; - echo '.$title. '; - $optional = ' class="'.$itemcolour.$autoclass.'"'; - } - - if (isset($item->editme)) { - echo ''; - if ($this->editdates) { - $this->print_edit_date($item->duetime); - } - echo ''; - - $focusitem = 'updateitembox'; - - echo ''; - - $addatend = false; - - } else { - echo ' '; - - echo ''; - $title = '"'.get_string('changetextcolour', 'checklist').'"'; - echo '.$title.'; - - if (!$autoitem) { - echo ''; - $title = '"'.get_string('edititem', 'checklist').'"'; - echo '.$title. '; - } - - if (!$autoitem && $item->indent > 0) { - echo ''; - $title = '"'.get_string('unindentitem', 'checklist').'"'; - echo '.$title.'; - } - - if (!$autoitem && ($item->indent < CHECKLIST_MAX_INDENT) && (($lastindent + 1) > $currindent)) { - echo ''; - $title = '"'.get_string('indentitem', 'checklist').'"'; - echo '.$title.'; - } - - echo ' '; - - // TODO more complex checks to take into account indentation. - if (!$autoitem && $item->position > 1) { - echo ''; - $title = '"'.get_string('moveitemup', 'checklist').'"'; - echo '.$title.'; - } - - if (!$autoitem && $item->position < $lastitem) { - echo ''; - $title = '"'.get_string('moveitemdown', 'checklist').'"'; - echo '.$title.'; - } - - if ($autoitem) { - if ($item->hidden != CHECKLIST_HIDDEN_BYMODULE) { - echo ' '; - if ($item->hidden == CHECKLIST_HIDDEN_MANUAL) { - $title = '"'.get_string('show').'"'; - echo '.$title.'; - } else { - $title = '"'.get_string('hide').'"'; - echo '.$title.'; - } - } - } else { - echo ' '; - $title = '"'.get_string('deleteitem', 'checklist').'"'; - echo '.$title.'; - } - - echo '   '; - $title = '"'.get_string('additemhere', 'checklist').'"'; - echo '.$title.'; - if ($item->duetime) { - if ($item->duetime > time()) { - echo ' '.userdate($item->duetime, get_string('strftimedate')).''; - } else { - echo ' '. - userdate($item->duetime, get_string('strftimedate')).''; - } - } - - } - - $thispage->remove_params(array('itemid')); - - if ($this->additemafter == $item->id) { - $addatend = false; - echo '
  2. '; - echo ''; - echo ''; - echo ' '; - echo ''; - if ($this->editdates) { - $this->print_edit_date(); - } - echo ''; - echo ''; - echo '
  3. '; - - if (!$focusitem) { - $focusitem = 'additembox'; - } - } - - $lastindent = $currindent; - - echo ''; - } - - echo html_writer::end_tag('form'); - } - - $thispage->remove_params(array('itemid')); - - if ($addatend) { - echo '
  4. '; - echo '
    '; - echo html_writer::input_hidden_params($thispage); - echo ''; - echo ''; - echo ''; - if ($this->editdates) { - $this->print_edit_date(); - } - echo ''; - echo '
    '; - echo '
  5. '; - if (!$focusitem) { - $focusitem = 'additembox'; - } - } - echo '
'; - while ($currindent) { - $currindent--; - echo ''; - } - - echo '
'; - echo html_writer::input_hidden_params($thispage, array('sesskey', 'editdates')); - if (!$this->editdates) { - echo ''; - echo ''; - } else { - echo ''; - } - if (!$this->checklist->autopopulate && $hasauto) { - echo ''; - echo ''; - } - echo '
'; - - if ($focusitem) { - echo ''; - } - - echo $OUTPUT->box_end(); + $this->output->checklist_edit_items($this->items, $status); } protected function view_report() { @@ -2174,7 +1386,7 @@ protected function process_view_actions() { case 'edititem': if ($this->useritems && isset($this->useritems[$itemid])) { - $this->useritems[$itemid]->editme = true; + $this->useritems[$itemid]->set_editme(); } break; @@ -2262,7 +1474,7 @@ protected function process_edit_actions() { break; case 'edititem': if (isset($this->items[$itemid])) { - $this->items[$itemid]->editme = true; + $this->items[$itemid]->set_editme(); } $additemafter = false; break; @@ -2414,8 +1626,6 @@ protected function process_report_actions() { public function additem($displaytext, $userid = 0, $indent = 0, $position = false, $duetime = false, $moduleid = 0, $optional = CHECKLIST_OPTIONAL_NO, $hidden = CHECKLIST_HIDDEN_NO) { - global $DB; - $displaytext = trim($displaytext); if ($displaytext == '') { return false; @@ -2432,7 +1642,7 @@ public function additem($displaytext, $userid = 0, $indent = 0, $position = fals } } - $item = new stdClass; + $item = new checklist_item(); $item->checklist = $this->checklist->id; $item->displaytext = $displaytext; if ($position) { @@ -2451,15 +1661,13 @@ public function additem($displaytext, $userid = 0, $indent = 0, $position = fals $item->eventid = 0; $item->colour = 'black'; $item->moduleid = $moduleid; - $item->checked = false; - $item->id = $DB->insert_record('checklist_item', $item); + $item->insert(); if ($item->id) { if ($userid) { $this->useritems[$item->id] = $item; - $this->useritems[$item->id]->checked = false; if ($position) { - uasort($this->useritems, 'checklist_itemcompare'); + checklist_item::sort_items($this->useritems); } } else { if ($position) { @@ -2467,11 +1675,9 @@ public function additem($displaytext, $userid = 0, $indent = 0, $position = fals $this->update_item_positions(1, $position); } $this->items[$item->id] = $item; - $this->items[$item->id]->checked = false; - $this->items[$item->id]->teachermark = CHECKLIST_TEACHERMARK_UNDECIDED; - uasort($this->items, 'checklist_itemcompare'); + checklist_item::sort_items($this->items); if ($this->checklist->duedatesoncalendar) { - $this->setevent($item->id, true); + $this->setevent($item, true); } } } @@ -2479,13 +1685,10 @@ public function additem($displaytext, $userid = 0, $indent = 0, $position = fals return $item->id; } - protected function setevent($itemid, $add) { - global $CFG, $DB; + protected function setevent(checklist_item $item, $add) { + global $CFG; require_once($CFG->dirroot.'/calendar/lib.php'); - $item = $this->items[$itemid]; - $update = false; - if ((!$add) || ($item->duetime == 0)) { // Remove the event (if any). if (!$item->eventid) { return; // No event to remove. @@ -2497,8 +1700,11 @@ protected function setevent($itemid, $add) { } catch (dml_missing_record_exception $e) { // Just ignore this error - the event is missing, so does not need deleting. } - $this->items[$itemid]->eventid = 0; - $update = true; + $item->eventid = 0; + if ($add) { + // Don't bother updating the record if we are deleting. + $item->update(); + } } else { // Add/update event. $eventdata = new stdClass(); @@ -2520,17 +1726,10 @@ protected function setevent($itemid, $add) { } if (!$item->eventid) { $event = calendar_event::create($eventdata, false); - $this->items[$itemid]->eventid = $event->id; - $update = true; + $item->eventid = $event->id; + $item->update(); } } - - if ($update) { // Event added or removed. - $upditem = new stdClass(); - $upditem->id = $itemid; - $upditem->eventid = $this->items[$itemid]->eventid; - $DB->update_record('checklist_item', $upditem); - } } public function setallevents() { @@ -2539,14 +1738,12 @@ public function setallevents() { } $add = $this->checklist->duedatesoncalendar; - foreach ($this->items as $key => $value) { - $this->setevent($key, $add); + foreach ($this->items as $item) { + $this->setevent($item, $add); } } protected function updateitemtext($itemid, $displaytext, $duetime = false) { - global $DB; - $displaytext = trim($displaytext); if ($displaytext == '') { return; @@ -2554,95 +1751,48 @@ protected function updateitemtext($itemid, $displaytext, $duetime = false) { if (isset($this->items[$itemid])) { if ($this->canedit()) { - $this->items[$itemid]->displaytext = $displaytext; - $upditem = new stdClass; - $upditem->id = $itemid; - $upditem->displaytext = $displaytext; - - $upditem->duetime = 0; + $item = $this->items[$itemid]; + $item->displaytext = $displaytext; + $item->duetime = 0; if ($duetime) { - $upditem->duetime = make_timestamp($duetime['year'], $duetime['month'], $duetime['day']); + $item->duetime = make_timestamp($duetime['year'], $duetime['month'], $duetime['day']); } - $this->items[$itemid]->duetime = $upditem->duetime; - - $DB->update_record('checklist_item', $upditem); - + $item->update(); if ($this->checklist->duedatesoncalendar) { - $this->setevent($itemid, true); + $this->setevent($item, true); } } } else if (isset($this->useritems[$itemid])) { if ($this->canaddown()) { - $this->useritems[$itemid]->displaytext = $displaytext; - $upditem = new stdClass; - $upditem->id = $itemid; - $upditem->displaytext = $displaytext; - $DB->update_record('checklist_item', $upditem); + $item = $this->useritems[$itemid]; + $item->displaytext = $displaytext; + $item->update(); } } } protected function toggledisableitem($itemid) { - global $DB; - if (isset($this->items[$itemid])) { if (!$this->canedit()) { return; } $item = $this->items[$itemid]; - if ($item->hidden == CHECKLIST_HIDDEN_NO) { - $item->hidden = CHECKLIST_HIDDEN_MANUAL; - } else if ($item->hidden == CHECKLIST_HIDDEN_MANUAL) { - $item->hidden = CHECKLIST_HIDDEN_NO; - } - - $upditem = new stdClass; - $upditem->id = $itemid; - $upditem->hidden = $item->hidden; - $DB->update_record('checklist_item', $upditem); + $item->toggle_hidden(); // If the item is a section heading, then show/hide all items in that section. - if ($item->itemoptional == CHECKLIST_OPTIONAL_HEADING) { - if ($item->hidden) { - foreach ($this->items as $it) { - if ($it->position <= $item->position) { - continue; - } - if ($it->itemoptional == CHECKLIST_OPTIONAL_HEADING) { - break; - } - if (!$it->moduleid) { - continue; - } - if ($it->hidden == CHECKLIST_HIDDEN_NO) { - $it->hidden = CHECKLIST_HIDDEN_MANUAL; - $upditem = new stdClass; - $upditem->id = $it->id; - $upditem->hidden = $it->hidden; - $DB->update_record('checklist_item', $upditem); - } + if ($item->is_heading()) { + foreach ($this->items as $it) { + if ($it->position <= $item->position) { + continue; // Loop until we find the current item. } - - } else { - - foreach ($this->items as $it) { - if ($it->position <= $item->position) { - continue; - } - if ($it->itemoptional == CHECKLIST_OPTIONAL_HEADING) { - break; - } - if (!$it->moduleid) { - continue; - } - if ($it->hidden == CHECKLIST_HIDDEN_MANUAL) { - $it->hidden = CHECKLIST_HIDDEN_NO; - $upditem = new stdClass; - $upditem->id = $it->id; - $upditem->hidden = $it->hidden; - $DB->update_record('checklist_item', $upditem); - } + if ($it->is_heading()) { + break; // Stop at the next heading. + } + if ($item->hidden) { + $it->hide_item(); + } else { + $it->show_item(); } } } @@ -2657,19 +1807,21 @@ protected function deleteitem($itemid, $forcedelete = false) { if (!$forcedelete && !$this->canedit()) { return; } - $this->setevent($itemid, false); // Remove any calendar events. + $item = $this->items[$itemid]; + $this->setevent($item, false); // Remove any calendar events. unset($this->items[$itemid]); } else if (isset($this->useritems[$itemid])) { if (!$this->canaddown()) { return; } + $item = $this->useritems[$itemid]; unset($this->useritems[$itemid]); } else { // Item for deletion is not currently available. return; } - $DB->delete_records('checklist_item', array('id' => $itemid)); + $item->delete(); $DB->delete_records('checklist_check', array('item' => $itemid)); $this->update_item_positions(); @@ -2681,11 +1833,9 @@ protected function moveitemto($itemid, $newposition, $forceupdate = false) { if (!isset($this->items[$itemid])) { if (isset($this->useritems[$itemid])) { if ($this->canupdateown()) { - $this->useritems[$itemid]->position = $newposition; - $upditem = new stdClass; - $upditem->id = $itemid; - $upditem->position = $newposition; - $DB->update_record('checklist_item', $upditem); + $item = $this->useritems[$itemid]; + $item->position = $newposition; + $item->update(); } } return; @@ -2713,12 +1863,10 @@ protected function moveitemto($itemid, $newposition, $forceupdate = false) { $this->update_item_positions(-1, $oldposition, $newposition); // Move items up (including this one). } - $this->items[$itemid]->position = $newposition; // Move item to new position. - uasort($this->items, 'checklist_itemcompare'); // Sort the array by position. - $upditem = new stdClass; - $upditem->id = $itemid; - $upditem->position = $newposition; - $DB->update_record('checklist_item', $upditem); // Update the database. + $item = $this->items[$itemid]; + $item->position = $newposition; // Move item to new position. + $item->update(); + checklist_item::sort_items($this->items); } protected function moveitemup($itemid) { @@ -2746,15 +1894,13 @@ protected function moveitemdown($itemid) { } protected function indentitemto($itemid, $indent) { - global $DB; - if (!isset($this->items[$itemid])) { // Not able to indent useritems, as they are always parent + 1. return; } + $item = $this->items[$itemid]; - $position = $this->items[$itemid]->position; - if ($position == 1) { + if ($item->position == 1) { $indent = 0; } @@ -2764,26 +1910,20 @@ protected function indentitemto($itemid, $indent) { $indent = CHECKLIST_MAX_INDENT; } - $oldindent = $this->items[$itemid]->indent; + $oldindent = $item->indent; $adjust = $indent - $oldindent; if ($adjust == 0) { return; } - $this->items[$itemid]->indent = $indent; - $upditem = new stdClass; - $upditem->id = $itemid; - $upditem->indent = $indent; - $DB->update_record('checklist_item', $upditem); + $item->indent = $indent; + $item->update(); // Update all 'children' of this item to new indent. - foreach ($this->items as $item) { - if ($item->position > $position) { - if ($item->indent > $oldindent) { - $item->indent += $adjust; - $upditem = new stdClass; - $upditem->id = $item->id; - $upditem->indent = $item->indent; - $DB->update_record('checklist_item', $upditem); + foreach ($this->items as $it) { + if ($it->position > $item->position) { + if ($it->indent > $oldindent) { + $it->indent += $adjust; + $it->update(); } else { break; } @@ -2813,6 +1953,7 @@ protected function makeoptional($itemid, $optional, $heading = false) { if (!isset($this->items[$itemid])) { return; } + $item = $this->items[$itemid]; if ($heading) { $optional = CHECKLIST_OPTIONAL_HEADING; @@ -2822,32 +1963,27 @@ protected function makeoptional($itemid, $optional, $heading = false) { $optional = CHECKLIST_OPTIONAL_NO; } - if ($this->items[$itemid]->moduleid) { - $op = $this->items[$itemid]->itemoptional; - if ($op == CHECKLIST_OPTIONAL_HEADING) { + if ($item->moduleid) { + if ($item->is_heading()) { return; // Topic headings must stay as headings. - } else if ($this->items[$itemid]->itemoptional == CHECKLIST_OPTIONAL_YES) { + } else if ($item->itemoptional == CHECKLIST_OPTIONAL_YES) { $optional = CHECKLIST_OPTIONAL_NO; // Module links cannot become headings. } else { $optional = CHECKLIST_OPTIONAL_YES; } } - $this->items[$itemid]->itemoptional = $optional; - $upditem = new stdClass; - $upditem->id = $itemid; - $upditem->itemoptional = $optional; - $DB->update_record('checklist_item', $upditem); + $item->itemoptional = $optional; + $item->update(); } protected function nextcolour($itemid) { - global $DB; - if (!isset($this->items[$itemid])) { return; } + $item = $this->items[$itemid]; - switch ($this->items[$itemid]->colour) { + switch ($item->colour) { case 'black': $nextcolour = 'red'; break; @@ -2864,11 +2000,8 @@ protected function nextcolour($itemid) { $nextcolour = 'black'; } - $upditem = new stdClass; - $upditem->id = $itemid; - $upditem->colour = $nextcolour; - $DB->update_record('checklist_item', $upditem); - $this->items[$itemid]->colour = $nextcolour; + $item->colour = $nextcolour; + $item->update(); } public function ajaxupdatechecks($changechecks) { @@ -2882,7 +2015,7 @@ public function ajaxupdatechecks($changechecks) { } } else { // If no new status, include in array if checked. - if ($item->checked) { + if ($item->is_checked_student()) { $newchecks[] = $item->id; } } @@ -2896,7 +2029,7 @@ public function ajaxupdatechecks($changechecks) { } } else { // If no new status, include in array if checked. - if ($item->checked) { + if ($item->is_checked_student()) { $newchecks[] = $item->id; } } @@ -2907,8 +2040,6 @@ public function ajaxupdatechecks($changechecks) { } protected function updatechecks($newchecks) { - global $DB; - if (!is_array($newchecks)) { // Something has gone wrong, so update nothing. return; @@ -2929,31 +2060,8 @@ protected function updatechecks($newchecks) { } $newval = in_array($item->id, $newchecks); - - if ($newval != $item->checked) { + if ($item->set_checked_student($this->userid, $newval)) { $updategrades = true; - $item->checked = $newval; - - $check = $DB->get_record('checklist_check', array('item' => $item->id, 'userid' => $this->userid)); - if ($check) { - if ($newval) { - $check->usertimestamp = time(); - } else { - $check->usertimestamp = 0; - } - - $DB->update_record('checklist_check', $check); - - } else { - $check = new stdClass; - $check->item = $item->id; - $check->userid = $this->userid; - $check->usertimestamp = time(); - $check->teachertimestamp = 0; - $check->teachermark = CHECKLIST_TEACHERMARK_UNDECIDED; - - $check->id = $DB->insert_record('checklist_check', $check); - } } } } @@ -2964,36 +2072,13 @@ protected function updatechecks($newchecks) { if ($this->useritems) { foreach ($this->useritems as $item) { $newval = in_array($item->id, $newchecks); - - if ($newval != $item->checked) { - $item->checked = $newval; - - $check = $DB->get_record('checklist_check', array('item' => $item->id, 'userid' => $this->userid)); - if ($check) { - if ($newval) { - $check->usertimestamp = time(); - } else { - $check->usertimestamp = 0; - } - $DB->update_record('checklist_check', $check); - - } else { - $check = new stdClass; - $check->item = $item->id; - $check->userid = $this->userid; - $check->usertimestamp = time(); - $check->teachertimestamp = 0; - $check->teachermark = CHECKLIST_TEACHERMARK_UNDECIDED; - - $check->id = $DB->insert_record('checklist_check', $check); - } - } + $item->set_checked_student($this->userid, $newval); } } } protected function updateteachermarks() { - global $USER, $DB, $CFG; + global $USER, $DB; $newchecks = optional_param_array('items', array(), PARAM_TEXT); if (!is_array($newchecks)) { @@ -3002,7 +2087,7 @@ protected function updateteachermarks() { } if ($this->checklist->teacheredit != CHECKLIST_MARKING_STUDENT) { - if (!$student = $DB->get_record('user', array('id' => $this->userid))) { + if (!$DB->record_exists('user', ['id' => $this->userid])) { error('No such user!'); } $params = array( @@ -3019,11 +2104,7 @@ protected function updateteachermarks() { $this->update_teachermarks($newchecks, $USER->id, $teachermarklocked); } - if ($CFG->version < 2011120100) { - $newcomments = optional_param('teachercomment', false, PARAM_TEXT); - } else { - $newcomments = optional_param_array('teachercomment', false, PARAM_TEXT); - } + $newcomments = optional_param_array('teachercomment', false, PARAM_TEXT); if (!$this->checklist->teachercomments || !$newcomments || !is_array($newcomments)) { return; } @@ -3075,37 +2156,17 @@ protected function updateteachermarks() { * @param bool $teachermarklocked (optional) set to true to prevent teachers from changing 'yes' to 'no'. */ public function update_teachermarks($newchecks, $teacherid, $teachermarklocked = false) { - global $DB; - $updategrades = false; foreach ($newchecks as $itemid => $newval) { if (isset($this->items[$itemid])) { $item = $this->items[$itemid]; - if ($teachermarklocked && $item->teachermark == CHECKLIST_TEACHERMARK_YES) { + if ($teachermarklocked && $item->is_checked_teacher()) { continue; // Does not have permission to update marks that are already 'Yes'. } - if ($newval != $item->teachermark) { - $updategrades = true; - - $newcheck = new stdClass; - $newcheck->teachertimestamp = time(); - $newcheck->teachermark = $newval; - $newcheck->teacherid = $teacherid; - - $item->teachermark = $newcheck->teachermark; - $item->teachertimestamp = $newcheck->teachertimestamp; - $item->teacherid = $newcheck->teacherid; - $oldcheck = $DB->get_record('checklist_check', array('item' => $item->id, 'userid' => $this->userid)); - if ($oldcheck) { - $newcheck->id = $oldcheck->id; - $DB->update_record('checklist_check', $newcheck); - } else { - $newcheck->item = $itemid; - $newcheck->userid = $this->userid; - $newcheck->id = $DB->insert_record('checklist_check', $newcheck); - } + if ($item->set_teachermark($this->userid, $newval, $teacherid)) { + $updategrades = true; } } } @@ -3135,17 +2196,15 @@ protected function updateallteachermarks() { continue; } foreach ($checkdata as $itemid => $val) { - if ($val != CHECKLIST_TEACHERMARK_NO && $val != CHECKLIST_TEACHERMARK_YES - && $val != CHECKLIST_TEACHERMARK_UNDECIDED - ) { - continue; // Invalid value. - } if (!$itemid) { continue; } if (!array_key_exists($itemid, $this->items)) { continue; // Item is not part of this checklist. } + if (!checklist_check::teachermark_valid($val)) { + continue; // Invalid value. + } if (!array_key_exists($userid, $userchecks)) { $userchecks[$userid] = array(); } @@ -3160,10 +2219,7 @@ protected function updateallteachermarks() { $teachermarklocked = $this->checklist->lockteachermarks && !has_capability('mod/checklist:updatelocked', $this->context); foreach ($userchecks as $userid => $items) { - list($isql, $iparams) = $DB->get_in_or_equal(array_keys($items)); - $params = array_merge(array($userid), $iparams); - $currentchecks = $DB->get_records_select('checklist_check', "userid = ? AND item $isql", - $params, '', 'item, id, teachermark'); + $currentchecks = checklist_check::fetch_by_userid_itemids($userid, array_keys($items)); $updategrades = false; foreach ($items as $itemid => $val) { if (!array_key_exists($itemid, $currentchecks)) { @@ -3172,30 +2228,25 @@ protected function updateallteachermarks() { } // No entry for this item - need to create it. - $newcheck = new stdClass; - $newcheck->item = $itemid; - $newcheck->userid = $userid; - $newcheck->teachermark = $val; - $newcheck->teachertimestamp = time(); - $newcheck->usertimestamp = 0; - $newcheck->teacherid = $USER->id; - - $DB->insert_record('checklist_check', $newcheck); + $newcheck = new checklist_check(['item' => $itemid, 'userid' => $userid], false); + $newcheck->set_teachermark($val, $USER->id); + $newcheck->save(); + $updategrades = true; - } else if ($currentchecks[$itemid]->teachermark != $val) { - if ($teachermarklocked && $currentchecks[$itemid]->teachermark == CHECKLIST_TEACHERMARK_YES) { - continue; - } + } else { + $current = $currentchecks[$itemid]; + if ($current->teachermark != $val) { + if ($teachermarklocked && $current->teachermark == CHECKLIST_TEACHERMARK_YES) { + continue; + } - $updcheck = new stdClass; - $updcheck->id = $currentchecks[$itemid]->id; - $updcheck->teachermark = $val; - $updcheck->teachertimestamp = time(); - $updcheck->teacherid = $USER->id; + // Update the existing item. + $current->set_teachermark($val, $USER->id); + $current->save(); - $DB->update_record('checklist_check', $updcheck); - $updategrades = true; + $updategrades = true; + } } } if ($updategrades) { @@ -3244,22 +2295,10 @@ public function update_all_autoupdate_checks() { if ($compdata->completionstate == COMPLETION_COMPLETE || $compdata->completionstate == COMPLETION_COMPLETE_PASS ) { - $check = $DB->get_record('checklist_check', array('item' => $item->itemid, 'userid' => $user->id)); - if ($check) { - if ($check->usertimestamp) { - continue; - } - $check->usertimestamp = time(); - $DB->update_record('checklist_check', $check); - } else { - $check = new stdClass; - $check->item = $item->itemid; - $check->userid = $user->id; - $check->usertimestamp = time(); - $check->teachertimestamp = 0; - $check->teachermark = CHECKLIST_TEACHERMARK_UNDECIDED; - - $check->id = $DB->insert_record('checklist_check', $check); + $check = new checklist_check(['item' => $item->itemid, 'userid' => $user->id]); + if (!$check->is_checked_student()) { + $check->set_checked_student(true); + $check->save(); } } } @@ -3272,22 +2311,10 @@ public function update_all_autoupdate_checks() { } foreach ($loguserids as $loguserid) { - $check = $DB->get_record('checklist_check', array('item' => $item->itemid, 'userid' => $loguserid)); - if ($check) { - if ($check->usertimestamp) { - continue; - } - $check->usertimestamp = time(); - $DB->update_record('checklist_check', $check); - } else { - $check = new stdClass; - $check->item = $item->itemid; - $check->userid = $loguserid; - $check->usertimestamp = time(); - $check->teachertimestamp = 0; - $check->teachermark = CHECKLIST_TEACHERMARK_UNDECIDED; - - $check->id = $DB->insert_record('checklist_check', $check); + $check = new checklist_check(['item' => $item->itemid, 'userid' => $loguserid]); + if (!$check->is_checked_student()) { + $check->set_checked_student(true); + $check->save(); } } @@ -3349,8 +2376,6 @@ protected function getnextuserid() { public static function print_user_progressbar($checklistid, $userid, $width = '300px', $showpercent = true, $return = false, $hidecomplete = false) { - global $OUTPUT; - list($ticked, $total) = self::get_user_progress($checklistid, $userid); if (!$total) { return ''; @@ -3358,22 +2383,15 @@ public static function print_user_progressbar($checklistid, $userid, $width = '3 if ($hidecomplete && ($ticked == $total)) { return ''; } - $percent = $ticked * 100 / $total; - // TODO - fix this now that styles.css is included. - $output = '
'; - $output .= '
 
'; - $output .= '
'; - if ($showpercent) { - $output .= ' '.sprintf('%0d%%', $percent).''; - } - $output .= '
'; + $output = self::get_renderer(); + + $out = $output->progress_bar_external($total, $ticked, $width, $showpercent); if ($return) { - return $output; + return $out; } - echo $output; + echo $out; return ''; } @@ -3451,19 +2469,4 @@ public function get_itemid_by_name($itemname, $strictness = MUST_EXIST) { } return null; } - -} - -function checklist_itemcompare($item1, $item2) { - if ($item1->position < $item2->position) { - return -1; - } else if ($item1->position > $item2->position) { - return 1; - } - if ($item1->id < $item2->id) { - return -1; - } else if ($item1->id > $item2->id) { - return 1; - } - return 0; } diff --git a/renderer.php b/renderer.php new file mode 100644 index 00000000..d25e4e3d --- /dev/null +++ b/renderer.php @@ -0,0 +1,898 @@ +. + +/** + * Checklist output functions. + * + * @package mod_checklist + * @copyright 2016 Davo Smith, Synergy Learning + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +use mod_checklist\local\checklist_item; +use mod_checklist\local\output_status; +use mod_checklist\local\progress_info; + +defined('MOODLE_INTERNAL') || die(); + +class mod_checklist_renderer extends plugin_renderer_base { + public function progress_bars($totalitems, $requireditems, $allcompleteitems, $reqcompleteitems) { + $out = ''; + + if ($requireditems > 0 && $totalitems > $requireditems) { + $out .= $this->progress_bar($requireditems, $reqcompleteitems, true); + } + $out .= $this->progress_bar($totalitems, $allcompleteitems, false); + + return $out; + } + + public function progress_bar($totalitems, $completeitems, $isrequired) { + $out = ''; + + $percentcomplete = $totalitems ? (($completeitems * 100.0) / $totalitems) : 0.0; + if ($isrequired) { + $heading = get_string('percentcomplete', 'checklist'); + $spanid = 'checklistprogressrequired'; + } else { + $heading = get_string('percentcompleteall', 'checklist'); + $spanid = 'checklistprogressall'; + } + + // Heading. + $heading .= ': '; + $out .= html_writer::div($heading, 'checklist_progress_heading'); + + // Progress bar. + $progress = ''; + $progress .= html_writer::div(' ', 'checklist_progress_inner', ['style' => "width: {$percentcomplete}%;"]); + $progress .= html_writer::div(' ', 'checklist_progress_anim', ['style' => "width: {$percentcomplete}%;"]); + $progress = html_writer::div($progress, 'checklist_progress_outer'); + $progress .= html_writer::span(' '.sprintf('%0d%%', $percentcomplete), 'checklist_progress_percent'); + + // Wrap in span + add clearer br. + $out .= html_writer::span($progress, '', ['id' => $spanid]); + $out .= html_writer::empty_tag('br', ['class' => 'clearer']); + + return $out; + } + + public function progress_bar_external($totalitems, $completeitems, $width, $showpercent) { + $out = ''; + + $percentcomplete = $totalitems ? ($completeitems * 100.0 / $totalitems) : 0.0; + + $out .= html_writer::div(' ', 'checklist_progress_inner', ['style' => "width: {$percentcomplete}%;"]); + $out = html_writer::div($out, 'checklist_progress_outer', ['style' => "width: $width;"]); + if ($showpercent) { + $out .= html_writer::span(' '.sprintf('%0d%%', $percentcomplete), 'checklist_progress_percent'); + } + $out .= html_writer::empty_tag('br', ['class' => 'clearer']); + return $out; + } + + /** + * @param checklist_item[] $items + * @param checklist_item[] $useritems + * @param bool|int[] $groupings + * @param string $intro + * @param output_status $status + * @param progress_info|null $progress + * @param object $student (optional) the student whose checklist is being viewed (if not viewing own checklist) + */ + public function checklist_items($items, $useritems, $groupings, $intro, output_status $status, $progress, $student = null) { + echo $this->output->box_start('generalbox boxwidthwide boxaligncenter checklistbox'); + + echo html_writer::tag('div', ' ', array('id' => 'checklistspinner')); + + $thispageurl = new moodle_url($this->page->url); + + $strteachername = ''; + $struserdate = ''; + $strteacherdate = ''; + if ($status->is_viewother()) { + echo '

'.get_string('checklistfor', 'checklist').' '.fullname($student, true).'

'; + echo ' '; + echo '
'; + echo html_writer::input_hidden_params($thispageurl, array('studentid')); + echo ''; + echo '
'; + + if (!$status->is_editcomments()) { + echo '
'; + echo html_writer::input_hidden_params($thispageurl); + echo ''; + echo ' '; + echo '
'; + } + echo '
'; + echo html_writer::input_hidden_params($thispageurl); + echo ''; + echo ''; + echo ' '; + echo '
'; + + $strteacherdate = get_string('teacherdate', 'mod_checklist'); + $struserdate = get_string('userdate', 'mod_checklist'); + $strteachername = get_string('teacherid', 'mod_checklist'); + } + + echo $intro; + echo '
'; + + if ($status->is_showprogressbar() && $progress) { + echo $this->progress_bars($progress->totalitems, $progress->requireditems, + $progress->allcompleteitems, $progress->requiredcompleteitems); + } + + if (!$items) { + print_string('noitems', 'checklist'); + } else { + $focusitem = false; + if ($status->is_updateform()) { + if ($status->is_canaddown() && !$status->is_viewother()) { + echo '
'; + echo html_writer::input_hidden_params($thispageurl); + if ($status->is_addown()) { + // Switch on for any other forms on this page (but off if this form submitted). + $thispageurl->param('useredit', 'on'); + echo ''; + } else { + echo ''; + echo ''; + } + echo '
'; + } + + echo '
'; + echo html_writer::input_hidden_params($thispageurl); + echo ''; + echo ''; + } + + if ($useritems) { + reset($useritems); + } + + if ($status->is_teachermarklocked()) { + echo '

'.get_string('lockteachermarkswarning', 'checklist').'

'; + } + + echo '
    '; + $currindent = 0; + foreach ($items as $item) { + + if ($item->hidden) { + continue; + } + + if ($status->is_checkgroupings() && $item->grouping) { + if (!in_array($item->grouping, $groupings)) { + continue; // Current user is not a member of this item's grouping, so skip. + } + } + + while ($item->indent > $currindent) { + $currindent++; + echo '
      '; + } + while ($item->indent < $currindent) { + $currindent--; + echo '
    '; + } + $itemname = '"item'.$item->id.'"'; + $checked = ''; + if ($status->is_updateform() || $status->is_viewother() || $status->is_userreport()) { + if ($item->is_checked_student()) { + $checked = ' checked="checked" '; + } + } + if ($status->is_viewother() || $status->is_userreport()) { + $checked .= ' disabled="disabled" '; + } else if (!$status->is_overrideauto() && $item->moduleid) { + $checked .= ' disabled="disabled" '; + } + switch ($item->colour) { + case 'red': + $itemcolour = 'itemred'; + break; + case 'orange': + $itemcolour = 'itemorange'; + break; + case 'green': + $itemcolour = 'itemgreen'; + break; + case 'purple': + $itemcolour = 'itempurple'; + break; + default: + $itemcolour = 'itemblack'; + } + + $checkclass = ''; + if ($item->is_heading()) { + $optional = ' class="itemheading '.$itemcolour.'" '; + } else if ($item->is_required()) { + $optional = ' class="'.$itemcolour.'" '; + } else { + $optional = ' class="itemoptional '.$itemcolour.'" '; + $checkclass = ' itemoptional'; + } + + echo '
  1. '; + if ($status->is_showteachermark()) { + if (!$item->is_heading()) { + if ($status->is_viewother()) { + $opts = [ + CHECKLIST_TEACHERMARK_UNDECIDED => '', + CHECKLIST_TEACHERMARK_YES => get_string('yes'), + CHECKLIST_TEACHERMARK_NO => get_string('no'), + ]; + $attr = ['id' => 'item'.$item->id]; // TODO davo - fix itemname handling. + if ($status->is_teachermarklocked() && $item->is_checked_teacher()) { + $attr['disabled'] = 'disabled'; + } + + echo html_writer::select($opts, "items[{$item->id}]", $item->teachermark, false, $attr); + + } else { + echo html_writer::empty_tag('img', [ + 'src' => $item->get_teachermark_image_url(), + 'alt' => $item->get_teachermark_text(), + 'title' => $item->get_teachermark_text(), + 'class' => $item->get_teachermark_class(), + ]); + } + } + } + if ($status->is_showcheckbox()) { + if (!$item->is_heading()) { + $id = ' id='.$itemname.' '; + if ($status->is_viewother() && $status->is_showteachermark()) { + $id = ''; + } + echo ''; + } + } + echo ''; + if (isset($item->modulelink)) { + echo ' '.
+                        get_string('linktomodule', 'checklist').''; + } + + if ($status->is_addown()) { + echo ' '; + $title = '"'.get_string('additemalt', 'checklist').'"'; + echo '.$title.'; + } + + if ($item->duetime) { + if ($item->duetime > time()) { + echo ' '.userdate($item->duetime, get_string('strftimedate')).''; + } else { + echo ' '.userdate($item->duetime, get_string('strftimedate')).''; + } + } + + if ($status->is_showcompletiondates()) { + if (!$item->is_heading()) { + if ($status->is_showteachermark() && $item->teachertimestamp) { + if ($item->get_teachername()) { + echo ''.$item->get_teachername().''; + } + echo ''. + userdate($item->teachertimestamp, get_string('strftimedatetimeshort')).''; + } + if ($status->is_showcheckbox() && $item->usertimestamp) { + echo ''. + userdate($item->usertimestamp, get_string('strftimedatetimeshort')).''; + } + } + } + + if ($status->is_teachercomments()) { + if ($comment = $item->get_comment()) { + echo '  '; + if ($comment->commentby) { + echo ''.$comment->get_commentby_name().': '; + } + if ($status->is_editcomments()) { + $outid = ''; + if (!$focusitem) { + $focusitem = 'firstcomment'; + $outid = ' id="firstcomment" '; + } + echo ''; + } else { + echo s($comment->text); + } + echo ' '; + } else if ($status->is_editcomments()) { + echo ' '; + } + } + + echo '
  2. '; + + // Output any user-added items. + if ($useritems) { + /** @var checklist_item $useritem */ + $useritem = current($useritems); + + if ($useritem && ($useritem->position == $item->position)) { + $thisitemurl = new moodle_url($thispageurl, ['action' => 'updateitem', 'sesskey' => sesskey()]); + + echo '
      '; + while ($useritem && ($useritem->position == $item->position)) { + $itemname = '"item'.$useritem->id.'"'; + $checked = ($status->is_updateform() && $useritem->is_checked_student()) ? ' checked="checked" ' : ''; + if ($useritem->is_editme()) { + $itemtext = explode("\n", $useritem->displaytext, 2); + $itemtext[] = ''; + $text = $itemtext[0]; + $note = $itemtext[1]; + $thisitemurl->param('itemid', $useritem->id); + + echo '
    1. '; + echo '
      '; + if ($status->is_showcheckbox()) { + echo ''; + } + echo ''; + echo html_writer::input_hidden_params($thisitemurl); + echo ''; + echo ''; + echo '
      '; + echo ''; + echo ''; + echo '
      '; + + echo '
      '; + echo html_writer::input_hidden_params($thispageurl); + echo ''; + echo '
      '; + echo '
      '; + echo '
    2. '; + + $focusitem = 'updateitembox'; + } else { + echo '
    3. '; + if ($status->is_showcheckbox()) { + echo ''; + } + $splittext = explode("\n", s($useritem->displaytext), 2); + $splittext[] = ''; + $text = $splittext[0]; + $note = str_replace("\n", '
      ', $splittext[1]); + echo ''; + + if ($status->is_addown()) { + $baseurl = $thispageurl.'&itemid='.$useritem->id.'&sesskey='.sesskey().'&action='; + echo ' '; + $title = '"'.get_string('edititem', 'checklist').'"'; + echo '.$title.'; + + echo ' '; + $title = '"'.get_string('deleteitem', 'checklist').'"'; + echo '.$title.'; + } + if ($note != '') { + echo '
      '.$note.'
      '; + } + + echo '
    4. '; + } + $useritem = next($useritems); + } + echo '
    '; + } + } + + if ($status->is_addown() && ($item->id == $status->get_additemafter())) { + $thisitemurl = clone $thispageurl; + $thisitemurl->param('action', 'additem'); + $thisitemurl->param('position', $item->position); + $thisitemurl->param('sesskey', sesskey()); + + echo '
    1. '; + echo '
      '; + echo '
      '; + echo html_writer::input_hidden_params($thisitemurl); + if ($status->is_showcheckbox()) { + echo ''; + } + echo ''; + echo ''; + echo '
      '; + echo ''; + echo '
      '; + echo '
      '; + + echo '
      '; + echo html_writer::input_hidden_params($thispageurl); + echo ''; + echo '
      '; + echo '
      '; + echo '
    '; + + if (!$focusitem) { + $focusitem = 'additembox'; + } + } + } + echo '
'; + + if ($status->is_updateform()) { + echo ''; + if ($status->is_viewother()) { + echo ' '; + echo ' '; + echo ' '; + } + echo ''; + } + + if ($focusitem) { + echo ''; + } + + if ($status->is_addown()) { + echo ''; + } + } + + echo $this->output->box_end(); + } + + /** + * @param checklist_item[] $items + * @param output_status $status + */ + public function checklist_edit_items($items, $status) { + echo $this->output->box_start('generalbox boxwidthwide boxaligncenter'); + + $currindent = 0; + $addatend = true; + $focusitem = false; + $hasauto = false; + + $thispageurl = new moodle_url($this->page->url, ['sesskey' => sesskey()]); + if ($status->get_additemafter()) { + $thispageurl->param('additemafter', $status->get_additemafter()); + } + if ($status->is_editdates()) { + $thispageurl->param('editdates', 'on'); + } + if ($status->get_itemid()) { + $thispageurl->param('itemid', $status->get_itemid()); + } + + if ($status->is_autoupdatewarning()) { + switch ($status->get_autoupdatewarning()) { + case CHECKLIST_MARKING_STUDENT: + echo '

'.get_string('autoupdatewarning_student', 'checklist').'

'; + break; + case CHECKLIST_MARKING_TEACHER: + echo '

'.get_string('autoupdatewarning_teacher', 'checklist').'

'; + break; + default: + echo '

'.get_string('autoupdatewarning_both', 'checklist').'

'; + break; + } + } + + // Start the ordered list of checklist items. + $attr = ['class' => 'checklist']; + if ($status->is_editdates()) { + $attr['class'] .= ' checklist-extendedit'; + } + echo html_writer::start_tag('ol', $attr); + + // Output each item. + if ($items) { + $lastitem = count($items); + $lastindent = 0; + + echo html_writer::start_tag('form', array('action' => $thispageurl->out_omit_querystring(), 'method' => 'post')); + echo html_writer::input_hidden_params($thispageurl); + + if ($status->is_autopopulate()) { + echo html_writer::empty_tag('input', array( + 'type' => 'submit', 'name' => 'showhideitems', + 'value' => get_string('showhidechecked', 'checklist') + )); + } + + foreach ($items as $item) { + + while ($item->indent > $currindent) { + $currindent++; + echo '
    '; + } + while ($item->indent < $currindent) { + $currindent--; + echo '
'; + } + + $itemname = '"item'.$item->id.'"'; + $itemurl = new moodle_url($thispageurl, ['itemid' => $item->id]); + + switch ($item->colour) { + case 'red': + $itemcolour = 'itemred'; + $nexticon = 'colour_orange'; + break; + case 'orange': + $itemcolour = 'itemorange'; + $nexticon = 'colour_green'; + break; + case 'green': + $itemcolour = 'itemgreen'; + $nexticon = 'colour_purple'; + break; + case 'purple': + $itemcolour = 'itempurple'; + $nexticon = 'colour_black'; + break; + default: + $itemcolour = 'itemblack'; + $nexticon = 'colour_red'; + } + + $autoitem = ($status->is_autopopulate()) && ($item->moduleid != 0); + if ($autoitem) { + $autoclass = ' itemauto'; + } else { + $autoclass = ''; + } + $hasauto = $hasauto || ($item->moduleid != 0); + + if ($item->is_editme()) { + echo '
  • '; + } else { + echo '
  • '; + } + + echo html_writer::start_span('', array('style' => 'display: inline-block; width: 16px;')); + if ($autoitem && $item->hidden != CHECKLIST_HIDDEN_BYMODULE) { + echo html_writer::checkbox('items['.$item->id.']', $item->id, false, '', + array('title' => $item->displaytext)); + } + echo html_writer::end_span(); + + // Item optional toggle. + if ($item->is_optional()) { + $title = '"'.get_string('optionalitem', 'checklist').'"'; + echo ''; + echo '.$title. '; + $optional = ' class="itemoptional '.$itemcolour.$autoclass.'" '; + } else if ($item->is_heading()) { + if ($item->hidden) { + $title = '"'.get_string('headingitem', 'checklist').'"'; + echo '.$title. '; + $optional = ' class="'.$itemcolour.$autoclass.' itemdisabled"'; + } else { + $title = '"'.get_string('headingitem', 'checklist').'"'; + if (!$autoitem) { + echo ''; + } + echo '.$title.'; + if (!$autoitem) { + echo ''; + } + echo ' '; + $optional = ' class="itemheading '.$itemcolour.$autoclass.'" '; + } + } else if ($item->hidden) { + $title = '"'.get_string('requireditem', 'checklist').'"'; + echo '.$title. '; + $optional = ' class="'.$itemcolour.$autoclass.' itemdisabled"'; + } else { + $title = '"'.get_string('requireditem', 'checklist').'"'; + echo ''; + echo '.$title. '; + $optional = ' class="'.$itemcolour.$autoclass.'"'; + } + + if ($item->is_editme()) { + // Edit item form. + $focusitem = 'updateitembox'; + $addatend = false; + echo $this->edit_item_form($status, $item); + + } else { + // Item text. + echo ' '; + + // Item colour. + echo ''; + $title = '"'.get_string('changetextcolour', 'checklist').'"'; + echo '.$title.'; + + // Edit item. + if (!$autoitem) { + $edititemurl = new moodle_url($itemurl, ['action' => 'edititem']); + $edititemurl->remove_params('additemafter'); + echo ''; + $title = '"'.get_string('edititem', 'checklist').'"'; + echo '.$title. '; + } + + // Change item indent. + if (!$autoitem && $item->indent > 0) { + echo ''; + $title = '"'.get_string('unindentitem', 'checklist').'"'; + echo '.$title.'; + } + if (!$autoitem && ($item->indent < CHECKLIST_MAX_INDENT) && (($lastindent + 1) > $currindent)) { + echo ''; + $title = '"'.get_string('indentitem', 'checklist').'"'; + echo '.$title.'; + } + + echo ' '; + + // Move item up/down. + if (!$autoitem && $item->position > 1) { + echo ''; + $title = '"'.get_string('moveitemup', 'checklist').'"'; + echo '.$title.'; + } + if (!$autoitem && $item->position < $lastitem) { + echo ''; + $title = '"'.get_string('moveitemdown', 'checklist').'"'; + echo '.$title.'; + } + + // Hide/delete item. + if ($autoitem) { + if ($item->hidden != CHECKLIST_HIDDEN_BYMODULE) { + echo ' '; + if ($item->hidden == CHECKLIST_HIDDEN_MANUAL) { + $title = '"'.get_string('show').'"'; + echo '.$title.'; + } else { + $title = '"'.get_string('hide').'"'; + echo '.$title.'; + } + } + } else { + echo ' '; + $title = '"'.get_string('deleteitem', 'checklist').'"'; + echo '.$title.'; + } + + // Add item icon. + echo '   '; + $title = '"'.get_string('additemhere', 'checklist').'"'; + echo '.$title.'; + if ($item->duetime) { + if ($item->duetime > time()) { + echo ' '.userdate($item->duetime, get_string('strftimedate')).''; + } else { + echo ' '. + userdate($item->duetime, get_string('strftimedate')).''; + } + } + + } + + if ($status->get_additemafter() == $item->id) { + $addatend = false; + if (!$focusitem) { + $focusitem = 'additembox'; + } + echo $this->add_item_form($status, $thispageurl, $currindent, $item->position + 1); + } + + $lastindent = $currindent; + + echo '
  • '; + } + + echo html_writer::end_tag('form'); + } + + if ($addatend) { + if (!$focusitem) { + $focusitem = 'additembox'; + } + echo $this->add_item_form($status, $thispageurl, $currindent); + } + echo ''; + while ($currindent) { + $currindent--; + echo ''; + } + + // Edit dates button. + $editdatesurl = new moodle_url($thispageurl); + $editdatesurl->remove_params('sesskey'); + if ($status->is_editdates()) { + $editdatesurl->remove_params('editdates'); + $editdatesstr = get_string('editdatesstop', 'mod_checklist'); + } else { + $editdatesurl->param('editdates', 'on'); + $editdatesstr = get_string('editdatesstart', 'mod_checklist'); + } + echo $this->output->single_button($editdatesurl, $editdatesstr, 'get'); + + // Remove autopopulate button. + if (!$status->is_autopopulate() && $hasauto) { + $removeautourl = new moodle_url($thispageurl, ['removeauto' => 1]); + echo $this->output->single_button($removeautourl, get_string('removeauto', 'mod_checklist')); + } + + if ($focusitem) { + echo ''; + } + + echo $this->output->box_end(); + } + + protected function print_edit_date($ts = 0) { + $out = ''; + + $out .= '
    '; + $id = uniqid(); + if ($ts == 0) { + $disabled = true; + $date = usergetdate(time()); + } else { + $disabled = false; + $date = usergetdate($ts); + } + $day = $date['mday']; + $month = $date['mon']; + $year = $date['year']; + + // Day. + $opts = range(1, 31); + $opts = array_combine($opts, $opts); + $out .= html_writer::select($opts, 'duetime[day]', $day, null, ['id' => "timedueday{$id}"]); + + // Month. + $opts = []; + for ($i = 1; $i <= 12; $i++) { + $opts[$i] = userdate(gmmktime(12, 0, 0, $i, 15, 2000), "%B"); + } + $out .= html_writer::select($opts, 'duetime[month]', $month, null, ['id' => "timeduemonth{$id}"]); + + // Year. + $today = usergetdate(time()); + $thisyear = $today['year']; + $opts = range($thisyear - 5, $thisyear + 10); + $opts = array_combine($opts, $opts); + $out .= html_writer::select($opts, 'duetime[year]', $year, null, ['id' => "timedueyear{$id}"]); + + // Disabled checkbox. + $attr = [ + 'type' => 'checkbox', 'name' => 'duetimedisable', + 'id' => "timeduedisable{$id}", 'onclick' => "toggledate{$id}()" + ]; + if ($disabled) { + $attr['checked'] = 'checked'; + } + $out .= html_writer::empty_tag('input', $attr); + $out .= html_writer::label(get_string('disable'), "timeduedisable{$id}"); + + // Script to disable items when unchecked. + $out .= <<< ENDSCRIPT + +ENDSCRIPT; + + return $out; + } + + /** + * @param output_status $status + * @param moodle_url $thispageurl + * @param int $currindent + * @param int $position (optional) + * @return string + */ + protected function add_item_form(output_status $status, moodle_url $thispageurl, $currindent, $position = null) { + $out = ''; + $addingatend = ($position === null); + + $out .= '
  • '; + if ($addingatend) { + $out .= '
    '; + $out .= html_writer::input_hidden_params($thispageurl); + } + + if ($addingatend) { + $out .= ''; + } else { + $out .= ''; + } + $out .= ''; + $out .= ' '; + $out .= ''; + $out .= ''; + if (!$addingatend) { + $out .= ''; + } + if ($status->is_editdates()) { + $out .= $this->print_edit_date(); + } + + if ($position === null) { + $out .= '
    '; + } + $out .= '
  • '; + + return $out; + } + + /** + * @param output_status $status + * @param checklist_item $item + * @return string + */ + protected function edit_item_form(output_status $status, checklist_item $item) { + $out = ''; + + $out .= ''; + $out .= ''; + $out .= ''; + if ($status->is_editdates()) { + $out .= $this->print_edit_date($item->duetime); + } + + return $out; + } +} \ No newline at end of file diff --git a/styles.css b/styles.css index eed4f536..94bdc5d4 100644 --- a/styles.css +++ b/styles.css @@ -4,6 +4,9 @@ ol.checklist { margin-top: 10px; margin-bottom: 0; } +ol.checklist ol.checklist { + margin-top: 0; +} ol.checklist li { list-style-type: none; @@ -175,6 +178,12 @@ ol.checklist li .itemteachername { background-color: #bf0000; } +.checklist_progress_heading { + display: block; + float: left; + width: 150px; +} + .checklist_progress_outer { border-width: 1px; border-style: solid; @@ -191,6 +200,7 @@ ol.checklist li .itemteachername { .checklist_progress_inner { background-color: #229b15; + background-image: url([[pix:mod_checklist|progress]]); height: 100%; width: 100%; background-repeat: repeat-x; @@ -206,6 +216,7 @@ ol.checklist li .itemteachername { .checklist_progress_anim { background-color: #98c193; + background-image: url([[pix:mod_checklist|progress-fade]]); height: 15px; width: 0; background-repeat: repeat-x; @@ -256,4 +267,10 @@ p.checklistwarning { ol.checklist label { display: inline; +} + +.checklist-extendedit .checklist-edititem { + border: 1px solid #ddd; + padding: 10px 0 5px; + margin: 5px 0; } \ No newline at end of file diff --git a/updatechecks.php b/updatechecks.php index f93f5461..f7b5dc53 100644 --- a/updatechecks.php +++ b/updatechecks.php @@ -28,7 +28,7 @@ global $DB, $CFG, $PAGE, $USER; $id = required_param('id', PARAM_INT); // Course_module ID. -$items = optional_param_array('items', false, PARAM_INT); +$items = required_param_array('items', PARAM_INT); $url = new moodle_url('/mod/checklist/view.php', array('id' => $id)); @@ -41,19 +41,10 @@ $context = context_module::instance($cm->id); $userid = $USER->id; -if (!has_capability('mod/checklist:updateown', $context)) { - echo 'Error: you do not have permission to update this checklist'; - die(); -} -if (!confirm_sesskey()) { - echo 'Error: invalid sesskey'; - die(); -} -if (!$items || !is_array($items)) { - echo 'Error: invalid (or missing) items list'; - die(); -} -if (!empty($items)) { +require_capability('mod/checklist:updateown', $context); +require_sesskey(); + +if ($items) { $chk = new checklist_class($cm->id, $userid, $checklist, $cm, $course); $chk->ajaxupdatechecks($items); } diff --git a/version.php b/version.php index 23441515..25433963 100644 --- a/version.php +++ b/version.php @@ -27,7 +27,7 @@ $plugin->version = 2016090900; // The current module version (Date: YYYYMMDDXX) $plugin->cron = 0; // Period for cron to check this module (secs). -$plugin->maturity = MATURITY_STABLE; +$plugin->maturity = MATURITY_BETA; $plugin->release = '2.7+ (Build: 2016090900)'; $plugin->requires = 2014051200; // Moodle 2.7+. $plugin->component = 'mod_checklist';