MDL-35272 Fix typo in qformat_blackboard_six.php
[moodle.git] / comment / lib.php
blob9831c4026f94bef11886f9fbb516f6cc7a35ea35
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * Comment is helper class to add/delete comments anywhere in moodle
20 * @package comment
21 * @copyright 2010 Dongsheng Cai <dongsheng@moodle.com>
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 defined('MOODLE_INTERNAL') || die();
27 class comment {
28 /**
29 * there may be several comment box in one page
30 * so we need a client_id to recognize them
31 * @var integer
33 private $cid;
34 /**
35 * commentarea is used to specify different
36 * parts shared the same itemid
37 * @var string
39 private $commentarea;
40 /**
41 * itemid is used to associate with commenting content
42 * @var integer
44 private $itemid;
45 /**
46 * this html snippet will be used as a template
47 * to build comment content
48 * @var string
50 private $template;
51 /**
52 * The context id for comments
53 * @var int
55 private $contextid;
56 /**
57 * The context itself
58 * @var stdClass
60 private $context;
61 /**
62 * The course id for comments
63 * @var int
65 private $courseid;
66 /**
67 * course module object, only be used to help find pluginname automatically
68 * if pluginname is specified, it won't be used at all
69 * @var stdClass
71 private $cm;
72 /**
73 * The component that this comment is for. It is STRONGLY recommended to set this.
74 * @var string
76 private $component;
77 /**
78 * This is calculated by normalising the component
79 * @var string
81 private $pluginname;
82 /**
83 * This is calculated by normalising the component
84 * @var string
86 private $plugintype;
87 /**
88 * Whether the user has the required capabilities/permissions to view comments.
89 * @var bool
91 private $viewcap = false;
92 /**
93 * Whether the user has the required capabilities/permissions to post comments.
94 * @var bool
96 private $postcap = false;
97 /**
98 * to costomize link text
99 * @var string
101 private $linktext;
103 * If set to true then comment sections won't be able to be opened and closed
104 * instead they will always be visible.
105 * @var bool
107 protected $notoggle = false;
109 * If set to true comments are automatically loaded as soon as the page loads.
110 * Normally this happens when the user expands the comment section.
111 * @var bool
113 protected $autostart = false;
115 * If set to true the total count of comments is displayed when displaying comments.
116 * @var bool
118 protected $displaytotalcount = false;
120 * If set to true a cancel button will be shown on the form used to submit comments.
121 * @var bool
123 protected $displaycancel = false;
125 * The number of comments associated with this comments params
126 * @var int
128 protected $totalcommentcount = null;
130 /**#@+
131 * static variable will be used by non-js comments UI
133 private static $nonjs = false;
134 private static $comment_itemid = null;
135 private static $comment_context = null;
136 private static $comment_area = null;
137 private static $comment_page = null;
138 private static $comment_component = null;
139 /**#@-*/
142 * Construct function of comment class, initialise
143 * class members
144 * @param stdClass $options
145 * @param object $options {
146 * context => context context to use for the comment [required]
147 * component => string which plugin will comment being added to [required]
148 * itemid => int the id of the associated item (forum post, glossary item etc) [required]
149 * area => string comment area
150 * cm => stdClass course module
151 * course => course course object
152 * client_id => string an unique id to identify comment area
153 * autostart => boolean automatically expend comments
154 * showcount => boolean display the number of comments
155 * displaycancel => boolean display cancel button
156 * notoggle => boolean don't show/hide button
157 * linktext => string title of show/hide button
160 public function __construct(stdClass $options) {
161 $this->viewcap = false;
162 $this->postcap = false;
164 // setup client_id
165 if (!empty($options->client_id)) {
166 $this->cid = $options->client_id;
167 } else {
168 $this->cid = uniqid();
171 // setup context
172 if (!empty($options->context)) {
173 $this->context = $options->context;
174 $this->contextid = $this->context->id;
175 } else if(!empty($options->contextid)) {
176 $this->contextid = $options->contextid;
177 $this->context = get_context_instance_by_id($this->contextid);
178 } else {
179 print_error('invalidcontext');
182 if (!empty($options->component)) {
183 // set and validate component
184 $this->set_component($options->component);
185 } else {
186 // component cannot be empty
187 throw new comment_exception('invalidcomponent');
190 // setup course
191 // course will be used to generate user profile link
192 if (!empty($options->course)) {
193 $this->courseid = $options->course->id;
194 } else if (!empty($options->courseid)) {
195 $this->courseid = $options->courseid;
196 } else {
197 $this->courseid = SITEID;
200 // setup coursemodule
201 if (!empty($options->cm)) {
202 $this->cm = $options->cm;
203 } else {
204 $this->cm = null;
207 // setup commentarea
208 if (!empty($options->area)) {
209 $this->commentarea = $options->area;
212 // setup itemid
213 if (!empty($options->itemid)) {
214 $this->itemid = $options->itemid;
215 } else {
216 $this->itemid = 0;
219 // setup customized linktext
220 if (!empty($options->linktext)) {
221 $this->linktext = $options->linktext;
222 } else {
223 $this->linktext = get_string('comments');
226 // setup options for callback functions
227 $this->comment_param = new stdClass();
228 $this->comment_param->context = $this->context;
229 $this->comment_param->courseid = $this->courseid;
230 $this->comment_param->cm = $this->cm;
231 $this->comment_param->commentarea = $this->commentarea;
232 $this->comment_param->itemid = $this->itemid;
234 // setup notoggle
235 if (!empty($options->notoggle)) {
236 $this->set_notoggle($options->notoggle);
239 // setup notoggle
240 if (!empty($options->autostart)) {
241 $this->set_autostart($options->autostart);
244 // setup displaycancel
245 if (!empty($options->displaycancel)) {
246 $this->set_displaycancel($options->displaycancel);
249 // setup displaytotalcount
250 if (!empty($options->showcount)) {
251 $this->set_displaytotalcount($options->showcount);
254 // setting post and view permissions
255 $this->check_permissions();
257 // load template
258 $this->template = html_writer::tag('div', '___picture___', array('class' => 'comment-userpicture'));
259 $this->template .= html_writer::start_tag('div', array('class' => 'comment-content'));
260 $this->template .= '___name___ - ';
261 $this->template .= html_writer::tag('span', '___time___');
262 $this->template .= html_writer::tag('div', '___content___');
263 $this->template .= html_writer::end_tag('div'); // .comment-content
264 if (!empty($this->plugintype)) {
265 $this->template = plugin_callback($this->plugintype, $this->pluginname, 'comment', 'template', array($this->comment_param), $this->template);
268 unset($options);
272 * Receive nonjs comment parameters
274 * @param moodle_page $page The page object to initialise comments within
275 * If not provided the global $PAGE is used
277 public static function init(moodle_page $page = null) {
278 global $PAGE;
280 if (empty($page)) {
281 $page = $PAGE;
283 // setup variables for non-js interface
284 self::$nonjs = optional_param('nonjscomment', '', PARAM_ALPHANUM);
285 self::$comment_itemid = optional_param('comment_itemid', '', PARAM_INT);
286 self::$comment_context = optional_param('comment_context', '', PARAM_INT);
287 self::$comment_page = optional_param('comment_page', '', PARAM_INT);
288 self::$comment_area = optional_param('comment_area', '', PARAM_AREA);
290 $page->requires->string_for_js('addcomment', 'moodle');
291 $page->requires->string_for_js('deletecomment', 'moodle');
292 $page->requires->string_for_js('comments', 'moodle');
293 $page->requires->string_for_js('commentsrequirelogin', 'moodle');
297 * Sets the component.
299 * This method shouldn't be public, changing the component once it has been set potentially
300 * invalidates permission checks.
301 * A coding_error is now thrown if code attempts to change the component.
303 * @param string $component
304 * @return void
306 public function set_component($component) {
307 if (!empty($this->component) && $this->component !== $component) {
308 throw new coding_exception('You cannot change the component of a comment once it has been set');
310 $this->component = $component;
311 list($this->plugintype, $this->pluginname) = normalize_component($component);
315 * Determines if the user can view the comment.
317 * @param bool $value
319 public function set_view_permission($value) {
320 $this->viewcap = (bool)$value;
324 * Determines if the user can post a comment
326 * @param bool $value
328 public function set_post_permission($value) {
329 $this->postcap = (bool)$value;
333 * check posting comments permission
334 * It will check based on user roles and ask modules
335 * If you need to check permission by modules, a
336 * function named $pluginname_check_comment_post must be implemented
338 private function check_permissions() {
339 $this->postcap = has_capability('moodle/comment:post', $this->context);
340 $this->viewcap = has_capability('moodle/comment:view', $this->context);
341 if (!empty($this->plugintype)) {
342 $permissions = plugin_callback($this->plugintype, $this->pluginname, 'comment', 'permissions', array($this->comment_param), array('post'=>false, 'view'=>false));
343 $this->postcap = $this->postcap && $permissions['post'];
344 $this->viewcap = $this->viewcap && $permissions['view'];
349 * Gets a link for this page that will work with JS disabled.
351 * @global moodle_page $PAGE
352 * @param moodle_page $page
353 * @return moodle_url
355 public function get_nojslink(moodle_page $page = null) {
356 if ($page === null) {
357 global $PAGE;
358 $page = $PAGE;
361 $link = new moodle_url($page->url, array(
362 'nonjscomment' => true,
363 'comment_itemid' => $this->itemid,
364 'comment_context' => $this->context->id,
365 'comment_area' => $this->commentarea,
367 $link->remove_params(array('comment_page'));
368 return $link;
372 * Sets the value of the notoggle option.
374 * If set to true then the user will not be able to expand and collase
375 * the comment section.
377 * @param bool $newvalue
379 public function set_notoggle($newvalue = true) {
380 $this->notoggle = (bool)$newvalue;
384 * Sets the value of the autostart option.
386 * If set to true then the comments will be loaded during page load.
387 * Normally this happens only once the user expands the comment section.
389 * @param bool $newvalue
391 public function set_autostart($newvalue = true) {
392 $this->autostart = (bool)$newvalue;
396 * Sets the displaycancel option
398 * If set to true then a cancel button will be shown when using the form
399 * to post comments.
401 * @param bool $newvalue
403 public function set_displaycancel($newvalue = true) {
404 $this->displaycancel = (bool)$newvalue;
408 * Sets the displaytotalcount option
410 * If set to true then the total number of comments will be displayed
411 * when printing comments.
413 * @param bool $newvalue
415 public function set_displaytotalcount($newvalue = true) {
416 $this->displaytotalcount = (bool)$newvalue;
420 * Initialises the JavaScript that enchances the comment API.
422 * @param moodle_page $page The moodle page object that the JavaScript should be
423 * initialised for.
425 public function initialise_javascript(moodle_page $page) {
427 $options = new stdClass;
428 $options->client_id = $this->cid;
429 $options->commentarea = $this->commentarea;
430 $options->itemid = $this->itemid;
431 $options->page = 0;
432 $options->courseid = $this->courseid;
433 $options->contextid = $this->contextid;
434 $options->component = $this->component;
435 $options->notoggle = $this->notoggle;
436 $options->autostart = $this->autostart;
438 $page->requires->js_init_call('M.core_comment.init', array($options), true);
440 return true;
444 * Prepare comment code in html
445 * @param boolean $return
446 * @return mixed
448 public function output($return = true) {
449 global $PAGE, $OUTPUT;
450 static $template_printed;
452 $this->initialise_javascript($PAGE);
454 if (!empty(self::$nonjs)) {
455 // return non js comments interface
456 return $this->print_comments(self::$comment_page, $return, true);
459 $html = '';
461 // print html template
462 // Javascript will use the template to render new comments
463 if (empty($template_printed) && $this->can_view()) {
464 $html .= html_writer::tag('div', $this->template, array('style' => 'display:none', 'id' => 'cmt-tmpl'));
465 $template_printed = true;
468 if ($this->can_view()) {
469 // print commenting icon and tooltip
470 $html .= html_writer::start_tag('div', array('class' => 'mdl-left'));
471 $html .= html_writer::link($this->get_nojslink($PAGE), get_string('showcommentsnonjs'), array('class' => 'showcommentsnonjs'));
473 if (!$this->notoggle) {
474 // If toggling is enabled (notoggle=false) then print the controls to toggle
475 // comments open and closed
476 $countstring = '';
477 if ($this->displaytotalcount) {
478 $countstring = '('.$this->count().')';
480 $html .= html_writer::start_tag('a', array('class' => 'comment-link', 'id' => 'comment-link-'.$this->cid, 'href' => '#'));
481 $html .= html_writer::empty_tag('img', array('id' => 'comment-img-'.$this->cid, 'src' => $OUTPUT->pix_url('t/collapsed'), 'alt' => $this->linktext, 'title' => $this->linktext));
482 $html .= html_writer::tag('span', $this->linktext.' '.$countstring, array('id' => 'comment-link-text-'.$this->cid));
483 $html .= html_writer::end_tag('a');
486 $html .= html_writer::start_tag('div', array('id' => 'comment-ctrl-'.$this->cid, 'class' => 'comment-ctrl'));
488 if ($this->autostart) {
489 // If autostart has been enabled print the comments list immediatly
490 $html .= html_writer::start_tag('ul', array('id' => 'comment-list-'.$this->cid, 'class' => 'comment-list comments-loaded'));
491 $html .= html_writer::tag('li', '', array('class' => 'first'));
492 $html .= $this->print_comments(0, true, false);
493 $html .= html_writer::end_tag('ul'); // .comment-list
494 $html .= $this->get_pagination(0);
495 } else {
496 $html .= html_writer::start_tag('ul', array('id' => 'comment-list-'.$this->cid, 'class' => 'comment-list'));
497 $html .= html_writer::tag('li', '', array('class' => 'first'));
498 $html .= html_writer::end_tag('ul'); // .comment-list
499 $html .= html_writer::tag('div', '', array('id' => 'comment-pagination-'.$this->cid, 'class' => 'comment-pagination'));
502 if ($this->can_post()) {
503 // print posting textarea
504 $html .= html_writer::start_tag('div', array('class' => 'comment-area'));
505 $html .= html_writer::start_tag('div', array('class' => 'db'));
506 $html .= html_writer::tag('textarea', '', array('name' => 'content', 'rows' => 2, 'cols' => 20, 'id' => 'dlg-content-'.$this->cid));
507 $html .= html_writer::end_tag('div'); // .db
509 $html .= html_writer::start_tag('div', array('class' => 'fd', 'id' => 'comment-action-'.$this->cid));
510 $html .= html_writer::link('#', get_string('savecomment'), array('id' => 'comment-action-post-'.$this->cid));
512 if ($this->displaycancel) {
513 $html .= html_writer::tag('span', ' | ');
514 $html .= html_writer::link('#', get_string('cancel'), array('id' => 'comment-action-cancel-'.$this->cid));
517 $html .= html_writer::end_tag('div'); // .fd
518 $html .= html_writer::end_tag('div'); // .comment-area
519 $html .= html_writer::tag('div', '', array('class' => 'clearer'));
522 $html .= html_writer::end_tag('div'); // .comment-ctrl
523 $html .= html_writer::end_tag('div'); // .mdl-left
524 } else {
525 $html = '';
528 if ($return) {
529 return $html;
530 } else {
531 echo $html;
536 * Return matched comments
538 * @param int $page
539 * @return mixed
541 public function get_comments($page = '') {
542 global $DB, $CFG, $USER, $OUTPUT;
543 if (!$this->can_view()) {
544 return false;
546 if (!is_numeric($page)) {
547 $page = 0;
549 $params = array();
550 $perpage = (!empty($CFG->commentsperpage))?$CFG->commentsperpage:15;
551 $start = $page * $perpage;
552 $ufields = user_picture::fields('u');
553 $sql = "SELECT $ufields, c.id AS cid, c.content AS ccontent, c.format AS cformat, c.timecreated AS ctimecreated
554 FROM {comments} c
555 JOIN {user} u ON u.id = c.userid
556 WHERE c.contextid = :contextid AND c.commentarea = :commentarea AND c.itemid = :itemid
557 ORDER BY c.timecreated DESC";
558 $params['contextid'] = $this->contextid;
559 $params['commentarea'] = $this->commentarea;
560 $params['itemid'] = $this->itemid;
562 $comments = array();
563 $formatoptions = array('overflowdiv' => true);
564 $rs = $DB->get_recordset_sql($sql, $params, $start, $perpage);
565 foreach ($rs as $u) {
566 $c = new stdClass();
567 $c->id = $u->cid;
568 $c->content = $u->ccontent;
569 $c->format = $u->cformat;
570 $c->timecreated = $u->ctimecreated;
571 $url = new moodle_url('/user/view.php', array('id'=>$u->id, 'course'=>$this->courseid));
572 $c->profileurl = $url->out(false);
573 $c->fullname = fullname($u);
574 $c->time = userdate($c->timecreated, get_string('strftimerecent', 'langconfig'));
575 $c->content = format_text($c->content, $c->format, $formatoptions);
576 $c->avatar = $OUTPUT->user_picture($u, array('size'=>18));
578 $candelete = $this->can_delete($c->id);
579 if (($USER->id == $u->id) || !empty($candelete)) {
580 $c->delete = true;
582 $comments[] = $c;
584 $rs->close();
586 if (!empty($this->plugintype)) {
587 // moodle module will filter comments
588 $comments = plugin_callback($this->plugintype, $this->pluginname, 'comment', 'display', array($comments, $this->comment_param), $comments);
591 return $comments;
595 * Returns the number of comments associated with the details of this object
597 * @global moodle_database $DB
598 * @return int
600 public function count() {
601 global $DB;
602 if ($this->totalcommentcount === null) {
603 $this->totalcommentcount = $DB->count_records('comments', array('itemid' => $this->itemid, 'commentarea' => $this->commentarea, 'contextid' => $this->context->id));
605 return $this->totalcommentcount;
609 * Returns HTML to display a pagination bar
611 * @global stdClass $CFG
612 * @global core_renderer $OUTPUT
613 * @param int $page
614 * @return string
616 public function get_pagination($page = 0) {
617 global $CFG, $OUTPUT;
618 $count = $this->count();
619 $perpage = (!empty($CFG->commentsperpage))?$CFG->commentsperpage:15;
620 $pages = (int)ceil($count/$perpage);
621 if ($pages == 1 || $pages == 0) {
622 return html_writer::tag('div', '', array('id' => 'comment-pagination-'.$this->cid, 'class' => 'comment-pagination'));
624 if (!empty(self::$nonjs)) {
625 // used in non-js interface
626 return $OUTPUT->paging_bar($count, $page, $perpage, $this->get_nojslink(), 'comment_page');
627 } else {
628 // return ajax paging bar
629 $str = '';
630 $str .= '<div class="comment-paging" id="comment-pagination-'.$this->cid.'">';
631 for ($p=0; $p<$pages; $p++) {
632 if ($p == $page) {
633 $class = 'curpage';
634 } else {
635 $class = 'pageno';
637 $str .= '<a href="#" class="'.$class.'" id="comment-page-'.$this->cid.'-'.$p.'">'.($p+1).'</a> ';
639 $str .= '</div>';
641 return $str;
645 * Add a new comment
647 * @global moodle_database $DB
648 * @param string $content
649 * @return mixed
651 public function add($content, $format = FORMAT_MOODLE) {
652 global $CFG, $DB, $USER, $OUTPUT;
653 if (!$this->can_post()) {
654 throw new comment_exception('nopermissiontocomment');
656 $now = time();
657 $newcmt = new stdClass;
658 $newcmt->contextid = $this->contextid;
659 $newcmt->commentarea = $this->commentarea;
660 $newcmt->itemid = $this->itemid;
661 $newcmt->content = $content;
662 $newcmt->format = $format;
663 $newcmt->userid = $USER->id;
664 $newcmt->timecreated = $now;
666 // This callback allow module to modify the content of comment, such as filter or replacement
667 plugin_callback($this->plugintype, $this->pluginname, 'comment', 'add', array(&$newcmt, $this->comment_param));
669 $cmt_id = $DB->insert_record('comments', $newcmt);
670 if (!empty($cmt_id)) {
671 $newcmt->id = $cmt_id;
672 $newcmt->time = userdate($now, get_string('strftimerecent', 'langconfig'));
673 $newcmt->fullname = fullname($USER);
674 $url = new moodle_url('/user/view.php', array('id' => $USER->id, 'course' => $this->courseid));
675 $newcmt->profileurl = $url->out();
676 $newcmt->content = format_text($newcmt->content, $format, array('overflowdiv'=>true));
677 $newcmt->avatar = $OUTPUT->user_picture($USER, array('size'=>16));
678 return $newcmt;
679 } else {
680 throw new comment_exception('dbupdatefailed');
685 * delete by context, commentarea and itemid
686 * @param stdClass|array $param {
687 * contextid => int the context in which the comments exist [required]
688 * commentarea => string the comment area [optional]
689 * itemid => int comment itemid [optional]
691 * @return boolean
693 public function delete_comments($param) {
694 global $DB;
695 $param = (array)$param;
696 if (empty($param['contextid'])) {
697 return false;
699 $DB->delete_records('comments', $param);
700 return true;
704 * Delete page_comments in whole course, used by course reset
706 * @param stdClass $context course context
708 public function reset_course_page_comments($context) {
709 global $DB;
710 $contexts = array();
711 $contexts[] = $context->id;
712 $children = get_child_contexts($context);
713 foreach ($children as $c) {
714 $contexts[] = $c->id;
716 list($ids, $params) = $DB->get_in_or_equal($contexts);
717 $DB->delete_records_select('comments', "commentarea='page_comments' AND contextid $ids", $params);
721 * Delete a comment
723 * @param int $commentid
724 * @return mixed
726 public function delete($commentid) {
727 global $DB, $USER;
728 $candelete = has_capability('moodle/comment:delete', $this->context);
729 if (!$comment = $DB->get_record('comments', array('id'=>$commentid))) {
730 throw new comment_exception('dbupdatefailed');
732 if (!($USER->id == $comment->userid || !empty($candelete))) {
733 throw new comment_exception('nopermissiontocomment');
735 $DB->delete_records('comments', array('id'=>$commentid));
736 return true;
740 * Print comments
742 * @param int $page
743 * @param boolean $return return comments list string or print it out
744 * @param boolean $nonjs print nonjs comments list or not?
745 * @return mixed
747 public function print_comments($page = 0, $return = true, $nonjs = true) {
748 global $DB, $CFG, $PAGE;
750 if (!$this->can_view()) {
751 return '';
754 $html = '';
755 if (!(self::$comment_itemid == $this->itemid &&
756 self::$comment_context == $this->context->id &&
757 self::$comment_area == $this->commentarea)) {
758 $page = 0;
760 $comments = $this->get_comments($page);
762 $html = '';
763 if ($nonjs) {
764 $html .= html_writer::tag('h3', get_string('comments'));
765 $html .= html_writer::start_tag('ul', array('id' => 'comment-list-'.$this->cid, 'class' => 'comment-list'));
767 // Reverse the comments array to display them in the correct direction
768 foreach (array_reverse($comments) as $cmt) {
769 $html .= html_writer::tag('li', $this->print_comment($cmt, $nonjs), array('id' => 'comment-'.$cmt->id.'-'.$this->cid));
771 if ($nonjs) {
772 $html .= html_writer::end_tag('ul');
773 $html .= $this->get_pagination($page);
775 if ($nonjs && $this->can_post()) {
776 // Form to add comments
777 $html .= html_writer::start_tag('form', array('method' => 'post', 'action' => new moodle_url('/comment/comment_post.php')));
778 // Comment parameters
779 $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'contextid', 'value' => $this->contextid));
780 $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'action', 'value' => 'add'));
781 $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'area', 'value' => $this->commentarea));
782 $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'component', 'value' => $this->component));
783 $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'itemid', 'value' => $this->itemid));
784 $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'courseid', 'value' => $this->courseid));
785 $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
786 $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'returnurl', 'value' => $PAGE->url));
787 // Textarea for the actual comment
788 $html .= html_writer::tag('textarea', '', array('name' => 'content', 'rows' => 2));
789 // Submit button to add the comment
790 $html .= html_writer::empty_tag('input', array('type' => 'submit', 'value' => get_string('submit')));
791 $html .= html_writer::end_tag('form');
793 if ($return) {
794 return $html;
795 } else {
796 echo $html;
801 * Returns an array containing comments in HTML format.
803 * @global core_renderer $OUTPUT
804 * @param stdClass $cmt {
805 * id => int comment id
806 * content => string comment content
807 * format => int comment text format
808 * timecreated => int comment's timecreated
809 * profileurl => string link to user profile
810 * fullname => comment author's full name
811 * avatar => string user's avatar
812 * delete => boolean does user have permission to delete comment?
814 * @param bool $nonjs
815 * @return array
817 public function print_comment($cmt, $nonjs = true) {
818 global $OUTPUT;
819 $patterns = array();
820 $replacements = array();
822 if (!empty($cmt->delete) && empty($nonjs)) {
823 $deletelink = html_writer::start_tag('div', array('class'=>'comment-delete'));
824 $deletelink .= html_writer::start_tag('a', array('href' => '#', 'id' => 'comment-delete-'.$this->cid.'-'.$cmt->id));
825 $deletelink .= $OUTPUT->pix_icon('t/delete', get_string('delete'));
826 $deletelink .= html_writer::end_tag('a');
827 $deletelink .= html_writer::end_tag('div');
828 $cmt->content = $deletelink . $cmt->content;
830 $patterns[] = '___picture___';
831 $patterns[] = '___name___';
832 $patterns[] = '___content___';
833 $patterns[] = '___time___';
834 $replacements[] = $cmt->avatar;
835 $replacements[] = html_writer::link($cmt->profileurl, $cmt->fullname);
836 $replacements[] = $cmt->content;
837 $replacements[] = userdate($cmt->timecreated, get_string('strftimerecent', 'langconfig'));
839 // use html template to format a single comment.
840 return str_replace($patterns, $replacements, $this->template);
844 * Revoke validate callbacks
846 * @param stdClass $params addtionall parameters need to add to callbacks
848 protected function validate($params=array()) {
849 foreach ($params as $key=>$value) {
850 $this->comment_param->$key = $value;
852 $validation = plugin_callback($this->plugintype, $this->pluginname, 'comment', 'validate', array($this->comment_param), false);
853 if (!$validation) {
854 throw new comment_exception('invalidcommentparam');
859 * Returns true if the user is able to view comments
860 * @return bool
862 public function can_view() {
863 $this->validate();
864 return !empty($this->viewcap);
868 * Returns true if the user can add comments against this comment description
869 * @return bool
871 public function can_post() {
872 $this->validate();
873 return isloggedin() && !empty($this->postcap);
877 * Returns true if the user can delete this comment
878 * @param int $commentid
879 * @return bool
881 public function can_delete($commentid) {
882 $this->validate(array('commentid'=>$commentid));
883 return has_capability('moodle/comment:delete', $this->context);
887 * Returns the component associated with the comment
888 * @return string
890 public function get_compontent() {
891 return $this->component;
895 * Returns the context associated with the comment
896 * @return stdClass
898 public function get_context() {
899 return $this->context;
903 * Returns the course id associated with the comment
904 * @return int
906 public function get_courseid() {
907 return $this->courseid;
911 * Returns the course module associated with the comment
913 * @return stdClass
915 public function get_cm() {
916 return $this->cm;
920 * Returns the item id associated with the comment
922 * @return int
924 public function get_itemid() {
925 return $this->itemid;
929 * Returns the comment area associated with the commentarea
931 * @return stdClass
933 public function get_commentarea() {
934 return $this->commentarea;
938 class comment_exception extends moodle_exception {