diff --git a/action.php b/action.php index 8c2049fb271880e9d1c4acc94aac623a3e808ce7..0efcba60f75ec6356735a7e9af567596d3605372 100644 --- a/action.php +++ b/action.php @@ -64,6 +64,11 @@ if ($action === 'read') { foreach ($records as $record) { + $comment = $DB->get_record('pdfannotator_comments', array('annotationid' => $record->id, 'isquestion' => 1)); + if ($comment && !pdfannotator_can_see_comment($comment, $context)) { + continue; + } + $entry = json_decode($record->data); // StdClass Object containing data that is specific to the respective annotation type. // Add general annotation data. $entry->type = pdfannotator_get_annotationtype_name($record->annotationtypeid); @@ -376,7 +381,8 @@ if ($action === 'getComments') { $annotationid = required_param('annotationId', PARAM_INT); // Create an array of all comment objects on the specified page and annotation. - $comments = pdfannotator_comment::read($documentid, $annotationid); + + $comments = pdfannotator_comment::read($documentid, $annotationid, $context); require_once($CFG->dirroot . '/mod/pdfannotator/classes/output/comment.php'); $myrenderer = $PAGE->get_renderer('mod_pdfannotator'); @@ -439,8 +445,8 @@ if ($action === 'editComment') { $editanypost = has_capability('mod/pdfannotator:editanypost', $context); $commentid = required_param('commentId', PARAM_INT); - $content = required_param('content', PARAM_RAW); - + $content = required_param('content', PARAM_RAW); + $data = pdfannotator_comment::update($commentid, $content, $editanypost); echo json_encode($data); } @@ -599,7 +605,7 @@ if ($action === 'getCommentsToPrint') { global $DB; // The model retrieves and selects data. - $conversations = pdfannotator_instance::get_conversations($documentid); + $conversations = pdfannotator_instance::get_conversations($documentid, $context); if ($conversations === -1) { // Sth. went wrong with the database query. echo json_encode(['status' => 'error']); diff --git a/backup/moodle2/backup_pdfannotator_stepslib.php b/backup/moodle2/backup_pdfannotator_stepslib.php index fa0545c092d70a1a7ea5f319a740d3ce655d8a95..bf3de9fd21f6c6b330d17cb0a3262f6829c2a7c7 100644 --- a/backup/moodle2/backup_pdfannotator_stepslib.php +++ b/backup/moodle2/backup_pdfannotator_stepslib.php @@ -54,7 +54,7 @@ class backup_pdfannotator_activity_structure_step extends backup_activity_struct // 2. Define each element separately. $pdfannotator = new backup_nested_element('pdfannotator', array('id'), array( - 'name', 'intro', 'introformat', 'usevotes', 'useprint', 'useprintcomments', 'use_studenttextbox', 'use_studentdrawing', 'timecreated', 'timemodified')); + 'name', 'intro', 'introformat', 'usevotes', 'useprint', 'useprintcomments', 'use_studenttextbox', 'use_studentdrawing', 'useprivatecomments', 'useprotectedcomments', 'timecreated', 'timemodified')); $annotations = new backup_nested_element('annotations'); $annotation = new backup_nested_element('annotation', array('id'), array('page', 'userid', 'annotationtypeid', 'data', 'timecreated', 'timemodified', 'modifiedby')); @@ -95,7 +95,10 @@ class backup_pdfannotator_activity_structure_step extends backup_activity_struct // ... if ($userinfo) {? // Add all annotations specific to this annotator instance. - $annotation->set_source_table('pdfannotator_annotations', array('pdfannotatorid' => backup::VAR_PARENTID)); + $annotation->set_source_sql('SELECT a.* FROM {pdfannotator_annotations} a ' + . 'JOIN {pdfannotator_comments} c ON a.id = c.annotationid ' + . 'WHERE a.pdfannotatorid = ? AND c.isquestion = "1" AND (c.visibility = "public" OR c.visibility = "anonymous") ', + array('pdfannotatorid' => backup::VAR_PARENTID)); // Add any subscriptions to this annotation. $subscription->set_source_table('pdfannotator_subscriptions', array('annotationid' => backup::VAR_PARENTID)); diff --git a/classes/output/comment.php b/classes/output/comment.php index 42cd44d05238730f497e5031ecf63e867d2f3fb7..6066cc8aec2170988a91a3c89864e7f2daf1495d 100644 --- a/classes/output/comment.php +++ b/classes/output/comment.php @@ -66,6 +66,9 @@ class comment implements \renderable, \templatable { $owner = ($comment->userid == $USER->id); $comment->owner = ($comment->userid == $USER->id); + $comment->private = ($comment->visibility == "private"); + $comment->protected = ($comment->visibility == "protected"); + $this->addcssclasses($comment, $owner); $this->setvotes($comment); diff --git a/classes/output/index.php b/classes/output/index.php index ba8e1927451747385bfa47ecaa3515e86d1209b1..4b0c276ec0aecb747be5023c3194c1ada57058ee 100644 --- a/classes/output/index.php +++ b/classes/output/index.php @@ -37,6 +37,8 @@ class index implements renderable, templatable { // Class should be placed elsew private $useprint; private $useprintcomments; private $printurl; + private $useprivatecomments; + private $useprotectedcomments; public function __construct($pdfannotator, $capabilities, $file) { @@ -46,6 +48,8 @@ class index implements renderable, templatable { // Class should be placed elsew $this->usestudentdrawing = ($pdfannotator->use_studentdrawing || $capabilities->usedrawing); $this->useprint = ($pdfannotator->useprint || $capabilities->useprint); $this->useprintcomments = ($pdfannotator->useprintcomments || $capabilities->useprintcomments); + $this->useprivatecomments = $pdfannotator->useprivatecomments; + $this->useprotectedcomments = $pdfannotator->useprotectedcomments; $contextid = $file->get_contextid(); $component = $file->get_component(); @@ -68,6 +72,11 @@ class index implements renderable, templatable { // Class should be placed elsew $data->pixsinglefile = $OUTPUT->image_url('/e/new_document'); $data->useprint = $this->useprint; $data->useprintcomments = $this->useprintcomments; + $data->useprivatecomments = $this->useprivatecomments; + $data->useprotectedcomments = $this->useprotectedcomments; + if ($data->useprotectedcomments) { + $data->protectedhelpicon = $OUTPUT->help_icon('protected_comments', 'mod_pdfannotator'); + } $data->printlink = $this->printurl; $data->pixprintdoc = $OUTPUT->image_url('download', 'mod_pdfannotator'); $data->pixprintcomments = $OUTPUT->image_url('print_comments', 'mod_pdfannotator'); diff --git a/controller.php b/controller.php index 19f4af42845a5e6ef03de58f297195870fc64f70..8695c925b9b3c870f7d6d79bd2936dd5e50bea25 100644 --- a/controller.php +++ b/controller.php @@ -446,7 +446,7 @@ if ($action === 'statistic') { $strings = $stringman->load_component_strings('pdfannotator', 'en'); // Method gets the strings of the language files. $PAGE->requires->strings_for_js(array_keys($strings), 'pdfannotator'); // Method to use the language-strings in javascript. $PAGE->requires->js(new moodle_url("/mod/pdfannotator/shared/locallib.js?ver=00002")); - $PAGE->requires->js(new moodle_url("/mod/pdfannotator/shared/statistic.js?ver=0001")); + $PAGE->requires->js(new moodle_url("/mod/pdfannotator/shared/statistic.js?ver=0004")); $myrenderer = $PAGE->get_renderer('mod_pdfannotator'); $capabilities = new stdClass(); $capabilities->viewquestions = has_capability('mod/pdfannotator:viewquestions', $context); diff --git a/db/access.php b/db/access.php index 41bfa292eaf942af12680d9b809757c4c269047e..f4324627dc05ec1e38fbb342515f33ea90119a5d 100644 --- a/db/access.php +++ b/db/access.php @@ -343,4 +343,34 @@ $capabilities = array( ), ), + 'mod/pdfannotator:viewprotectedcomments' => array ( + 'captype' => 'read', + 'contextlevel' => CONTEXT_MODULE, + 'archetypes' => array( + 'manager' => CAP_ALLOW, + ), + ), + + 'mod/pdfannotator:writeprivatecomments' => array ( + 'captype' => 'write', + 'contextlevel' => CONTEXT_MODULE, + 'archetypes' => array( + 'student' => CAP_ALLOW, + 'manager' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + 'teacher' => CAP_ALLOW, + ), + ), + + 'mod/pdfannotator:writeprotectedcomments' => array ( + 'captype' => 'write', + 'contextlevel' => CONTEXT_MODULE, + 'archetypes' => array( + 'student' => CAP_ALLOW, + 'manager' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + 'teacher' => CAP_ALLOW, + ), + ), + ); diff --git a/db/install.xml b/db/install.xml index 077ce1a41fc2c3659d654767b61f190e27770514..3324d944bee9ea463f3a3d9d064af096383b7442 100644 --- a/db/install.xml +++ b/db/install.xml @@ -16,6 +16,8 @@ <FIELD NAME="useprintcomments" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Allow participants to print comments"/> <FIELD NAME="use_studenttextbox" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/> <FIELD NAME="use_studentdrawing" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/> + <FIELD NAME="useprivatecomments" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/> + <FIELD NAME="useprotectedcomments" TYPE="int" LENGTH="2" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/> <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/> <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false"/> </FIELDS> diff --git a/db/upgrade.php b/db/upgrade.php index c3e680ce6a83560700b9c565e8814b534a8cbb60..46454acca5d8f4da6515051ead2bdbba9afd45cf 100644 --- a/db/upgrade.php +++ b/db/upgrade.php @@ -575,5 +575,29 @@ function xmldb_pdfannotator_upgrade($oldversion) { upgrade_mod_savepoint(true, 2019070100, 'pdfannotator'); } + if ($oldversion < 2021032201) { + + // Define field useprivatecomments to be added to pdfannotator. + $table = new xmldb_table('pdfannotator'); + $field = new xmldb_field('useprivatecomments', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'use_studentdrawing'); + + // Conditionally launch add field useprivatecomments. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Define field useprotectedcomments to be added to pdfannotator. + $table = new xmldb_table('pdfannotator'); + $field = new xmldb_field('useprotectedcomments', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0', 'useprivatecomments'); + + // Conditionally launch add field useprotectedcomments. + if (!$dbman->field_exists($table, $field)) { + $dbman->add_field($table, $field); + } + + // Pdfannotator savepoint reached. + upgrade_mod_savepoint(true, 2021032201, 'pdfannotator'); + } + return true; } diff --git a/lang/en/pdfannotator.php b/lang/en/pdfannotator.php index aae8f65b17f57af4cc55cd5efe52c7ecb2044c1c..25eb1c859f3043e0a7133d3d3080a0dc7ef050c2 100644 --- a/lang/en/pdfannotator.php +++ b/lang/en/pdfannotator.php @@ -25,6 +25,8 @@ $string['actiondropdown'] = "Options"; $string['activities'] = 'Activities'; $string['addAComment'] = 'Add a comment'; +$string['add_protected_comment'] = 'Add a comment to private question'; +$string['add_private_comment'] = 'Add a comment to personal note'; $string['ago'] = '{$a} ago'; $string['all'] = 'all'; $string['allanswers'] = 'all'; @@ -157,6 +159,10 @@ $string['global_setting_use_studenttextbox_desc'] = "Please note that textbox an $string['global_setting_useprint'] = 'Allow save and print?'; $string['global_setting_useprint_comments'] = 'Allow saving/printing comments?'; $string['global_setting_useprint_comments_desc'] = 'Allow participants to save and print the annotations and comments'; +$string['global_setting_use_private_comments'] = 'Allow personal notes?'; +$string['global_setting_use_private_comments_desc'] = 'Allow participants to write personal annotations and personal notes'; +$string['global_setting_use_protected_comments'] = 'Allow private comments?'; +$string['global_setting_use_protected_comments_desc'] = 'Allow participants to write private annotations and private comments. Only author and manager can see this comment.'; $string['global_setting_useprint_desc'] = 'Allow participants to save and print the pdf document and its comments'; $string['global_setting_useprint_document'] = 'Allow saving/printing document?'; $string['global_setting_useprint_document_desc'] = 'Allow participants to save and print the pdf document'; @@ -215,6 +221,9 @@ $string['month'] = 'month'; $string['months'] = 'months'; $string['myanswers'] = 'my answers'; $string['mypost'] = 'My post'; +$string['myprivate'] = 'My personal notes'; +$string['myprotectedanswers'] = 'my private answers'; +$string['myprotectedquestions'] = 'my private questions'; $string['myquestion'] = 'Question'; $string['myquestions'] = 'my questions'; $string['newanswerhtml'] = 'Your subscribed question "{$a->question}" was answered by {$a->answeruser} with the comment: <br /> <br /> "{$a->content}"<br /><br /> @@ -320,6 +329,12 @@ $string['privacy:metadata:pdfannotator_subscriptions'] = "Information about the $string['privacy:metadata:pdfannotator_votes:commentid'] = "The ID of the comment."; $string['privacy:metadata:pdfannotator_votes:userid'] = "The ID of the user who marked the comment as interesting or helpful. It is saved in order to prevent users from voting for the same comment repeatedly."; $string['privacy:metadata:pdfannotator_votes'] = "Information about questions and comments that were marked as interesting or helpful."; +$string['private_comments'] = "Personal notes"; +$string['protected_answers'] = 'Private answers'; +$string['protected_comments'] = "Private comments"; +$string['protected_comments_help'] = 'Visible only for you and managers.'; +$string['protected_questions'] = 'Private questions'; +$string['public_comments'] = 'Public comments'; $string['question'] = 'Question'; $string['questions'] = 'questions'; $string['questionsimgtitle'] = "Show all questions on this page"; @@ -362,6 +377,8 @@ $string['seeabove'] = ''; $string['seenreports'] = 'read only'; $string['send'] = 'Send'; $string['sendAnonymous'] = 'post anonymous'; +$string['sendPrivate'] = 'post personal note'; +$string['sendProtected'] = 'post private comment'; $string['setting_alternative_name'] = 'Name'; $string['setting_alternative_name_desc'] = 'Provide an alternative name for the PDF. If empty, the name of the pdf will be taken as representative name'; $string['setting_alternative_name_help'] = "If the name is more than 20 characters long, the remaining characters will be replaced with '...' in the annotator's internal tab navigation."; @@ -378,6 +395,10 @@ $string['setting_useprint_comments_help'] = 'Allow participants to save and prin $string['setting_useprint_document'] = 'Save and print pdf document'; $string['setting_useprint_document_help'] = 'Allow participants to save and print the pdf document'; $string['setting_useprint_help'] = "Please note that drawings are not anonymous and can neither be commented nor reported."; +$string['setting_use_private_comments'] = "Allow personal notes"; +$string['setting_use_private_comments_help'] = "Allow participants to write personal notes. Other person cannot see this comment."; +$string['setting_use_protected_comments'] = "Allow private comments"; +$string['setting_use_protected_comments_help'] = "Allow participants to write private comments. Only author and manager can see this comment."; $string['setting_usevotes'] = "Votes/Likes"; $string['setting_usevotes_help'] = "With this option enabled, users can like / vote for posts other than their own."; $string['show'] = 'Show'; @@ -425,6 +446,8 @@ $string['use_studentdrawing'] = "Enable drawing for participants?"; $string['use_studenttextbox'] = "Enable textbox tool for participants?"; $string['useprint'] = "Give participants access to the PDF?"; $string['useprint_comments'] = "Give participants access to the PDF and its comments?"; +$string['use_private_comments'] = "Allow participants to write personal notes?"; +$string['use_protected_comments'] = "Allow participants to write private comments?"; $string['useprint_document'] = "Give participants access to the PDF?"; $string['usevotes'] = "Allow users to like comments."; $string['view'] = 'Document'; diff --git a/locallib.php b/locallib.php index 660ad2507aef950106b3c2ccf3e928e3c0bf7ad3..bf70e9eabffd52c6f955bb22a6cd4aeb623b56ae 100644 --- a/locallib.php +++ b/locallib.php @@ -58,8 +58,8 @@ function pdfannotator_display_embed($pdfannotator, $cm, $course, $file, $page = $PAGE->requires->js(new moodle_url("/mod/pdfannotator/shared/pdf.js")); $PAGE->requires->js(new moodle_url("/mod/pdfannotator/shared/pdf_viewer.js")); $PAGE->requires->js(new moodle_url("/mod/pdfannotator/shared/textclipper.js")); - $PAGE->requires->js(new moodle_url("/mod/pdfannotator/shared/index.js?ver=00012i")); - $PAGE->requires->js(new moodle_url("/mod/pdfannotator/shared/locallib.js?ver=00002")); + $PAGE->requires->js(new moodle_url("/mod/pdfannotator/shared/index.js?ver=00014")); + $PAGE->requires->js(new moodle_url("/mod/pdfannotator/shared/locallib.js?ver=00003")); // Pass parameters from PHP to JavaScript. @@ -89,6 +89,7 @@ function pdfannotator_display_embed($pdfannotator, $cm, $course, $file, $page = // The renderer renders the original index.php / takes the template and renders it. $myrenderer = $PAGE->get_renderer('mod_pdfannotator'); echo $myrenderer->render_index(new index($pdfannotator, $capabilities, $file)); + $PAGE->requires->js_init_call('checkOnlyOneCheckbox', null, true); pdfannotator_print_intro($pdfannotator, $cm, $course); @@ -135,7 +136,7 @@ function pdfannotator_get_annotationtype_name($typeid) { function pdfannotator_handle_latex($context, string $subject) { global $CFG; require_once($CFG->dirroot . '/mod/pdfannotator/constants.php'); - $latexapi = get_config('mod_pdfannotator','latexapi'); + $latexapi = get_config('mod_pdfannotator', 'latexapi'); // Look for these formulae: $$ ... $$, \( ... \) and \[ ... \] // !!! keep indentation! @@ -188,7 +189,7 @@ SIGN; $match[0] = $string; $result[] = trim(substr($subject, $textstart, $formulaoffset - $textstart)); - if($latexapi == LATEX_TO_PNG_GOOGLE_API) { + if ($latexapi == LATEX_TO_PNG_GOOGLE_API) { $result[] = pdfannotator_process_latex_google($match[0]); } else { $result[] = pdfannotator_process_latex_moodle($context, $match[0]); @@ -210,7 +211,7 @@ function pdfannotator_process_latex_moodle($context, $string) { $tex = new latex(); $md5 = md5($string); $image = $tex->render($string, $md5 . 'png'); - if($image == false) { + if ($image == false) { return false; } $imagedata = file_get_contents($image); @@ -228,7 +229,7 @@ function pdfannotator_process_latex_moodle($context, $string) { * @return type */ function pdfannotator_process_latex_google(string $string) { - + $length = strlen($string); $im = null; if ($length <= 200) { // Google API constraint XXX find better alternative if possible. @@ -720,9 +721,9 @@ function pdfannotator_get_questions($courseid, $context, $questionfilter) { $cminfo = pdfannotator_instance::get_cm_info($courseid); list($insql, $inparams) = $DB->get_in_or_equal(array_keys($cminfo)); - $sql = "SELECT a.id as annoid, a.page, a.pdfannotatorid, p.name AS pdfannotatorname, p.usevotes, cm.id AS cmid, " + $sql = "SELECT a.id as annoid, a.page, a.pdfannotatorid, p.name AS pdfannotatorname, p.usevotes, cm.id AS cmid, c.isquestion, " . "c.id as commentid, c.content, c.userid, c.visibility, c.timecreated, c.isdeleted, c.ishidden, " - . "SUM(vote) AS votes, COUNT(answ.id)-1 AS answercount, MAX(answ.timecreated) AS lastanswered " + . "SUM(vote) AS votes, MAX(answ.timecreated) AS lastanswered " . "FROM {pdfannotator_annotations} a " . "JOIN {pdfannotator_comments} c ON c.annotationid = a.id " . "JOIN {pdfannotator} p ON a.pdfannotatorid = p.id " @@ -744,24 +745,25 @@ function pdfannotator_get_questions($courseid, $context, $questionfilter) { $labelhidden = "<br><span class='tag tag-info'>" . get_string('hiddenfromstudents') . "</span>"; // XXX use moodle method if exists. $labelunavailable = "<br><span class='tag tag-info'>" . get_string('restricted') . "</span>"; + $res = []; foreach ($questions as $key => $question) { + if (!pdfannotator_can_see_comment($question, $context)) { + continue; + } + if (empty($question->votes)) { $question->votes = 0; } if ($question->usevotes == 0) { $question->votes = '-'; } - if (empty($question->answercount)) { - $question->answercount = 0; - } - if ($question->lastanswered != $question->timecreated) { - $conditions = array('annotationid' => $question->annoid, 'timecreated' => $question->lastanswered, 'isquestion' => 0); - $r = $DB->get_record('pdfannotator_comments', $conditions, 'userid, visibility', IGNORE_MISSING); - if (!empty($r)) { - $question->lastuser = $r->userid; - $question->lastuservisibility = $r->visibility; - } + $question->answercount = pdfannotator_count_answers($question->annoid, $context); + + $lastanswer = pdfannotator_get_last_answer($question->annoid, $context); + if ($lastanswer) { + $question->lastuser = $lastanswer->userid; + $question->lastuservisibility = $lastanswer->visibility; } else { $question->lastanswered = false; } @@ -794,8 +796,11 @@ function pdfannotator_get_questions($courseid, $context, $questionfilter) { $question->content = format_text($question->content); $question->link = (new moodle_url('/mod/pdfannotator/view.php', array('id' => $question->cmid, 'page' => $question->page, 'annoid' => $question->annoid, 'commid' => $question->commentid)))->out(); + + $res[] = $question; + } - return $questions; + return $res; } /** @@ -895,8 +900,9 @@ function pdfannotator_get_answers_for_this_user($courseid, $context, $answerfilt $labelunavailable = "<br><span class='tag tag-info'>" . get_string('restricted') . "</span>"; if ($answerfilter == 0) { // Either: get all answers in this annotator. - $sql = "SELECT c.id AS answerid, c.content AS answer, c.userid AS answeredby, c.visibility, " - . "c.timemodified, c.solved AS correct, c.ishidden AS answerhidden, a.id AS annoid, a.page, q.id AS questionid, " + $sql = "SELECT c.id AS answerid, c.content AS answer, c.userid AS userid, c.visibility, " + . "c.timemodified, c.solved AS correct, c.ishidden AS answerhidden, a.id AS annoid, a.page, q.id AS questionid, q.userid AS questionuserid, c.isquestion, c.annotationid, " + . "q.visibility AS questionvisibility, " . "q.content AS answeredquestion, q.isdeleted AS questiondeleted, q.ishidden AS questionhidden, p.id AS annotatorid, " . "p.name AS pdfannotatorname, cm.id AS cmid, s.id AS issubscribed " . "FROM {pdfannotator_annotations} a " @@ -908,8 +914,9 @@ function pdfannotator_get_answers_for_this_user($courseid, $context, $answerfilt . "WHERE p.course = ? AND q.isquestion = 1 AND NOT c.isquestion = 1 AND NOT c.isdeleted = 1 AND cm.id $insql " . "ORDER BY annoid ASC"; } else { // Or: get answers to those questions the user subscribed to. - $sql = "SELECT c.id AS answerid, c.content AS answer, c.userid AS answeredby, c.visibility, " - . "c.timemodified, c.solved AS correct, c.ishidden AS answerhidden, a.id AS annoid, a.page, q.id AS questionid, " + $sql = "SELECT c.id AS answerid, c.content AS answer, c.userid AS userid, c.visibility, " + . "c.timemodified, c.solved AS correct, c.ishidden AS answerhidden, a.id AS annoid, a.page, q.id AS questionid, q.userid AS questionuserid, c.isquestion, c.annotationid, " + . "q.visibility AS questionvisibility, " . "q.content AS answeredquestion, q.isdeleted AS questiondeleted, q.ishidden AS questionhidden, p.id AS annotatorid, " . "p.name AS pdfannotatorname, cm.id AS cmid " . "FROM {pdfannotator_subscriptions} s " @@ -926,7 +933,11 @@ function pdfannotator_get_answers_for_this_user($courseid, $context, $answerfilt $entries = $DB->get_records_sql($sql, $params); + $res = []; foreach ($entries as $key => $entry) { + if (!pdfannotator_can_see_comment($entry, $context)) { + continue; + } $entry->link = (new moodle_url('/mod/pdfannotator/view.php', array('id' => $entry->cmid, 'page' => $entry->page, 'annoid' => $entry->annoid, 'commid' => $entry->answerid)))->out(); $entry->questionlink = (new moodle_url('/mod/pdfannotator/view.php', @@ -975,9 +986,11 @@ function pdfannotator_get_answers_for_this_user($courseid, $context, $answerfilt $entry->answeredquestion = format_text($entry->answeredquestion); $entry->answer = format_text($entry->answer); + + $res[] = $entry; } - return $entries; + return $res; } /** @@ -1542,7 +1555,7 @@ function pdfannotator_questionstable_add_row($thiscourse, $table, $question, $ur } $time = pdfannotator_get_user_datetime_shortformat($question->timecreated); if (!empty($question->lastanswered)) { // ! ($question->lastanswered != $question->timecreated) { - if ($question->lastuservisibility != 'public') { + if ($question->lastuservisibility == 'anonymous') { $lastresponder = get_string('anonymous', 'pdfannotator'); } else { $lastresponder = "<a href=" . $CFG->wwwroot . "/user/view.php?id=$question->lastuser&course=$thiscourse>" . pdfannotator_get_username($question->lastuser) . "</a>"; @@ -1599,7 +1612,7 @@ function pdfannotator_answerstable_add_row($thiscourse, $table, $answer, $cmid, if ($answer->visibility != 'public') { $answeredby = get_string('anonymous', 'pdfannotator'); } else { - $answeredby = "<a href=" . $CFG->wwwroot . "/user/view.php?id=$answer->answeredby&course=$thiscourse>" . pdfannotator_get_username($answer->answeredby) . "</a>"; + $answeredby = "<a href=" . $CFG->wwwroot . "/user/view.php?id=$answer->userid&course=$thiscourse>" . pdfannotator_get_username($answer->userid) . "</a>"; } $answertime = pdfannotator_get_user_datetime_shortformat($answer->timemodified); @@ -1744,3 +1757,65 @@ function pdfannotator_is_phone() { $param = filter_input(INPUT_SERVER, 'HTTP_USER_AGENT', FILTER_DEFAULT); // XXX How to filter, here? return preg_match("/(android|avantgo|blackberry|bolt|boost|cricket|docomo|fone|hiptop|mini|mobi|palm|phone|pie|tablet|up\.browser|up\.link|webos|wos)/i", $param); } + + +function pdfannotator_get_last_answer($annotationid, $context) { + global $DB; + $params = array('isquestion' => 0, 'annotationid' => $annotationid); + $answers = $DB->get_records('pdfannotator_comments', $params, 'timecreated DESC' ); + + foreach ($answers as $answer) { + if (!pdfannotator_can_see_comment($answer, $context)) { + continue; + } else { + return $answer; + } + } + return null; +} + +function pdfannotator_can_see_comment($comment, $context) { + global $USER, $DB; + if (is_array($comment)) { + $comment = (object)$comment; + } + + // If the comment is an answer, it is always saved as public. So, we check the visibility of the corresponding question. + if (!$comment->isquestion) { + $question = $DB->get_record('pdfannotator_comments', array('annotationid' => $comment->annotationid, 'isquestion' => '1')); + $question = (object)$question; + } else { + $question = $comment; + } + + // Private Comments are only displayed for the author. + if ($question->visibility == "private" && $USER->id != $question->userid) { + return false; + } + + // Protected Comments are only displayed for the author and for the managers. + if ($question->visibility == "protected" && $USER->id != $question->userid && !has_capability('mod/pdfannotator:viewprotectedcomments', $context)) { + return false; + } + return true; +} + +/** + * Count how many answers has a question with $annotationid + * return only answers that the user can see + */ +function pdfannotator_count_answers($annotationid, $context) { + global $DB; + $params = array('isquestion' => 0, 'annotationid' => $annotationid); + $answers = $DB->get_records('pdfannotator_comments', $params); + $count = 0; + + foreach ($answers as $answer) { + + if (!pdfannotator_can_see_comment($answer, $context)) { + continue; + } + $count++; + } + return $count; +} \ No newline at end of file diff --git a/mod_form.php b/mod_form.php index e0fcaa3f37e16d54bbff8a29f6402d82e1be198e..260f1013c83264dfcfd05dc3d27adbe705578e9b 100644 --- a/mod_form.php +++ b/mod_form.php @@ -96,6 +96,16 @@ class mod_pdfannotator_mod_form extends moodleform_mod { $mform->setDefault('useprintcomments', $config->useprintcomments); $mform->addHelpButton('useprintcomments', 'setting_useprint_comments', 'pdfannotator'); + $mform->addElement('advcheckbox', 'useprivatecomments', get_string('setting_use_private_comments', 'pdfannotator'), get_string('use_private_comments', 'pdfannotator'), null, array(0, 1)); + $mform->setType('useprivatecomments', PARAM_BOOL); + $mform->setDefault('useprivatecomments', $config->use_private_comments); + $mform->addHelpButton('useprivatecomments', 'setting_use_private_comments', 'pdfannotator'); + + $mform->addElement('advcheckbox', 'useprotectedcomments', get_string('setting_use_protected_comments', 'pdfannotator'), get_string('use_protected_comments', 'pdfannotator'), null, array(0, 1)); + $mform->setType('useprotectedcomments', PARAM_BOOL); + $mform->setDefault('useprotectedcomments', $config->use_protected_comments); + $mform->addHelpButton('useprotectedcomments', 'setting_use_protected_comments', 'pdfannotator'); + // Add legacy files flag only if used. if (isset($this->current->legacyfiles) and $this->current->legacyfiles != RESOURCELIB_LEGACYFILES_NO) { $options = array(RESOURCELIB_LEGACYFILES_DONE => get_string('legacyfilesdone', 'pdfannotator'), diff --git a/model/comment.class.php b/model/comment.class.php index e8449015c93a85b5ca14d8e3f7ad9e2a9d27430a..bb5236c568a13622176b93f9412d8073872eeeac 100644 --- a/model/comment.class.php +++ b/model/comment.class.php @@ -60,12 +60,8 @@ class pdfannotator_comment { $commentuuid = $DB->insert_record('pdfannotator_comments', $datarecord, $returnid = true); $datarecord->uuid = $commentuuid; - $datarecord->username = $USER->username; - if ($visibility === 'anonymous') { - $datarecord->username = get_string('anonymous', 'pdfannotator'); - } else { - $datarecord->username = get_string('me', 'pdfannotator'); - } + self::set_username($datarecord); + $datarecord->content = format_text($datarecord->content, $format = FORMAT_MOODLE, $options = ['para' => false]); $datarecord->timecreated = pdfannotator_optional_timeago($datarecord->timecreated); $datarecord->timemodified = pdfannotator_optional_timeago($datarecord->timemodified); @@ -136,14 +132,15 @@ class pdfannotator_comment { * @global type $DB * @param type $documentid * @param type $highlightid + * @param $context * @return \stdClass */ - public static function read($documentid, $annotationid) { + public static function read($documentid, $annotationid, $context) { - global $DB; + global $DB, $USER; // Get the ids and text content of all comments attached to this annotation/highlight. - $sql = "SELECT c.id, c.content, c.userid, c.visibility, c.isquestion, c.isdeleted, c.ishidden, c.timecreated, c.timemodified, c.modifiedby, c.solved, SUM(vote) AS votes " + $sql = "SELECT c.id, c.content, c.userid, c.visibility, c.isquestion, c.isdeleted, c.ishidden, c.timecreated, c.timemodified, c.modifiedby, c.solved, c.annotationid, SUM(vote) AS votes " . "FROM {pdfannotator_comments} c LEFT JOIN {pdfannotator_votes} v" . " ON c.id=v.commentid WHERE annotationid = ?" . " GROUP BY c.id, c.content, c.userid, c.visibility, c.isquestion, c.isdeleted, c.ishidden, c.timecreated, c.timemodified, c.modifiedby, c.solved" @@ -159,8 +156,14 @@ class pdfannotator_comment { foreach ($comments as $data) { $comment = new stdClass(); + $comment->userid = $data->userid; // Author of comment. $comment->visibility = $data->visibility; $comment->isquestion = $data->isquestion; + $comment->annotationid = $annotationid; + if ( !pdfannotator_can_see_comment($comment, $context)) { + continue; + } + $comment->timecreated = pdfannotator_optional_timeago($data->timecreated); // If the comment was edited. if ($data->timecreated != $data->timemodified) { @@ -175,7 +178,6 @@ class pdfannotator_comment { $comment->modifiedby = $annotation->modifiedby; } - $comment->annotation = $annotationid; $comment->isdeleted = $data->isdeleted; $comment->uuid = $data->id; @@ -192,7 +194,7 @@ class pdfannotator_comment { $comment->content = $data->content; $comment->content = format_text($data->content, $format = FORMAT_MOODLE, $options = ['para' => false]); } - $comment->userid = $data->userid; // Author of comment. + self::set_username($comment); $comment->solved = $data->solved; $comment->votes = $data->votes; @@ -214,6 +216,8 @@ class pdfannotator_comment { global $USER; switch ($comment->visibility) { case 'public': + case 'private': + case 'protected': if ($comment->userid === $USER->id) { $comment->username = get_string('me', 'pdfannotator'); } else { @@ -574,27 +578,33 @@ class pdfannotator_comment { } public static function get_questions($documentid, $pagenumber, $context) { - global $DB; + global $DB, $USER; $displayhidden = has_capability('mod/pdfannotator:seehiddencomments', $context); // Get all questions of a page with a subselect, where all ids of annotations of one page are selected. $sql = "SELECT c.* FROM {pdfannotator_comments} c WHERE isquestion = 1 AND annotationid IN " . "(SELECT id FROM {pdfannotator_annotations} a WHERE a.page = :page AND a.pdfannotatorid = :docid)"; $questions = $DB->get_records_sql($sql, array('page' => $pagenumber, 'docid' => $documentid)); - + $ret = []; foreach ($questions as $question) { - $params = array('isquestion' => 0, 'annotationid' => $question->annotationid); - $count = $DB->count_records('pdfannotator_comments', $params); - $question->answercount = $count; + // Private Comments are only displayed for the author. + + if ( !pdfannotator_can_see_comment($question, $context) ) { + continue; + } + + $question->answercount = pdfannotator_count_answers($question->annotationid, $context); $question->page = $pagenumber; + if ($question->isdeleted == 1) { $question->content = '<em>'.get_string('deletedComment', 'pdfannotator').'</em>'; } if ($question->ishidden == 1 && !$displayhidden) { $question->content = get_string('hiddenComment', 'pdfannotator'); } + $ret[] = $question; } - return $questions; + return $ret; } public static function get_all_questions($documentid, $context) { @@ -607,6 +617,9 @@ class pdfannotator_comment { $ret = []; foreach ($questions as $question) { + if ( !pdfannotator_can_see_comment($question, $context) ) { + continue; + } $ret[$question->page][] = $question; } return $ret; @@ -635,9 +648,11 @@ class pdfannotator_comment { $questions = $DB->get_records_sql($sql, $params); foreach ($questions as $question) { - $params = array('isquestion' => 0, 'annotationid' => $question->annotationid); - $count = $DB->count_records('pdfannotator_comments', $params); - $question->answercount = $count; + if (!pdfannotator_can_see_comment($question, $context)) { + continue; + } + + $question->answercount = pdfannotator_count_answers($question->annotationid, $context); if ($question->isdeleted == 1) { $question->content = '<em>'.get_string('deletedComment', 'pdfannotator').'</em>'; } diff --git a/model/pdfannotator.php b/model/pdfannotator.php index 3658501f52afb0ce4485775eb5df17b3c5272ddc..e1b9546c9e4eedefb43c8cf17d264ac51c2fb287 100644 --- a/model/pdfannotator.php +++ b/model/pdfannotator.php @@ -123,12 +123,12 @@ class pdfannotator_instance { return $this->name; } - public static function get_conversations($pdfannotatorid) { + public static function get_conversations($pdfannotatorid, $context) { global $DB; $sql = "SELECT q.id, q.content AS answeredquestion, q.timemodified, q.userid, q.visibility," - . " a.id AS annoid, a.page, a.annotationtypeid " + . " a.id AS annoid, a.page, a.annotationtypeid, q.isquestion " . "FROM {pdfannotator_annotations} a " . "JOIN {pdfannotator_comments} q ON q.annotationid = a.id " . "WHERE q.isquestion = 1 AND a.pdfannotatorid = ? AND NOT q.isdeleted = 1 " @@ -140,8 +140,14 @@ class pdfannotator_instance { return -1; } + $res = []; + foreach ($questions as $question) { + if (!pdfannotator_can_see_comment($question, $context)) { + continue; + } + $question->answeredquestion = html_entity_decode($question->answeredquestion); $question->timemodified = pdfannotator_get_user_datetime($question->timemodified); if ($question->visibility === 'anonymous') { @@ -175,8 +181,8 @@ class pdfannotator_instance { unset($question->annoid); $question->answers = $answers; - + $res[] = $question; } - return $questions; + return $res; } } diff --git a/model/statistics.class.php b/model/statistics.class.php index 589598a2b483108607ef49df83bfd62c6f9a426e..be58107b8a056d96382da1cc0f221bf49fbfd195 100644 --- a/model/statistics.class.php +++ b/model/statistics.class.php @@ -144,6 +144,9 @@ class pdfannotator_statistics { $ret[] = array('row' => array(get_string('myanswers', 'pdfannotator'), $this->get_comments_annotator('0', true), $this->get_comments_course('0', true))); $ret[] = array('row' => array(get_string('average_answers', 'pdfannotator').'<a class="btn btn-link p-a-0" role="button" data-container="body" data-toggle="popover" data-placement="right" data-content="'.get_string('average_help', 'pdfannotator').'" data-html="true" tabindex="0" data-trigger="focus"><li class="icon fa fa-question-circle text-info fa-fw" aria-hidden="true" title="'.get_string('entity_helptitle', 'pdfannotator').' '.get_string('average', 'pdfannotator').'"></li></a>' , round($this->get_comments_average_annotator('0'), 2), round($this->get_comments_average_course('0'), 2))); + $ret[] = array('row' => array(get_string('private_comments', 'pdfannotator'), $this->count_private_comments($this->annotatorid, 0) + $this->count_private_comments($this->annotatorid, 1), $this->count_private_comments_in_course())); + $ret[] = array('row' => array(get_string('protected_comments', 'pdfannotator'), $this->count_protected_comments($this->annotatorid, 1) + $this->count_protected_comments($this->annotatorid, 0), $this->count_protected_comments_in_course())); + if ($this->isteacher) { $ret[] = array('row' => array(get_string('reports', 'pdfannotator'), $this->get_reports_annotator(), $this->get_reports_course())); } @@ -166,19 +169,40 @@ class pdfannotator_statistics { $myanswers = []; $otherquestions = []; $myquestions = []; - foreach ($pdfannotators as $pdfannotator) { + foreach ($pdfannotators as $index => $pdfannotator) { $countquestions = self::count_comments_annotator($pdfannotator->get_id(), '1'); $countmyquestions = self::count_comments_annotator($pdfannotator->get_id(), '1', $this->userid); $countanswers = self::count_comments_annotator($pdfannotator->get_id(), '0'); $countmyanswers = self::count_comments_annotator($pdfannotator->get_id(), '0', $this->userid); - $otherquestions[] = $countquestions - $countmyquestions; - $myquestions[] = $countmyquestions; - $otheranswers[] = $countanswers - $countmyanswers; - $myanswers[] = $countmyanswers; + $countprivateanswers = self::count_private_comments($pdfannotator->get_id(), 0); + $countmyprivateanswers = self::count_private_comments($pdfannotator->get_id(), 0, $this->userid); + $countprivatequestions = self::count_private_comments($pdfannotator->get_id(), 1); + $countmyprivatequestions = self::count_private_comments($pdfannotator->get_id(), 1, $this->userid); + + $countprotectedanswers = self::count_protected_comments($pdfannotator->get_id(), 0); + $countmyprotectedanswers = self::count_protected_comments($pdfannotator->get_id(), 0, $this->userid); + $countprotectedquestions = self::count_protected_comments($pdfannotator->get_id(), 1); + $countmyprotectedquestions = self::count_protected_comments($pdfannotator->get_id(), 1, $this->userid); + + $otherprotectedquestions[] = $countprotectedquestions - $countmyprotectedquestions; + $myprotectedquestions[] = $countmyprotectedquestions; + $otherprotectedanswers[] = $countprotectedanswers - $countmyprotectedanswers; + $myprotectedanswers[] = $countmyprotectedanswers; + + $otherprivate[] = ($countprivateanswers - $countmyprivateanswers) + ($countprivatequestions - $countmyprivatequestions); + $myprivate[] = $countmyprivateanswers + $countmyprivatequestions; + + $myquestions[] = $countmyquestions - $countmyprotectedquestions - $countmyprivatequestions; + $otherquestions[] = $countquestions - $myquestions[$index] - $countprotectedanswers - $countprivatequestions; + + $myanswers[] = $countmyanswers - $countmyprotectedanswers - $countmyprivateanswers; + $otheranswers[] = $countanswers - $myanswers[$index] - $countprotectedanswers - $countprivateanswers; + $names[] = $pdfannotator->get_name(); + } - $ret = array($names, $otherquestions, $myquestions, $otheranswers, $myanswers); + $ret = array($names, $otherquestions, $myquestions, $otheranswers, $myanswers, $otherprivate, $myprivate, $otherprotectedquestions, $myprotectedquestions, $otherprotectedanswers, $myprotectedanswers); return $ret; } @@ -201,4 +225,70 @@ class pdfannotator_statistics { return $DB->count_records('pdfannotator_comments', $conditions); } + /** + * Count private comments for annotator. + */ + public function count_private_comments($annotatorid, $isquestion, $userid=false) { + global $DB; + if ($isquestion) { + $params = ['pdfannotatorid' => $annotatorid, 'visibility' => "private", 'isdeleted' => "0"];; + if ($userid) { + $params['userid'] = $userid; + } + $count = $DB->count_records('pdfannotator_comments', $params); + } else { + // Count answers to private questions if they were saved as public in the database. + $sql = 'SELECT COUNT(*) FROM {pdfannotator_comments} answers ' + . 'JOIN {pdfannotator_comments} questions ' + . 'ON answers.annotationid = questions.annotationid ' + . 'WHERE questions.visibility = "private" AND answers.visibility = "public" AND questions.pdfannotatorid = ? AND answers.isdeleted = ? '; + $params = [$annotatorid, "0"]; + if ($userid) { + $sql .= ' AND answers.userid = ? AND questions.userid = ?'; + array_push($params, $userid, $userid); + } + $count = $DB->count_records_sql($sql, $params); + } + return $count; + } + + public function count_protected_comments($annotatorid, $isquestion, $userid=false) { + global $DB; + if ($isquestion) { + $params = ['pdfannotatorid' => $annotatorid, 'visibility' => "protected", 'isdeleted' => "0"];; + if ($userid) { + $params['userid'] = $userid; + } + $count = $DB->count_records('pdfannotator_comments', $params); + } else { + // Count answers to private questions if they were saved as public in the database. + $sql = 'SELECT COUNT(*) FROM {pdfannotator_comments} answers ' + . 'JOIN {pdfannotator_comments} questions ' + . 'ON answers.annotationid = questions.annotationid ' + . 'WHERE questions.visibility = "protected" AND answers.visibility = "public" AND questions.pdfannotatorid = ? AND answers.isdeleted = ? '; + $params = [$annotatorid, "0"]; + if ($userid) { + $sql .= ' AND answers.userid = ? AND questions.userid = ?'; + array_push($params, $userid, $userid); + } + $count = $DB->count_records_sql($sql, $params); + } + return $count; + + } + + public function count_private_comments_in_course() { + global $DB; + $sql = 'SELECT COUNT(*) FROM {pdfannotator_comments} c JOIN {pdfannotator} a ON ' + . 'a.course = ? AND a.id = c.pdfannotatorid WHERE c.visibility = ? AND c.isdeleted = ?'; + return $DB->count_records_sql($sql, array($this->courseid, "private", '0')); + } + + public function count_protected_comments_in_course() { + global $DB; + $sql = 'SELECT COUNT(*) FROM {pdfannotator_comments} c JOIN {pdfannotator} a ON ' + . 'a.course = ? AND a.id = c.pdfannotatorid WHERE c.visibility = ? AND c.isdeleted = ?'; + return $DB->count_records_sql($sql, array($this->courseid, "protected", '0')); + } + } diff --git a/settings.php b/settings.php index dd36a4bec191f584f2c6009da9c4291b42dd3bdd..5b41d22a5f92e9e3407ddd707cde5750ac62662d 100644 --- a/settings.php +++ b/settings.php @@ -40,6 +40,14 @@ if ($ADMIN->fulltree) { get_string('global_setting_use_studentdrawing', 'pdfannotator'), get_string('global_setting_use_studentdrawing_desc', 'pdfannotator'), 0)); + $settings->add(new admin_setting_configcheckbox('mod_pdfannotator/use_private_comments', + get_string('global_setting_use_private_comments', 'pdfannotator'), + get_string('global_setting_use_private_comments_desc', 'pdfannotator'), 0)); + + $settings->add(new admin_setting_configcheckbox('mod_pdfannotator/use_protected_comments', + get_string('global_setting_use_protected_comments', 'pdfannotator'), + get_string('global_setting_use_protected_comments_desc', 'pdfannotator'), 0)); + //Define what API to use for converting latex formulas into png. $options = array(); $options[LATEX_TO_PNG_MOODLE] = get_string("global_setting_latexusemoodle", "pdfannotator"); diff --git a/shared/index.js b/shared/index.js index 5e00dc97f4e4b61b552c3469ecbd8f0b5d420830..7b8edc72046fe337419e5cf08aedb9a12eba3988 100644 --- a/shared/index.js +++ b/shared/index.js @@ -1889,13 +1889,33 @@ function startIndex(Y,_cm,_documentObject,_userid,_capabilities, _toolbarSetting if (supportsComments(target)) { //showLoader UI.showLoader(); - $('#comment-wrapper h4')[0].innerHTML = M.util.get_string('comments','pdfannotator'); (function () { var documentId = target.parentNode.getAttribute('data-pdf-annotate-document'); var annotationId = target.getAttribute('data-pdf-annotate-id'); _2.default.getStoreAdapter().getComments(documentId, annotationId).then(function (comments) { UI.hideLoader(); + var title; + if(comments.comments[0].visibility == "protected") { + title = M.util.get_string('protected_comments','pdfannotator'); + $("#protectedDiv").hide(); + $("#anonymousDiv").hide(); + $("#privateDiv").hide(); + $("#myarea").attr("placeholder", M.util.get_string('add_protected_comment', 'pdfannotator')); + } else if (comments.comments[0].visibility == "private") { + title = M.util.get_string('private_comments','pdfannotator'); + $("#privateDiv").hide(); + $("#protectedDiv").hide(); + $("#anonymousDiv").hide(); + $("#myarea").attr("placeholder", M.util.get_string('add_private_comment', 'pdfannotator')); + } else { + title = M.util.get_string('public_comments','pdfannotator'); + $("#privateDiv").hide(); + $("#protectedDiv").hide(); + $("#anonymousDiv").show(); + } + + $('#comment-wrapper h4')[0].innerHTML = title; commentList.innerHTML = ''; commentForm.style.display = 'inherit'; @@ -1905,10 +1925,7 @@ function startIndex(Y,_cm,_documentObject,_userid,_capabilities, _toolbarSetting button2.style.display = 'inline'; commentForm.onsubmit = function (e) { document.querySelector('#commentSubmit').disabled = true; - var commentVisibility= "public"; - if(document.querySelector('#anonymousCheckbox').checked){ - commentVisibility = "anonymous"; - } + var commentVisibility= read_visibility_of_checkbox(); var isquestion = 0; // this is a normal comment, so it is not a question if(commentText.value.trim().length < 2){ //should be more than one character, otherwise it should not be saved. @@ -5497,7 +5514,8 @@ function startIndex(Y,_cm,_documentObject,_userid,_capabilities, _toolbarSetting * * @param {Number} x The x coordinate of the point * @param {Number} y The y coordinate of the point - */function savePoint(x,y){ + */ + function savePoint(x,y){ var svg=(0,_utils.findSVGAtPoint)(x,y); if(!svg){return;} var rect=svg.getBoundingClientRect(); @@ -5762,7 +5780,8 @@ function startIndex(Y,_cm,_documentObject,_userid,_capabilities, _toolbarSetting } /** * Save a new point annotation from input - */function savePoint(svg = null){ + */ + function savePoint(svg = null){ if(textarea.value.trim().length>1){ disablePoint(); var page = pageNumber; @@ -5783,10 +5802,7 @@ function startIndex(Y,_cm,_documentObject,_userid,_capabilities, _toolbarSetting var documentId=_getMetadata.documentId; var pageNumber=page; var annotation=Object.assign({type:'point'},(0,_utils.scaleDown)(svg,{x:clientX-((0,_utils.roundDigits)(_rect.left,4)),y:clientY-((0,_utils.roundDigits)(_rect.top,4))})); - var commentVisibility = "public"; - if(document.querySelector('#anonymousCheckbox').checked){ - commentVisibility = "anonymous"; - } + var commentVisibility= read_visibility_of_checkbox(); var isquestion = 1; //The Point was created so the comment is a question _PDFJSAnnotate2.default.getStoreAdapter().addAnnotation(documentId,pageNumber,annotation) .then(function(annotation){ @@ -6200,7 +6216,8 @@ function startIndex(Y,_cm,_documentObject,_userid,_capabilities, _toolbarSetting * @param {String} type The type of rect (area, highlight, strikeout) * @param {Array} rects The rects to use for annotation * @param {String} color The color of the rects - */function saveRect(type,rects,color,e){ + */ + function saveRect(type,rects,color,e){ var annotation = initializeAnnotation(type,rects,color,_svg); var _getMetadata=(0,_utils.getMetadata)(_svg); var documentId=_getMetadata.documentId; @@ -6221,10 +6238,7 @@ function startIndex(Y,_cm,_documentObject,_userid,_capabilities, _toolbarSetting .addAnnotation(documentId,pageNumber,annotation) .then(function(annotation){ - var commentVisibility = "public"; - if(document.querySelector('#anonymousCheckbox').checked){ - commentVisibility = "anonymous"; - } + var commentVisibility= read_visibility_of_checkbox(); var isquestion = 1; //The annotation was created, so this comment has to be a question; _PDFJSAnnotate2.default.getStoreAdapter().addComment(documentId,annotation.uuid,content,commentVisibility,isquestion) .then(function(msg){ @@ -6667,7 +6681,7 @@ function startIndex(Y,_cm,_documentObject,_userid,_capabilities, _toolbarSetting button1.style.display = 'inline'; var button2 = document.getElementById('questionsOnThisPage'); // to be found in index template button2.style.display = 'inline'; - + //title $('#comment-wrapper h4')[0].innerHTML = M.util.get_string('comments','pdfannotator'); //add Eventlistener to Toolbar. Every Click in Toolbar should cancel the Annotation-Comment-Creation @@ -6675,7 +6689,12 @@ function startIndex(Y,_cm,_documentObject,_userid,_capabilities, _toolbarSetting //Hide shown comments document.querySelector('.comment-list-container').innerHTML = '<p></p>'; form = document.querySelector('.comment-list-form'); - form.setAttribute('style','display:inherit'); + $(document).ready(function(){ + form.setAttribute('style','display:inherit'); + $('#anonymousDiv').show(); + $('#privateDiv').show(); + $('#protectedDiv').show(); + }); textarea = document.getElementById('myarea'); textarea.placeholder = M.util.get_string('startDiscussion','pdfannotator'); submitbutton = document.getElementById('commentSubmit'); @@ -6721,6 +6740,9 @@ function startIndex(Y,_cm,_documentObject,_userid,_capabilities, _toolbarSetting document.querySelector('.comment-list-container').innerHTML = '<p></p>'; form = document.querySelector('.comment-list-form'); form.setAttribute('style','display:inherit'); + $('#anonymousCheckbox').show(); + $('#privateCheckbox').show(); + $('#protectedCheckbox').show(); textarea = document.getElementById('myarea'); textarea.placeholder = M.util.get_string('startDiscussion','pdfannotator'); submitbutton = document.getElementById('commentSubmit'); @@ -7424,3 +7446,25 @@ function startIndex(Y,_cm,_documentObject,_userid,_capabilities, _toolbarSetting /******/ ]); }); //require JQuery closed } + +/** + * + */ +function read_visibility_of_checkbox(){ + var commentVisibility= "public"; + if (document.querySelector('#anonymousCheckbox').checked) { + commentVisibility = "anonymous"; + document.querySelector('#anonymousCheckbox').checked = false; + } else if (document.querySelector('#privateCheckbox') != null) { + if (document.querySelector('#privateCheckbox').checked) { + commentVisibility = "private"; + document.querySelector('#privateCheckbox').checked = false; + } + } else if (document.querySelector('#protectedCheckbox') != null) { + if (document.querySelector('#protectedCheckbox').checked) { + commentVisibility = "protected"; + document.querySelector('#protectedCheckbox').checked = false; + } + } + return commentVisibility; +} diff --git a/shared/locallib.js b/shared/locallib.js index 5f9525035718c560da1e56bdf61e5b014a41f27d..7680637720bfba38356e25401b8f4302e2069e5a 100644 --- a/shared/locallib.js +++ b/shared/locallib.js @@ -83,8 +83,6 @@ function addDropdownNavigation(Y, __capabilities, __cmid) { } - - function renderMathJax() { var counter = 0; let mathjax = function () { @@ -178,3 +176,52 @@ function makeFullScreen() { document.querySelector('#body-wrapper').style.height = oldHeight; } } + +/** + * Check just one checkbox under the comment form + * + */ +function checkOnlyOneCheckbox( Y ) { + var radios = document.getElementsByClassName('pdfannotator-radio'); + var anonymousCheckbox = document.getElementById('anonymousCheckbox'); + var privateCheckbox = document.getElementById('privateCheckbox'); + var protectedCheckbox = document.getElementById('protectedCheckbox'); + if(anonymousCheckbox) { + anonymousCheckbox.addEventListener('click', function(){ + if(anonymousCheckbox.checked) { + if(privateCheckbox){ + privateCheckbox.checked = false; + } + if(protectedCheckbox) { + protectedCheckbox.checked = false; + } + } + }); + } + + if(privateCheckbox) { + privateCheckbox.addEventListener('click', function(){ + if(privateCheckbox.checked) { + if(anonymousCheckbox){ + anonymousCheckbox.checked = false; + } + if(protectedCheckbox) { + protectedCheckbox.checked = false; + } + } + }); + } + + if(protectedCheckbox) { + protectedCheckbox.addEventListener('click', function(){ + if(protectedCheckbox.checked) { + if(anonymousCheckbox){ + anonymousCheckbox.checked = false; + } + if(privateCheckbox) { + privateCheckbox.checked = false; + } + } + }); + } +} diff --git a/shared/statistic.js b/shared/statistic.js index f3e161524f81bffbfb56870b7e413fbee0312537..c561eb85c47d064a97c7406868951b8e800d538f 100644 --- a/shared/statistic.js +++ b/shared/statistic.js @@ -6,7 +6,7 @@ */ // R: The first parameter has to be Y, because it is a default YUI-object (demanded by moodle). -function setCharts(Y, names, otherquestions, myquestions, otheranswers, myanswers) { +function setCharts(Y, names, otherquestions, myquestions, otheranswers, myanswers, otherprivate, myprivate, otherprotectedquestions, myprotectedquestions, otherprotectedanswers, myprotectedanswers) { require(['core/chartjs'], function (Chart) { // On small screens set width depending on number of annotators. Otherwise the diagram is very small. let width = Math.max(names.length * 25, 300); @@ -15,7 +15,7 @@ function setCharts(Y, names, otherquestions, myquestions, otheranswers, myanswer document.getElementById('chart-container').style.width = width + "px"; } - var maxValue = calculateMax(otherquestions, myquestions, otheranswers, myanswers); + var maxValue = calculateMax(otherquestions, myquestions, otheranswers, myanswers, otherprivate, myprivate, otherprotectedquestions, myprotectedquestions, otherprotectedanswers, myprotectedanswers); var ctx = document.getElementById('myChart').getContext('2d'); var myChart = new Chart(ctx, { @@ -32,18 +32,51 @@ function setCharts(Y, names, otherquestions, myquestions, otheranswers, myanswer stack: 'questions', data: otherquestions, backgroundColor: 'rgb(142,186,229)', + }, { + label: M.util.get_string('myprotectedquestions', 'pdfannotator'), + stack: 'questions', + data: myprotectedquestions, + backgroundColor: 'rgb(137, 204, 207)', + }, { + label: M.util.get_string('protected_questions', 'pdfannotator') + ' ' + M.util.get_string('by_other_users', 'pdfannotator'), + stack: 'questions', + data: otherprotectedquestions, + backgroundColor: 'rgb(0, 152, 161)', }, { label: M.util.get_string('myanswers', 'pdfannotator'), stack: 'answers', data: myanswers, - backgroundColor: 'rgb(87,171,39)', - }, + backgroundColor: 'rgb(87, 171, 39)', + }, { label: M.util.get_string('answers', 'pdfannotator') + ' ' + M.util.get_string('by_other_users', 'pdfannotator'), stack: 'answers', data: otheranswers, - backgroundColor: 'rgb(184,214,152)', + backgroundColor: 'rgb(184, 214, 152)', + }, + { + label: M.util.get_string('myprotectedanswers', 'pdfannotator'), + stack: 'answers', + data: myprotectedanswers, + backgroundColor: 'rgb(224, 230, 154)', + }, { + label: M.util.get_string('protected_answers', 'pdfannotator') + ' ' + M.util.get_string('by_other_users', 'pdfannotator'), + stack: 'answers', + data: otherprotectedanswers, + backgroundColor: 'rgb(189, 205, 0)', + }, + { + label: M.util.get_string('myprivate', 'pdfannotator'), + stack: 'private', + data: myprivate, + backgroundColor: 'rgb(246, 168, 0)', + }, + { + label: M.util.get_string('private_comments', 'pdfannotator') + ' ' + M.util.get_string('by_other_users', 'pdfannotator'), + stack: 'private', + data: otherprivate, + backgroundColor: 'rgb(253, 212, 143)', }] }, options: { @@ -87,16 +120,22 @@ function setCharts(Y, names, otherquestions, myquestions, otheranswers, myanswer }); } -function calculateMax(otherquestions, myquestions, otheranswers, myanswers) { +/** + * Calculate the height of the diagramm in the statistic + */ +function calculateMax(otherquestions, myquestions, otheranswers, myanswers, otherprivate, myprivate, otherprotectedquestions, myprotectedquestions, otherprotectedanswers, myprotectedanswers) { let max = 0; for (let i = 0; i < otherquestions.length; ++i) { - if (otherquestions[i] + myquestions[i] > max) { - max = otherquestions[i] + myquestions[i]; + if (otherquestions[i] + myquestions[i] + otherprotectedquestions[i] + myprotectedquestions[i] > max) { + max = otherquestions[i] + myquestions[i] + otherprotectedquestions[i] + myprotectedquestions[i]; + } + if (otheranswers[i] + myanswers[i] + otherprotectedanswers[i] + myprotectedanswers[i] > max) { + max = otheranswers[i] + myanswers[i] + otherprotectedanswers[i] + myprotectedanswers[i]; } - if (otheranswers[i] + myanswers[i] > max) { - max = otheranswers[i] + myanswers[i]; + if (otherprivate[i] + myprivate[i] > max) { + max = otherprivate[i] + myprivate[i]; } - } + } return max; } diff --git a/styles.css b/styles.css index 418ed21179288d487c55b7393e6985cadb1e7a8b..c47122067bd9d26071dfc84d2c87d13c1399f09c 100644 --- a/styles.css +++ b/styles.css @@ -522,6 +522,15 @@ body { float: right; } +.path-mod-pdfannotator #anonymousLabel, .path-mod-pdfannotator #privateLabel, .path-mod-pdfannotator #protectedLabel { + margin-left: 5px; + margin-bottom: 0; +} + +.path-mod-pdfannotator #anonymousDiv, .path-mod-pdfannotator #privateDiv, .path-mod-pdfannotator #protectedDiv { + margin: 5px 0px; +} + .path-mod-pdfannotator .helperLayer { width: 100%; height: 100%; @@ -865,4 +874,4 @@ header, section, footer, aside, nav, main, article, figure { .toolbaritem .pdfannotator_text { display: inline-block; visibility: visible; -} \ No newline at end of file +} diff --git a/templates/index.mustache b/templates/index.mustache index c583313ecb3cecc5b23dc43f65ba113f9a3b231c..13190d46adea4bf4f9d3e7f30d92c0346e88349a 100644 --- a/templates/index.mustache +++ b/templates/index.mustache @@ -16,7 +16,7 @@ {{#usestudenttextbox}} <span class="toolbaritem"> - <button class="pdfannotator_text text" type="button" title="{{# str }} text, pdfannotator {{/ str }}" data-tooltype="text">{{# pix }}text_color_picker,pdfannotator, {{# str }} text, pdfannotator {{/ str }} {{/ pix}}</button> + <button class="text" type="button" title="{{# str }} text, pdfannotator {{/ str }}" data-tooltype="text">{{# pix }}text_color_picker,pdfannotator, {{# str }} text, pdfannotator {{/ str }} {{/ pix}}</button> <select class="text-size"></select> <div class="text-color"></div> </span> @@ -133,8 +133,18 @@ <textarea id="myarea" placeholder="{{# str }} addAComment, pdfannotator {{/ str }}" cols="40" rows="3"></textarea> <div id="anonymousDiv" class="row-fluid row"> - <input type="checkbox" name="visibility" value="anonymous" id="anonymousCheckbox" style="width:auto;"><label for="anonymousCheckbox">{{# str }} sendAnonymous, pdfannotator {{/ str }}</label> + <input type="checkbox" name="visibility" value="anonymous" id="anonymousCheckbox" class="pdfannotator-radio" style="width:auto;"><label id="anonymousLabel" for="anonymousCheckbox">{{# str }} sendAnonymous, pdfannotator {{/ str }}</label> </div> + {{# useprivatecomments }} + <div id="privateDiv" class="row-fluid row"> + <input type="checkbox" name="visibility" value="private" id="privateCheckbox" class="pdfannotator-radio" style="width:auto;"><label id="privateLabel" for="privateCheckbox">{{# str }} sendPrivate, pdfannotator {{/ str }}</label> + </div> + {{/ useprivatecomments }} + {{# useprotectedcomments }} + <div id="protectedDiv" class="row-fluid row"> + <input type="checkbox" name="visibility" value="protected" id="protectedCheckbox" class="pdfannotator-radio" style="width:auto;"><label id="protectedLabel" for="protectedCheckbox">{{# str }} sendProtected, pdfannotator {{/ str }} {{{protectedhelpicon}}} </label> + </div> + {{/ useprotectedcomments }} <input id="commentSubmit" class="owner btn btn-primary" type="submit" value="{{# str }} answerButton, pdfannotator {{/ str }}"> <input id="commentCancel" class="owner btn btn-secondary" type="reset" value="{{# str }} cancelButton, pdfannotator {{/ str }}" > diff --git a/version.php b/version.php index a8c7720aa8fe4b0b0121ed42ec0b956c5266aaa8..cf0973bb678dfa2bf2815bafd3f34304fa7a0032 100644 --- a/version.php +++ b/version.php @@ -25,6 +25,6 @@ defined('MOODLE_INTERNAL') || die(); $plugin->component = 'mod_pdfannotator'; // Full name of the plugin (used for diagnostics). -$plugin->version = 2021031902; // The current module version (Date: YYYYMMDDXX). +$plugin->version = 2021032201; // The current module version (Date: YYYYMMDDXX). $plugin->release = 'PDF Annotator v1.4 release 5'; $plugin->requires = 2016112900; // Requires this Moodle version.