MDL-66999 theme_boost: @extend use .table classes in badges renderer
[moodle.git] / badges / renderer.php
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.
13 //
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  * Renderer for use with the badges output
19  *
20  * @package    core
21  * @subpackage badges
22  * @copyright  2012 onwards Totara Learning Solutions Ltd {@link http://www.totaralms.com/}
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  * @author     Yuliya Bozhko <yuliya.bozhko@totaralms.com>
25  */
27 require_once($CFG->libdir . '/badgeslib.php');
28 require_once($CFG->libdir . '/tablelib.php');
30 /**
31  * Standard HTML output renderer for badges
32  */
33 class core_badges_renderer extends plugin_renderer_base {
35     // Outputs badges list.
36     public function print_badges_list($badges, $userid, $profile = false, $external = false) {
37         global $USER, $CFG;
38         foreach ($badges as $badge) {
39             if (!$external) {
40                 $context = ($badge->type == BADGE_TYPE_SITE) ? context_system::instance() : context_course::instance($badge->courseid);
41                 $bname = $badge->name;
42                 $imageurl = moodle_url::make_pluginfile_url($context->id, 'badges', 'badgeimage', $badge->id, '/', 'f1', false);
43             } else {
44                 $bname = '';
45                 $imageurl = '';
46                 if (!empty($badge->name)) {
47                     $bname = s($badge->name);
48                 }
49                 if (!empty($badge->image)) {
50                     $imageurl = $badge->image;
51                 }
52                 if (isset($badge->assertion->badge->name)) {
53                     $bname = s($badge->assertion->badge->name);
54                 }
55                 if (isset($badge->imageUrl)) {
56                     $imageurl = $badge->imageUrl;
57                 }
58             }
60             $name = html_writer::tag('span', $bname, array('class' => 'badge-name'));
62             $image = html_writer::empty_tag('img', array('src' => $imageurl, 'class' => 'badge-image'));
63             if (!empty($badge->dateexpire) && $badge->dateexpire < time()) {
64                 $image .= $this->output->pix_icon('i/expired',
65                         get_string('expireddate', 'badges', userdate($badge->dateexpire)),
66                         'moodle',
67                         array('class' => 'expireimage'));
68                 $name .= '(' . get_string('expired', 'badges') . ')';
69             }
71             $download = $status = $push = '';
72             if (($userid == $USER->id) && !$profile) {
73                 $params = array(
74                     'download' => $badge->id,
75                     'hash' => $badge->uniquehash,
76                     'sesskey' => sesskey()
77                 );
78                 $url = new moodle_url(
79                     'mybadges.php',
80                     $params
81                 );
82                 $notexpiredbadge = (empty($badge->dateexpire) || $badge->dateexpire > time());
83                 $backpackexists = badges_user_has_backpack($USER->id);
84                 if (!empty($CFG->badges_allowexternalbackpack) && $notexpiredbadge && $backpackexists) {
85                     $assertion = new moodle_url('/badges/assertion.php', array('b' => $badge->uniquehash));
86                     $action = null;
87                     if (badges_open_badges_backpack_api() == OPEN_BADGES_V1) {
88                         $action = new component_action('click', 'addtobackpack', array('assertion' => $assertion->out(false)));
89                         $addurl = new moodle_url('#');
90                     } else {
91                         $addurl = new moodle_url('/badges/backpack-add.php', array('hash' => $badge->uniquehash));
92                     }
93                     $icon = new pix_icon('t/backpack', get_string('addtobackpack', 'badges'));
94                     $push = $this->output->action_icon($addurl, $icon, $action);
95                 }
97                 $download = $this->output->action_icon($url, new pix_icon('t/download', get_string('download')));
98                 if ($badge->visible) {
99                     $url = new moodle_url('mybadges.php', array('hide' => $badge->issuedid, 'sesskey' => sesskey()));
100                     $status = $this->output->action_icon($url, new pix_icon('t/hide', get_string('makeprivate', 'badges')));
101                 } else {
102                     $url = new moodle_url('mybadges.php', array('show' => $badge->issuedid, 'sesskey' => sesskey()));
103                     $status = $this->output->action_icon($url, new pix_icon('t/show', get_string('makepublic', 'badges')));
104                 }
105             }
107             if (!$profile) {
108                 $url = new moodle_url('badge.php', array('hash' => $badge->uniquehash));
109             } else {
110                 if (!$external) {
111                     $url = new moodle_url('/badges/badge.php', array('hash' => $badge->uniquehash));
112                 } else {
113                     $hash = hash('md5', $badge->hostedUrl);
114                     $url = new moodle_url('/badges/external.php', array('hash' => $hash, 'user' => $userid));
115                 }
116             }
117             $actions = html_writer::tag('div', $push . $download . $status, array('class' => 'badge-actions'));
118             $items[] = html_writer::link($url, $image . $actions . $name, array('title' => $bname));
119         }
121         return html_writer::alist($items, array('class' => 'badges'));
122     }
124     // Recipients selection form.
125     public function recipients_selection_form(user_selector_base $existinguc, user_selector_base $potentialuc) {
126         $output = '';
127         $formattributes = array();
128         $formattributes['id'] = 'recipientform';
129         $formattributes['action'] = $this->page->url;
130         $formattributes['method'] = 'post';
131         $output .= html_writer::start_tag('form', $formattributes);
132         $output .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
134         $existingcell = new html_table_cell();
135         $existingcell->text = $existinguc->display(true);
136         $existingcell->attributes['class'] = 'existing';
137         $actioncell = new html_table_cell();
138         $actioncell->text  = html_writer::start_tag('div', array());
139         $actioncell->text .= html_writer::empty_tag('input', array(
140                     'type' => 'submit',
141                     'name' => 'award',
142                     'value' => $this->output->larrow() . ' ' . get_string('award', 'badges'),
143                     'class' => 'actionbutton btn btn-secondary')
144                 );
145         $actioncell->text .= html_writer::empty_tag('input', array(
146                     'type' => 'submit',
147                     'name' => 'revoke',
148                     'value' => get_string('revoke', 'badges') . ' ' . $this->output->rarrow(),
149                     'class' => 'actionbutton btn btn-secondary')
150                 );
151         $actioncell->text .= html_writer::end_tag('div', array());
152         $actioncell->attributes['class'] = 'actions';
153         $potentialcell = new html_table_cell();
154         $potentialcell->text = $potentialuc->display(true);
155         $potentialcell->attributes['class'] = 'potential';
157         $table = new html_table();
158         $table->attributes['class'] = 'recipienttable boxaligncenter';
159         $table->data = array(new html_table_row(array($existingcell, $actioncell, $potentialcell)));
160         $output .= html_writer::table($table);
162         $output .= html_writer::end_tag('form');
163         return $output;
164     }
166     // Prints a badge overview infomation.
167     public function print_badge_overview($badge, $context) {
168         $display = "";
169         $languages = get_string_manager()->get_list_of_languages();
171         // Badge details.
172         $display .= $this->heading(get_string('badgedetails', 'badges'), 3);
173         $dl = array();
174         $dl[get_string('name')] = $badge->name;
175         $dl[get_string('version', 'badges')] = $badge->version;
176         $dl[get_string('language')] = $languages[$badge->language];
177         $dl[get_string('description', 'badges')] = $badge->description;
178         $dl[get_string('createdon', 'search')] = userdate($badge->timecreated);
179         $dl[get_string('badgeimage', 'badges')] = print_badge_image($badge, $context, 'large');
180         $dl[get_string('imageauthorname', 'badges')] = $badge->imageauthorname;
181         $dl[get_string('imageauthoremail', 'badges')] =
182             html_writer::tag('a', $badge->imageauthoremail, array('href' => 'mailto:' . $badge->imageauthoremail));
183         $dl[get_string('imageauthorurl', 'badges')] =
184             html_writer::link($badge->imageauthorurl, $badge->imageauthorurl, array('target' => '_blank'));
185         $dl[get_string('imagecaption', 'badges')] = $badge->imagecaption;
186         $display .= $this->definition_list($dl);
188         // Issuer details.
189         $display .= $this->heading(get_string('issuerdetails', 'badges'), 3);
190         $dl = array();
191         $dl[get_string('issuername', 'badges')] = $badge->issuername;
192         $dl[get_string('contact', 'badges')] = html_writer::tag('a', $badge->issuercontact, array('href' => 'mailto:' . $badge->issuercontact));
193         $display .= $this->definition_list($dl);
195         // Issuance details if any.
196         $display .= $this->heading(get_string('issuancedetails', 'badges'), 3);
197         if ($badge->can_expire()) {
198             if ($badge->expiredate) {
199                 $display .= get_string('expiredate', 'badges', userdate($badge->expiredate));
200             } else if ($badge->expireperiod) {
201                 if ($badge->expireperiod < 60) {
202                     $display .= get_string('expireperiods', 'badges', round($badge->expireperiod, 2));
203                 } else if ($badge->expireperiod < 60 * 60) {
204                     $display .= get_string('expireperiodm', 'badges', round($badge->expireperiod / 60, 2));
205                 } else if ($badge->expireperiod < 60 * 60 * 24) {
206                     $display .= get_string('expireperiodh', 'badges', round($badge->expireperiod / 60 / 60, 2));
207                 } else {
208                     $display .= get_string('expireperiod', 'badges', round($badge->expireperiod / 60 / 60 / 24, 2));
209                 }
210             }
211         } else {
212             $display .= get_string('noexpiry', 'badges');
213         }
215         // Criteria details if any.
216         $display .= $this->heading(get_string('bcriteria', 'badges'), 3);
217         if ($badge->has_criteria()) {
218             $display .= self::print_badge_criteria($badge);
219         } else {
220             $display .= get_string('nocriteria', 'badges');
221             if (has_capability('moodle/badges:configurecriteria', $context)) {
222                 $display .= $this->output->single_button(
223                     new moodle_url('/badges/criteria.php', array('id' => $badge->id)),
224                     get_string('addcriteria', 'badges'), 'POST', array('class' => 'activatebadge'));
225             }
226         }
228         // Awards details if any.
229         if (has_capability('moodle/badges:viewawarded', $context)) {
230             $display .= $this->heading(get_string('awards', 'badges'), 3);
231             if ($badge->has_awards()) {
232                 $url = new moodle_url('/badges/recipients.php', array('id' => $badge->id));
233                 $a = new stdClass();
234                 $a->link = $url->out();
235                 $a->count = count($badge->get_awards());
236                 $display .= get_string('numawards', 'badges', $a);
237             } else {
238                 $display .= get_string('noawards', 'badges');
239             }
241             if (has_capability('moodle/badges:awardbadge', $context) &&
242                 $badge->has_manual_award_criteria() &&
243                 $badge->is_active()) {
244                 $display .= $this->output->single_button(
245                         new moodle_url('/badges/award.php', array('id' => $badge->id)),
246                         get_string('award', 'badges'), 'POST', array('class' => 'activatebadge'));
247             }
248         }
250         $display .= self::print_badge_endorsement($badge);
251         $display .= self::print_badge_related($badge);
252         $display .= self::print_badge_alignments($badge);
254         return html_writer::div($display, null, array('id' => 'badge-overview'));
255     }
257     // Prints action icons for the badge.
258     public function print_badge_table_actions($badge, $context) {
259         $actions = "";
261         if (has_capability('moodle/badges:configuredetails', $context) && $badge->has_criteria()) {
262             // Activate/deactivate badge.
263             if ($badge->status == BADGE_STATUS_INACTIVE || $badge->status == BADGE_STATUS_INACTIVE_LOCKED) {
264                 // "Activate" will go to another page and ask for confirmation.
265                 $url = new moodle_url('/badges/action.php');
266                 $url->param('id', $badge->id);
267                 $url->param('activate', true);
268                 $url->param('sesskey', sesskey());
269                 $return = new moodle_url(qualified_me());
270                 $url->param('return', $return->out_as_local_url(false));
271                 $actions .= $this->output->action_icon($url, new pix_icon('t/show', get_string('activate', 'badges'))) . " ";
272             } else {
273                 $url = new moodle_url(qualified_me());
274                 $url->param('lock', $badge->id);
275                 $url->param('sesskey', sesskey());
276                 $actions .= $this->output->action_icon($url, new pix_icon('t/hide', get_string('deactivate', 'badges'))) . " ";
277             }
278         }
280         // Award badge manually.
281         if ($badge->has_manual_award_criteria() &&
282                 has_capability('moodle/badges:awardbadge', $context) &&
283                 $badge->is_active()) {
284             $url = new moodle_url('/badges/award.php', array('id' => $badge->id));
285             $actions .= $this->output->action_icon($url, new pix_icon('t/award', get_string('award', 'badges'))) . " ";
286         }
288         // Edit badge.
289         if (has_capability('moodle/badges:configuredetails', $context)) {
290             $url = new moodle_url('/badges/edit.php', array('id' => $badge->id, 'action' => 'badge'));
291             $actions .= $this->output->action_icon($url, new pix_icon('t/edit', get_string('edit'))) . " ";
292         }
294         // Duplicate badge.
295         if (has_capability('moodle/badges:createbadge', $context)) {
296             $url = new moodle_url('/badges/action.php', array('copy' => '1', 'id' => $badge->id, 'sesskey' => sesskey()));
297             $actions .= $this->output->action_icon($url, new pix_icon('t/copy', get_string('copy'))) . " ";
298         }
300         // Delete badge.
301         if (has_capability('moodle/badges:deletebadge', $context)) {
302             $url = new moodle_url(qualified_me());
303             $url->param('delete', $badge->id);
304             $actions .= $this->output->action_icon($url, new pix_icon('t/delete', get_string('delete'))) . " ";
305         }
307         return $actions;
308     }
310     /**
311      * Render an issued badge.
312      *
313      * @param \core_badges\output\issued_badge $ibadge
314      * @return string
315      */
316     protected function render_issued_badge(\core_badges\output\issued_badge $ibadge) {
317         global $USER, $CFG, $DB, $SITE;
318         $issued = $ibadge->issued;
319         $userinfo = $ibadge->recipient;
320         $badgeclass = $ibadge->badgeclass;
321         $badge = new badge($ibadge->badgeid);
322         $now = time();
323         $expiration = isset($issued['expires']) ? $issued['expires'] : $now + 86400;
324         $badgeimage = is_array($badgeclass['image']) ? $badgeclass['image']['id'] : $badgeclass['image'];
325         $languages = get_string_manager()->get_list_of_languages();
327         $output = '';
328         $output .= html_writer::start_tag('div', array('id' => 'badge'));
329         $output .= html_writer::start_tag('div', array('id' => 'badge-image'));
330         $output .= html_writer::empty_tag('img', array('src' => $badgeimage, 'alt' => $badge->name, 'width' => '100'));
331         if ($expiration < $now) {
332             $output .= $this->output->pix_icon('i/expired',
333             get_string('expireddate', 'badges', userdate($issued['expires'])),
334                 'moodle',
335                 array('class' => 'expireimage'));
336         }
338         if ($USER->id == $userinfo->id && !empty($CFG->enablebadges)) {
339             $output .= $this->output->single_button(
340                         new moodle_url('/badges/badge.php', array('hash' => $issued['uid'], 'bake' => true)),
341                         get_string('download'),
342                         'POST');
343             if (!empty($CFG->badges_allowexternalbackpack) && ($expiration > $now) && badges_user_has_backpack($USER->id)) {
345                 if (badges_open_badges_backpack_api() == OPEN_BADGES_V1) {
346                     $assertion = new moodle_url('/badges/assertion.php', array('b' => $issued['uid']));
347                     $action = new component_action('click', 'addtobackpack', array('assertion' => $assertion->out(false)));
348                     $attributes = array(
349                             'type'  => 'button',
350                             'class' => 'btn btn-secondary m-1',
351                             'id'    => 'addbutton',
352                             'value' => get_string('addtobackpack', 'badges'));
353                     $tobackpack = html_writer::tag('input', '', $attributes);
354                     $this->output->add_action_handler($action, 'addbutton');
355                     $output .= $tobackpack;
356                 } else {
357                     $assertion = new moodle_url('/badges/backpack-add.php', array('hash' => $issued['uid']));
358                     $attributes = ['class' => 'btn btn-secondary m-1', 'role' => 'button'];
359                     $tobackpack = html_writer::link($assertion, get_string('addtobackpack', 'badges'), $attributes);
360                     $output .= $tobackpack;
361                 }
362             }
363         }
364         $output .= html_writer::end_tag('div');
366         $output .= html_writer::start_tag('div', array('id' => 'badge-details'));
367         // Recipient information.
368         $output .= $this->output->heading(get_string('recipientdetails', 'badges'), 3);
369         $dl = array();
370         if ($userinfo->deleted) {
371             $strdata = new stdClass();
372             $strdata->user = fullname($userinfo);
373             $strdata->site = format_string($SITE->fullname, true, array('context' => context_system::instance()));
375             $dl[get_string('name')] = get_string('error:userdeleted', 'badges', $strdata);
376         } else {
377             $dl[get_string('name')] = fullname($userinfo);
378         }
379         $output .= $this->definition_list($dl);
381         $output .= $this->output->heading(get_string('issuerdetails', 'badges'), 3);
382         $dl = array();
383         $dl[get_string('issuername', 'badges')] = $badge->issuername;
384         if (isset($badge->issuercontact) && !empty($badge->issuercontact)) {
385             $dl[get_string('contact', 'badges')] = obfuscate_mailto($badge->issuercontact);
386         }
387         $output .= $this->definition_list($dl);
389         $output .= $this->output->heading(get_string('badgedetails', 'badges'), 3);
390         $dl = array();
391         $dl[get_string('name')] = $badge->name;
392         if (!empty($badge->version)) {
393             $dl[get_string('version', 'badges')] = $badge->version;
394         }
395         if (!empty($badge->language)) {
396             $dl[get_string('language')] = $languages[$badge->language];
397         }
398         $dl[get_string('description', 'badges')] = $badge->description;
399         if (!empty($badge->imageauthorname)) {
400             $dl[get_string('imageauthorname', 'badges')] = $badge->imageauthorname;
401         }
402         if (!empty($badge->imageauthoremail)) {
403             $dl[get_string('imageauthoremail', 'badges')] =
404                     html_writer::tag('a', $badge->imageauthoremail, array('href' => 'mailto:' . $badge->imageauthoremail));
405         }
406         if (!empty($badge->imageauthorurl)) {
407             $dl[get_string('imageauthorurl', 'badges')] =
408                     html_writer::link($badge->imageauthorurl, $badge->imageauthorurl, array('target' => '_blank'));
409         }
410         if (!empty($badge->imagecaption)) {
411             $dl[get_string('imagecaption', 'badges')] = $badge->imagecaption;
412         }
414         if ($badge->type == BADGE_TYPE_COURSE && isset($badge->courseid)) {
415             $coursename = $DB->get_field('course', 'fullname', array('id' => $badge->courseid));
416             $dl[get_string('course')] = $coursename;
417         }
418         $dl[get_string('bcriteria', 'badges')] = self::print_badge_criteria($badge);
419         $output .= $this->definition_list($dl);
421         $output .= $this->output->heading(get_string('issuancedetails', 'badges'), 3);
422         $dl = array();
423         if (!is_numeric($issued['issuedOn'])) {
424             $issued['issuedOn'] = strtotime($issued['issuedOn']);
425         }
426         $dl[get_string('dateawarded', 'badges')] = userdate($issued['issuedOn']);
427         if (isset($issued['expires'])) {
428             if (!is_numeric($issued['expires'])) {
429                 $issued['expires'] = strtotime($issued['expires']);
430             }
431             if ($issued['expires'] < $now) {
432                 $dl[get_string('expirydate', 'badges')] = userdate($issued['expires']) . get_string('warnexpired', 'badges');
434             } else {
435                 $dl[get_string('expirydate', 'badges')] = userdate($issued['expires']);
436             }
437         }
439         // Print evidence.
440         $agg = $badge->get_aggregation_methods();
441         $evidence = $badge->get_criteria_completions($userinfo->id);
442         $eids = array_map(function($o) {
443             return $o->critid;
444         }, $evidence);
445         unset($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]);
447         $items = array();
448         foreach ($badge->criteria as $type => $c) {
449             if (in_array($c->id, $eids)) {
450                 if (count($c->params) == 1) {
451                     $items[] = get_string('criteria_descr_single_' . $type , 'badges') . $c->get_details();
452                 } else {
453                     $items[] = get_string('criteria_descr_' . $type , 'badges',
454                             core_text::strtoupper($agg[$badge->get_aggregation_method($type)])) . $c->get_details();
455                 }
456             }
457         }
459         $dl[get_string('evidence', 'badges')] = get_string('completioninfo', 'badges') . html_writer::alist($items, array(), 'ul');
460         $output .= $this->definition_list($dl);
461         $endorsement = $badge->get_endorsement();
462         if (!empty($endorsement)) {
463             $output .= self::print_badge_endorsement($badge);
464         }
466         $relatedbadges = $badge->get_related_badges(true);
467         $items = array();
468         foreach ($relatedbadges as $related) {
469             $relatedurl = new moodle_url('/badges/overview.php', array('id' => $related->id));
470             $items[] = html_writer::link($relatedurl->out(), $related->name, array('target' => '_blank'));
471         }
472         if (!empty($items)) {
473             $output .= $this->heading(get_string('relatedbages', 'badges'), 3);
474             $output .= html_writer::alist($items, array(), 'ul');
475         }
477         $alignments = $badge->get_alignments();
478         if (!empty($alignments)) {
479             $output .= $this->heading(get_string('alignment', 'badges'), 3);
480             $items = array();
481             foreach ($alignments as $alignment) {
482                 $items[] = html_writer::link($alignment->targeturl, $alignment->targetname, array('target' => '_blank'));
483             }
484             $output .= html_writer::alist($items, array(), 'ul');
485         }
486         $output .= html_writer::end_tag('div');
488         return $output;
489     }
491     /**
492      * Render an external badge.
493      *
494      * @param \core_badges\output\external_badge $ibadge
495      * @return string
496      */
497     protected function render_external_badge(\core_badges\output\external_badge $ibadge) {
498         $issued = $ibadge->issued;
499         $assertion = $issued->assertion;
500         $issuer = $assertion->badge->issuer;
501         $userinfo = $ibadge->recipient;
502         $table = new html_table();
503         $today = strtotime(date('Y-m-d'));
505         $output = '';
506         $output .= html_writer::start_tag('div', array('id' => 'badge'));
507         $output .= html_writer::start_tag('div', array('id' => 'badge-image'));
508         if (isset($issued->imageUrl)) {
509             $issued->image = $issued->imageUrl;
510         }
511         $output .= html_writer::empty_tag('img', array('src' => $issued->image, 'width' => '100'));
512         if (isset($assertion->expires)) {
513             $expiration = is_numeric($assertion->expires) ? $assertion->expires : strtotime($assertion->expires);
514             if ($expiration < $today) {
515                 $output .= $this->output->pix_icon('i/expired',
516                         get_string('expireddate', 'badges', userdate($expiration)),
517                         'moodle',
518                         array('class' => 'expireimage'));
519             }
520         }
521         $output .= html_writer::end_tag('div');
523         $output .= html_writer::start_tag('div', array('id' => 'badge-details'));
525         // Recipient information.
526         $output .= $this->output->heading(get_string('recipientdetails', 'badges'), 3);
527         $dl = array();
528         // Technically, we should alway have a user at this point, but added an extra check just in case.
529         if ($userinfo) {
530             if (!$ibadge->valid) {
531                 $notify = $this->output->notification(get_string('recipientvalidationproblem', 'badges'), 'notifynotice');
532                 $dl[get_string('name')] = fullname($userinfo) . $notify;
533             } else {
534                 $dl[get_string('name')] = fullname($userinfo);
535             }
536         } else {
537             $notify = $this->output->notification(get_string('recipientidentificationproblem', 'badges'), 'notifynotice');
538             $dl[get_string('name')] = $notify;
539         }
540         $output .= $this->definition_list($dl);
542         $output .= $this->output->heading(get_string('issuerdetails', 'badges'), 3);
543         $dl = array();
544         $dl[get_string('issuername', 'badges')] = s($issuer->name);
545         if (isset($issuer->origin)) {
546             $dl[get_string('issuerurl', 'badges')] = html_writer::tag('a', $issuer->origin, array('href' => $issuer->origin));
547         }
549         if (isset($issuer->contact)) {
550             $dl[get_string('contact', 'badges')] = obfuscate_mailto($issuer->contact);
551         }
552         $output .= $this->definition_list($dl);
554         $output .= $this->output->heading(get_string('badgedetails', 'badges'), 3);
555         $dl = array();
556         $dl[get_string('name')] = s($assertion->badge->name);
557         $dl[get_string('description', 'badges')] = s($assertion->badge->description);
558         if (isset($assertion->badge->criteria)) {
559             $dl[get_string('bcriteria', 'badges')] = html_writer::tag(
560                 'a',
561                 s($assertion->badge->criteria),
562                 array('href' => $assertion->badge->criteria)
563             );
564         }
565         $output .= $this->definition_list($dl);
567         $dl = array();
568         if (isset($assertion->issued_on)) {
569             $issuedate = is_numeric($assertion->issued_on) ? $assertion->issued_on : strtotime($assertion->issued_on);
570             $dl[get_string('dateawarded', 'badges')] = userdate($issuedate);
571         }
572         if (isset($assertion->expires)) {
573             if ($expiration < $today) {
574                 $dl[get_string('expirydate', 'badges')] = userdate($expiration) . get_string('warnexpired', 'badges');
575             } else {
576                 $dl[get_string('expirydate', 'badges')] = userdate($expiration);
577             }
578         }
579         if (isset($assertion->evidence)) {
580             $dl[get_string('evidence', 'badges')] = html_writer::tag(
581                 'a',
582                 s($assertion->evidence),
583                 array('href' => $assertion->evidence)
584             );
585         }
586         if (!empty($dl)) {
587             $output .= $this->output->heading(get_string('issuancedetails', 'badges'), 3);
588             $output .= $this->definition_list($dl);
589         }
590         $output .= html_writer::end_tag('div');
592         return $output;
593     }
595     /**
596      * Render a collection of user badges.
597      *
598      * @param \core_badges\output\badge_user_collection $badges
599      * @return string
600      */
601     protected function render_badge_user_collection(\core_badges\output\badge_user_collection $badges) {
602         global $CFG, $USER, $SITE, $OUTPUT;
603         $backpack = $badges->backpack;
604         $mybackpack = new moodle_url('/badges/mybackpack.php');
606         $paging = new paging_bar($badges->totalcount, $badges->page, $badges->perpage, $this->page->url, 'page');
607         $htmlpagingbar = $this->render($paging);
609         // Set backpack connection string.
610         $backpackconnect = '';
611         if (!empty($CFG->badges_allowexternalbackpack) && is_null($backpack)) {
612             $backpackconnect = $this->output->box(get_string('localconnectto', 'badges', $mybackpack->out()), 'noticebox');
613         }
614         // Search box.
615         $searchform = $this->output->box($this->helper_search_form($badges->search), 'boxwidthwide boxaligncenter');
617         // Download all button.
618         $actionhtml = $this->output->single_button(
619                     new moodle_url('/badges/mybadges.php', array('downloadall' => true, 'sesskey' => sesskey())),
620                     get_string('downloadall'), 'POST', array('class' => 'activatebadge'));
621         $downloadall = $this->output->box('', 'col-md-3');
622         $downloadall .= $this->output->box($actionhtml, 'col-md-9');
623         $downloadall = $this->output->box($downloadall, 'row m-l-2');
625         // Local badges.
626         $localhtml = html_writer::start_tag('div', array('id' => 'issued-badge-table', 'class' => 'generalbox'));
627         $sitename = format_string($SITE->fullname, true, array('context' => context_system::instance()));
628         $heading = get_string('localbadges', 'badges', $sitename);
629         $localhtml .= $this->output->heading_with_help($heading, 'localbadgesh', 'badges');
630         if ($badges->badges) {
631             $countmessage = $this->output->box(get_string('badgesearned', 'badges', $badges->totalcount));
633             $htmllist = $this->print_badges_list($badges->badges, $USER->id);
634             $localhtml .= $backpackconnect . $countmessage . $searchform;
635             $localhtml .= $htmlpagingbar . $htmllist . $htmlpagingbar . $downloadall;
636         } else {
637             $localhtml .= $searchform . $this->output->notification(get_string('nobadges', 'badges'));
638         }
639         $localhtml .= html_writer::end_tag('div');
641         // External badges.
642         $externalhtml = "";
643         if (!empty($CFG->badges_allowexternalbackpack)) {
644             $externalhtml .= html_writer::start_tag('div', array('class' => 'generalbox'));
645             $externalhtml .= $this->output->heading_with_help(get_string('externalbadges', 'badges'), 'externalbadges', 'badges');
646             if (!is_null($backpack)) {
647                 if ($backpack->backpackid != $CFG->badges_site_backpack) {
648                     $externalhtml .= $OUTPUT->notification(get_string('backpackneedsupdate', 'badges'), 'warning');
650                 }
651                 if ($backpack->totalcollections == 0) {
652                     $externalhtml .= get_string('nobackpackcollectionssummary', 'badges', $backpack);
653                 } else {
654                     if ($backpack->totalbadges == 0) {
655                         $externalhtml .= get_string('nobackpackbadgessummary', 'badges', $backpack);
656                     } else {
657                         $externalhtml .= get_string('backpackbadgessummary', 'badges', $backpack);
658                         $externalhtml .= '<br/><br/>' . $this->print_badges_list($backpack->badges, $USER->id, true, true);
659                     }
660                 }
661             } else {
662                 $externalhtml .= get_string('externalconnectto', 'badges', $mybackpack->out());
663             }
665             $externalhtml .= html_writer::end_tag('div');
666             $attr = ['class' => 'btn btn-secondary'];
667             $label = get_string('backpackbadgessettings', 'badges');
668             $backpacksettings = html_writer::link(new moodle_url('/badges/mybackpack.php'), $label, $attr);
669             $actionshtml = $this->output->box('', 'col-md-3');
670             $actionshtml .= $this->output->box($backpacksettings, 'col-md-9');
671             $actionshtml = $this->output->box($actionshtml, 'row m-l-2');
672             $externalhtml .= $actionshtml;
673         }
675         return $localhtml . $externalhtml;
676     }
678     /**
679      * Render a collection of badges.
680      *
681      * @param \core_badges\output\badge_collection $badges
682      * @return string
683      */
684     protected function render_badge_collection(\core_badges\output\badge_collection $badges) {
685         $paging = new paging_bar($badges->totalcount, $badges->page, $badges->perpage, $this->page->url, 'page');
686         $htmlpagingbar = $this->render($paging);
687         $table = new html_table();
688         $table->attributes['class'] = 'table table-bordered table-striped';
690         $sortbyname = $this->helper_sortable_heading(get_string('name'),
691                 'name', $badges->sort, $badges->dir);
692         $sortbyawarded = $this->helper_sortable_heading(get_string('awardedtoyou', 'badges'),
693                 'dateissued', $badges->sort, $badges->dir);
694         $table->head = array(
695                     get_string('badgeimage', 'badges'),
696                     $sortbyname,
697                     get_string('description', 'badges'),
698                     get_string('bcriteria', 'badges'),
699                     $sortbyawarded
700                 );
701         $table->colclasses = array('badgeimage', 'name', 'description', 'criteria', 'awards');
703         foreach ($badges->badges as $badge) {
704             $badgeimage = print_badge_image($badge, $this->page->context, 'large');
705             $name = $badge->name;
706             $description = $badge->description;
707             $criteria = self::print_badge_criteria($badge);
708             if ($badge->dateissued) {
709                 $icon = new pix_icon('i/valid',
710                             get_string('dateearned', 'badges',
711                                 userdate($badge->dateissued, get_string('strftimedatefullshort', 'core_langconfig'))));
712                 $badgeurl = new moodle_url('/badges/badge.php', array('hash' => $badge->uniquehash));
713                 $awarded = $this->output->action_icon($badgeurl, $icon, null, null, true);
714             } else {
715                 $awarded = "";
716             }
717             $row = array($badgeimage, $name, $description, $criteria, $awarded);
718             $table->data[] = $row;
719         }
721         $htmltable = html_writer::table($table);
723         return $htmlpagingbar . $htmltable . $htmlpagingbar;
724     }
726     /**
727      * Render a table of badges.
728      *
729      * @param \core_badges\output\badge_management $badges
730      * @return string
731      */
732     protected function render_badge_management(\core_badges\output\badge_management $badges) {
733         $paging = new paging_bar($badges->totalcount, $badges->page, $badges->perpage, $this->page->url, 'page');
735         // New badge button.
736         $htmlnew = '';
737         if (has_capability('moodle/badges:createbadge', $this->page->context)) {
738             $n['type'] = $this->page->url->get_param('type');
739             $n['id'] = $this->page->url->get_param('id');
740             $btn = $this->output->single_button(new moodle_url('newbadge.php', $n), get_string('newbadge', 'badges'));
741             $htmlnew = $this->output->box($btn);
742         }
744         $htmlpagingbar = $this->render($paging);
745         $table = new html_table();
746         $table->attributes['class'] = 'table table-bordered table-striped';
748         $sortbyname = $this->helper_sortable_heading(get_string('name'),
749                 'name', $badges->sort, $badges->dir);
750         $sortbystatus = $this->helper_sortable_heading(get_string('status', 'badges'),
751                 'status', $badges->sort, $badges->dir);
752         $table->head = array(
753                 $sortbyname,
754                 $sortbystatus,
755                 get_string('bcriteria', 'badges'),
756                 get_string('awards', 'badges'),
757                 get_string('actions')
758             );
759         $table->colclasses = array('name', 'status', 'criteria', 'awards', 'actions');
761         foreach ($badges->badges as $b) {
762             $style = !$b->is_active() ? array('class' => 'dimmed') : array();
763             $forlink =  print_badge_image($b, $this->page->context) . ' ' .
764                         html_writer::start_tag('span') . $b->name . html_writer::end_tag('span');
765             $name = html_writer::link(new moodle_url('/badges/overview.php', array('id' => $b->id)), $forlink, $style);
766             $status = $b->statstring;
767             $criteria = self::print_badge_criteria($b, 'short');
769             if (has_capability('moodle/badges:viewawarded', $this->page->context)) {
770                 $awards = html_writer::link(new moodle_url('/badges/recipients.php', array('id' => $b->id)), $b->awards);
771             } else {
772                 $awards = $b->awards;
773             }
775             $actions = self::print_badge_table_actions($b, $this->page->context);
777             $row = array($name, $status, $criteria, $awards, $actions);
778             $table->data[] = $row;
779         }
780         $htmltable = html_writer::table($table);
782         return $htmlnew . $htmlpagingbar . $htmltable . $htmlpagingbar;
783     }
785     /**
786      * Prints tabs for badge editing.
787      *
788      * @param integer $badgeid The badgeid to edit.
789      * @param context $context The current context.
790      * @param string $current The currently selected tab.
791      * @return string
792      */
793     public function print_badge_tabs($badgeid, $context, $current = 'overview') {
794         global $DB;
796         $badge = new badge($badgeid);
797         $row = array();
799         $row[] = new tabobject('overview',
800                     new moodle_url('/badges/overview.php', array('id' => $badgeid)),
801                     get_string('boverview', 'badges')
802                 );
804         if (has_capability('moodle/badges:configuredetails', $context)) {
805             $row[] = new tabobject('details',
806                         new moodle_url('/badges/edit.php', array('id' => $badgeid, 'action' => 'badge')),
807                         get_string('bdetails', 'badges')
808                     );
809         }
811         if (has_capability('moodle/badges:configurecriteria', $context)) {
812             $row[] = new tabobject('criteria',
813                         new moodle_url('/badges/criteria.php', array('id' => $badgeid)),
814                         get_string('bcriteria', 'badges')
815                     );
816         }
818         if (has_capability('moodle/badges:configuremessages', $context)) {
819             $row[] = new tabobject('message',
820                         new moodle_url('/badges/edit.php', array('id' => $badgeid, 'action' => 'message')),
821                         get_string('bmessage', 'badges')
822                     );
823         }
825         if (has_capability('moodle/badges:viewawarded', $context)) {
826             $awarded = $DB->count_records_sql('SELECT COUNT(b.userid)
827                                                FROM {badge_issued} b INNER JOIN {user} u ON b.userid = u.id
828                                                WHERE b.badgeid = :badgeid AND u.deleted = 0', array('badgeid' => $badgeid));
829             $row[] = new tabobject('awards',
830                         new moodle_url('/badges/recipients.php', array('id' => $badgeid)),
831                         get_string('bawards', 'badges', $awarded)
832                     );
833         }
835         if (has_capability('moodle/badges:configuredetails', $context)) {
836             $row[] = new tabobject('bendorsement',
837                 new moodle_url('/badges/endorsement.php', array('id' => $badgeid)),
838                 get_string('bendorsement', 'badges')
839             );
840         }
842         if (has_capability('moodle/badges:configuredetails', $context)) {
843             $sql = "SELECT COUNT(br.badgeid)
844                       FROM {badge_related} br
845                      WHERE (br.badgeid = :badgeid OR br.relatedbadgeid = :badgeid2)";
846             $related = $DB->count_records_sql($sql, ['badgeid' => $badgeid, 'badgeid2' => $badgeid]);
847             $row[] = new tabobject('brelated',
848                 new moodle_url('/badges/related.php', array('id' => $badgeid)),
849                 get_string('brelated', 'badges', $related)
850             );
851         }
853         if (has_capability('moodle/badges:configuredetails', $context)) {
854             $alignments = $DB->count_records_sql("SELECT COUNT(bc.id)
855                       FROM {badge_alignment} bc WHERE bc.badgeid = :badgeid", array('badgeid' => $badgeid));
856             $row[] = new tabobject('balignment',
857                 new moodle_url('/badges/alignment.php', array('id' => $badgeid)),
858                 get_string('balignment', 'badges', $alignments)
859             );
860         }
862         echo $this->tabtree($row, $current);
863     }
865     /**
866      * Prints badge status box.
867      *
868      * @param badge $badge
869      * @return Either the status box html as a string or null
870      */
871     public function print_badge_status_box(badge $badge) {
872         if (has_capability('moodle/badges:configurecriteria', $badge->get_context())) {
874             if (!$badge->has_criteria()) {
875                 $criteriaurl = new moodle_url('/badges/criteria.php', array('id' => $badge->id));
876                 $status = get_string('nocriteria', 'badges');
877                 if ($this->page->url != $criteriaurl) {
878                     $action = $this->output->single_button(
879                         $criteriaurl,
880                         get_string('addcriteria', 'badges'), 'POST', array('class' => 'activatebadge'));
881                 } else {
882                     $action = '';
883                 }
885                 $message = $status . $action;
886             } else {
887                 $status = get_string('statusmessage_' . $badge->status, 'badges');
888                 if ($badge->is_active()) {
889                     $action = $this->output->single_button(new moodle_url('/badges/action.php',
890                                 array('id' => $badge->id, 'lock' => 1, 'sesskey' => sesskey(),
891                                       'return' => $this->page->url->out_as_local_url(false))),
892                             get_string('deactivate', 'badges'), 'POST', array('class' => 'activatebadge'));
893                 } else {
894                     $action = $this->output->single_button(new moodle_url('/badges/action.php',
895                                 array('id' => $badge->id, 'activate' => 1, 'sesskey' => sesskey(),
896                                       'return' => $this->page->url->out_as_local_url(false))),
897                             get_string('activate', 'badges'), 'POST', array('class' => 'activatebadge'));
898                 }
900                 $message = $status . $this->output->help_icon('status', 'badges') . $action;
902             }
904             $style = $badge->is_active() ? 'generalbox statusbox active' : 'generalbox statusbox inactive';
905             return $this->output->box($message, $style);
906         }
908         return null;
909     }
911     /**
912      * Returns information about badge criteria in a list form.
913      *
914      * @param badge $badge Badge objects
915      * @param string $short Indicates whether to print full info about this badge
916      * @return string $output HTML string to output
917      */
918     public function print_badge_criteria(badge $badge, $short = '') {
919         $agg = $badge->get_aggregation_methods();
920         if (empty($badge->criteria)) {
921             return get_string('nocriteria', 'badges');
922         }
924         $overalldescr = '';
925         $overall = $badge->criteria[BADGE_CRITERIA_TYPE_OVERALL];
926         if (!$short && !empty($overall->description)) {
927             $overalldescr = $this->output->box(
928                 format_text($overall->description, $overall->descriptionformat, array('context' => $badge->get_context())),
929                 'criteria-description'
930                 );
931         }
933         // Get the condition string.
934         if (count($badge->criteria) == 2) {
935             $condition = '';
936             if (!$short) {
937                 $condition = get_string('criteria_descr', 'badges');
938             }
939         } else {
940             $condition = get_string('criteria_descr_' . $short . BADGE_CRITERIA_TYPE_OVERALL, 'badges',
941                                       core_text::strtoupper($agg[$badge->get_aggregation_method()]));
942         }
944         unset($badge->criteria[BADGE_CRITERIA_TYPE_OVERALL]);
946         $items = array();
947         // If only one criterion left, make sure its description goe to the top.
948         if (count($badge->criteria) == 1) {
949             $c = reset($badge->criteria);
950             if (!$short && !empty($c->description)) {
951                 $overalldescr = $this->output->box(
952                     format_text($c->description, $c->descriptionformat, array('context' => $badge->get_context())),
953                     'criteria-description'
954                     );
955             }
956             if (count($c->params) == 1) {
957                 $items[] = get_string('criteria_descr_single_' . $short . $c->criteriatype , 'badges') .
958                            $c->get_details($short);
959             } else {
960                 $items[] = get_string('criteria_descr_' . $short . $c->criteriatype, 'badges',
961                         core_text::strtoupper($agg[$badge->get_aggregation_method($c->criteriatype)])) .
962                         $c->get_details($short);
963             }
964         } else {
965             foreach ($badge->criteria as $type => $c) {
966                 $criteriadescr = '';
967                 if (!$short && !empty($c->description)) {
968                     $criteriadescr = $this->output->box(
969                         format_text($c->description, $c->descriptionformat, array('context' => $badge->get_context())),
970                         'criteria-description'
971                         );
972                 }
973                 if (count($c->params) == 1) {
974                     $items[] = get_string('criteria_descr_single_' . $short . $type , 'badges') .
975                                $c->get_details($short) . $criteriadescr;
976                 } else {
977                     $items[] = get_string('criteria_descr_' . $short . $type , 'badges',
978                             core_text::strtoupper($agg[$badge->get_aggregation_method($type)])) .
979                             $c->get_details($short) .
980                             $criteriadescr;
981                 }
982             }
983         }
985         return $overalldescr . $condition . html_writer::alist($items, array(), 'ul');;
986     }
988     /**
989      * Prints criteria actions for badge editing.
990      *
991      * @param badge $badge
992      * @return string
993      */
994     public function print_criteria_actions(badge $badge) {
995         $output = '';
996         if (!$badge->is_active() && !$badge->is_locked()) {
997             $accepted = $badge->get_accepted_criteria();
998             $potential = array_diff($accepted, array_keys($badge->criteria));
1000             if (!empty($potential)) {
1001                 foreach ($potential as $p) {
1002                     if ($p != 0) {
1003                         $select[$p] = get_string('criteria_' . $p, 'badges');
1004                     }
1005                 }
1006                 $output .= $this->output->single_select(
1007                     new moodle_url('/badges/criteria_settings.php', array('badgeid' => $badge->id, 'add' => true)),
1008                     'type',
1009                     $select,
1010                     '',
1011                     array('' => 'choosedots'),
1012                     null,
1013                     array('label' => get_string('addbadgecriteria', 'badges'))
1014                 );
1015             } else {
1016                 $output .= $this->output->box(get_string('nothingtoadd', 'badges'), 'clearfix');
1017             }
1018         }
1020         return $output;
1021     }
1023     /**
1024      * Renders a table with users who have earned the badge.
1025      * Based on stamps collection plugin.
1026      *
1027      * @param \core_badges\output\badge_recipients $recipients
1028      * @return string
1029      */
1030     protected function render_badge_recipients(\core_badges\output\badge_recipients $recipients) {
1031         $paging = new paging_bar($recipients->totalcount, $recipients->page, $recipients->perpage, $this->page->url, 'page');
1032         $htmlpagingbar = $this->render($paging);
1033         $table = new html_table();
1034         $table->attributes['class'] = 'generaltable boxaligncenter boxwidthwide';
1036         $sortbyfirstname = $this->helper_sortable_heading(get_string('firstname'),
1037                 'firstname', $recipients->sort, $recipients->dir);
1038         $sortbylastname = $this->helper_sortable_heading(get_string('lastname'),
1039                 'lastname', $recipients->sort, $recipients->dir);
1040         if ($this->helper_fullname_format() == 'lf') {
1041             $sortbyname = $sortbylastname . ' / ' . $sortbyfirstname;
1042         } else {
1043             $sortbyname = $sortbyfirstname . ' / ' . $sortbylastname;
1044         }
1046         $sortbydate = $this->helper_sortable_heading(get_string('dateawarded', 'badges'),
1047                 'dateissued', $recipients->sort, $recipients->dir);
1049         $table->head = array($sortbyname, $sortbydate, '');
1051         foreach ($recipients->userids as $holder) {
1052             $fullname = fullname($holder);
1053             $fullname = html_writer::link(
1054                             new moodle_url('/user/profile.php', array('id' => $holder->userid)),
1055                             $fullname
1056                         );
1057             $awarded  = userdate($holder->dateissued);
1058             $badgeurl = html_writer::link(
1059                             new moodle_url('/badges/badge.php', array('hash' => $holder->uniquehash)),
1060                             get_string('viewbadge', 'badges')
1061                         );
1063             $row = array($fullname, $awarded, $badgeurl);
1064             $table->data[] = $row;
1065         }
1067         $htmltable = html_writer::table($table);
1069         return $htmlpagingbar . $htmltable . $htmlpagingbar;
1070     }
1072     ////////////////////////////////////////////////////////////////////////////
1073     // Helper methods
1074     // Reused from stamps collection plugin
1075     ////////////////////////////////////////////////////////////////////////////
1077     /**
1078      * Renders a text with icons to sort by the given column
1079      *
1080      * This is intended for table headings.
1081      *
1082      * @param string $text    The heading text
1083      * @param string $sortid  The column id used for sorting
1084      * @param string $sortby  Currently sorted by (column id)
1085      * @param string $sorthow Currently sorted how (ASC|DESC)
1086      *
1087      * @return string
1088      */
1089     protected function helper_sortable_heading($text, $sortid = null, $sortby = null, $sorthow = null) {
1090         $out = html_writer::tag('span', $text, array('class' => 'text'));
1092         if (!is_null($sortid)) {
1093             if ($sortby !== $sortid || $sorthow !== 'ASC') {
1094                 $url = new moodle_url($this->page->url);
1095                 $url->params(array('sort' => $sortid, 'dir' => 'ASC'));
1096                 $out .= $this->output->action_icon($url,
1097                         new pix_icon('t/sort_asc', get_string('sortbyx', 'core', s($text)), null, array('class' => 'iconsort')));
1098             }
1099             if ($sortby !== $sortid || $sorthow !== 'DESC') {
1100                 $url = new moodle_url($this->page->url);
1101                 $url->params(array('sort' => $sortid, 'dir' => 'DESC'));
1102                 $out .= $this->output->action_icon($url,
1103                         new pix_icon('t/sort_desc', get_string('sortbyxreverse', 'core', s($text)), null, array('class' => 'iconsort')));
1104             }
1105         }
1106         return $out;
1107     }
1108     /**
1109      * Tries to guess the fullname format set at the site
1110      *
1111      * @return string fl|lf
1112      */
1113     protected function helper_fullname_format() {
1114         $fake = new stdClass();
1115         $fake->lastname = 'LLLL';
1116         $fake->firstname = 'FFFF';
1117         $fullname = get_string('fullnamedisplay', '', $fake);
1118         if (strpos($fullname, 'LLLL') < strpos($fullname, 'FFFF')) {
1119             return 'lf';
1120         } else {
1121             return 'fl';
1122         }
1123     }
1124     /**
1125      * Renders a search form
1126      *
1127      * @param string $search Search string
1128      * @return string HTML
1129      */
1130     protected function helper_search_form($search) {
1131         global $CFG;
1132         require_once($CFG->libdir . '/formslib.php');
1134         $mform = new MoodleQuickForm('searchform', 'POST', $this->page->url);
1136         $mform->addElement('hidden', 'sesskey', sesskey());
1138         $el[] = $mform->createElement('text', 'search', get_string('search'), array('size' => 20));
1139         $mform->setDefault('search', $search);
1140         $el[] = $mform->createElement('submit', 'submitsearch', get_string('search'));
1141         $el[] = $mform->createElement('submit', 'clearsearch', get_string('clear'));
1142         $mform->addGroup($el, 'searchgroup', get_string('searchname', 'badges'), ' ', false);
1144         ob_start();
1145         $mform->display();
1146         $out = ob_get_clean();
1148         return $out;
1149     }
1151     /**
1152      * Renders a definition list
1153      *
1154      * @param array $items the list of items to define
1155      * @param array
1156      */
1157     protected function definition_list(array $items, array $attributes = array()) {
1158         $output = html_writer::start_tag('dl', $attributes);
1159         foreach ($items as $label => $value) {
1160             $output .= html_writer::tag('dt', $label);
1161             $output .= html_writer::tag('dd', $value);
1162         }
1163         $output .= html_writer::end_tag('dl');
1164         return $output;
1165     }
1167     /**
1168      * Outputs list en badges.
1169      *
1170      * @param badge $badge Badge object.
1171      * @return string $output content endorsement to output.
1172      */
1173     protected function print_badge_endorsement(badge $badge) {
1174         $output = '';
1175         $endorsement = $badge->get_endorsement();
1176         $dl = array();
1177         $output .= $this->heading(get_string('endorsement', 'badges'), 3);
1178         if (!empty($endorsement)) {
1179             $dl[get_string('issuername', 'badges')] = $endorsement->issuername;
1180             $dl[get_string('issueremail', 'badges')] =
1181                 html_writer::tag('a', $endorsement->issueremail, array('href' => 'mailto:' . $endorsement->issueremail));
1182             $dl[get_string('issuerurl', 'badges')] = html_writer::link($endorsement->issuerurl, $endorsement->issuerurl,
1183                 array('target' => '_blank'));
1184             $dl[get_string('dateawarded', 'badges')] = userdate($endorsement->dateissued);
1185             $dl[get_string('claimid', 'badges')] = html_writer::link($endorsement->claimid, $endorsement->claimid,
1186             array('target' => '_blank'));
1187             $dl[get_string('claimcomment', 'badges')] = $endorsement->claimcomment;
1188             $output .= $this->definition_list($dl);
1189         } else {
1190             $output .= get_string('noendorsement', 'badges');
1191         }
1192         return $output;
1193     }
1195     /**
1196      * Print list badges related.
1197      *
1198      * @param badge $badge Badge objects.
1199      * @return string $output List related badges to output.
1200      */
1201     protected function print_badge_related(badge $badge) {
1202         $output = '';
1203         $relatedbadges = $badge->get_related_badges();
1204         $output .= $this->heading(get_string('relatedbages', 'badges'), 3);
1205         if (!empty($relatedbadges)) {
1206             $items = array();
1207             foreach ($relatedbadges as $related) {
1208                 $relatedurl = new moodle_url('/badges/overview.php', array('id' => $related->id));
1209                 $items[] = html_writer::link($relatedurl->out(), $related->name, array('target' => '_blank'));
1210             }
1211             $output .= html_writer::alist($items, array(), 'ul');
1212         } else {
1213             $output .= get_string('norelated', 'badges');
1214         }
1215         return $output;
1216     }
1218     /**
1219      * Print list badge alignments.
1220      *
1221      * @param badge $badge Badge objects.
1222      * @return string $output List alignments to output.
1223      */
1224     protected function print_badge_alignments(badge $badge) {
1225         $output = '';
1226         $output .= $this->heading(get_string('alignment', 'badges'), 3);
1227         $alignments = $badge->get_alignments();
1228         if (!empty($alignments)) {
1229             $items = array();
1230             foreach ($alignments as $alignment) {
1231                 $urlaligment = new moodle_url('alignment.php',
1232                     array('id' => $badge->id, 'alignmentid' => $alignment->id)
1233                 );
1234                 $items[] = html_writer::link($urlaligment, $alignment->targetname, array('target' => '_blank'));
1235             }
1236             $output .= html_writer::alist($items, array(), 'ul');
1237         } else {
1238             $output .= get_string('noalignment', 'badges');
1239         }
1240         return $output;
1241     }
1243     /**
1244      * Renders a table for related badges.
1245      *
1246      * @param \core_badges\output\badge_related $related list related badges.
1247      * @return string list related badges to output.
1248      */
1249     protected function render_badge_related(\core_badges\output\badge_related $related) {
1250         $currentbadge = new badge($related->currentbadgeid);
1251         $languages = get_string_manager()->get_list_of_languages();
1252         $paging = new paging_bar($related->totalcount, $related->page, $related->perpage, $this->page->url, 'page');
1253         $htmlpagingbar = $this->render($paging);
1254         $table = new html_table();
1255         $table->attributes['class'] = 'generaltable boxaligncenter boxwidthwide';
1256         $table->head = array(
1257             get_string('name'),
1258             get_string('version', 'badges'),
1259             get_string('language', 'badges'),
1260             get_string('type', 'badges')
1261         );
1262         if (!$currentbadge->is_active() && !$currentbadge->is_locked()) {
1263             array_push($table->head, '');
1264         }
1266         foreach ($related->badges as $badge) {
1267             $badgeobject = new badge($badge->id);
1268             $style = array('title' => $badgeobject->name);
1269             if (!$badgeobject->is_active()) {
1270                 $style['class'] = 'dimmed';
1271             }
1272             $context = ($badgeobject->type == BADGE_TYPE_SITE) ?
1273                 context_system::instance() : context_course::instance($badgeobject->courseid);
1274             $forlink = print_badge_image($badgeobject, $context) . ' ' .
1275                 html_writer::start_tag('span') . $badgeobject->name . html_writer::end_tag('span');
1276             $name = html_writer::link(new moodle_url('/badges/overview.php', array('id' => $badgeobject->id)), $forlink, $style);
1278             $row = array(
1279                 $name,
1280                 $badge->version,
1281                 $badge->language ? $languages[$badge->language] : '',
1282                 $badge->type == BADGE_TYPE_COURSE ? get_string('badgesview', 'badges') : get_string('sitebadges', 'badges')
1283             );
1284             if (!$currentbadge->is_active() && !$currentbadge->is_locked()) {
1285                 $action = $this->output->action_icon(
1286                     new moodle_url('related_action.php',
1287                         array(
1288                             'badgeid' => $related->currentbadgeid,
1289                             'relatedid' => $badge->id,
1290                             'action' => 'remove'
1291                         )
1292                     ), new pix_icon('t/delete', get_string('delete')));
1293                 $actions = html_writer::tag('div', $action, array('class' => 'badge-actions'));
1294                 array_push($row, $actions);
1295             }
1296             $table->data[] = $row;
1297         }
1298         $htmltable = html_writer::table($table);
1300         return $htmlpagingbar . $htmltable . $htmlpagingbar;
1301     }
1303     /**
1304      * Renders a table with alignment.
1305      *
1306      * @param core_badges\output\badge_alignments $alignments List alignments.
1307      * @return string List alignment to output.
1308      */
1309     protected function render_badge_alignments(\core_badges\output\badge_alignments $alignments) {
1310         $currentbadge = new badge($alignments->currentbadgeid);
1311         $paging = new paging_bar($alignments->totalcount, $alignments->page, $alignments->perpage, $this->page->url, 'page');
1312         $htmlpagingbar = $this->render($paging);
1313         $table = new html_table();
1314         $table->attributes['class'] = 'generaltable boxaligncenter boxwidthwide';
1315         $table->head = array('Name', 'URL', '');
1317         foreach ($alignments->alignments as $item) {
1318             $urlaligment = new moodle_url('alignment.php',
1319                 array(
1320                     'id' => $currentbadge->id,
1321                     'alignmentid' => $item->id,
1322                 )
1323             );
1324             $row = array(
1325                 html_writer::link($urlaligment, $item->targetname),
1326                 html_writer::link($item->targeturl, $item->targeturl, array('target' => '_blank'))
1327             );
1328             if (!$currentbadge->is_active() && !$currentbadge->is_locked()) {
1329                 $delete = $this->output->action_icon(
1330                     new moodle_url('alignment_action.php',
1331                         array(
1332                             'id' => $currentbadge->id,
1333                             'alignmentid' => $item->id,
1334                             'action' => 'remove'
1335                         )
1336                     ), new pix_icon('t/delete', get_string('delete')));
1337                 $edit = $this->output->action_icon(
1338                     new moodle_url('alignment.php',
1339                         array(
1340                             'id' => $currentbadge->id,
1341                             'alignmentid' => $item->id,
1342                             'action' => 'edit'
1343                         )
1344                     ), new pix_icon('t/edit', get_string('edit')));
1345                 $actions = html_writer::tag('div', $edit . $delete, array('class' => 'badge-actions'));
1346                 array_push($row, $actions);
1347             }
1348             $table->data[] = $row;
1349         }
1350         $htmltable = html_writer::table($table);
1352         return $htmlpagingbar . $htmltable . $htmlpagingbar;
1353     }
1355     /**
1356      * Defer to template.
1357      *
1358      * @param \core_badges\output\external_backpacks_page $page
1359      * @return bool|string
1360      */
1361     public function render_external_backpacks_page(\core_badges\output\external_backpacks_page $page) {
1362         $data = $page->export_for_template($this);
1363         return parent::render_from_template('core_badges/external_backpacks_page', $data);
1364     }