Compare commits
60 commits
main
...
MOODLE_36_
Author | SHA1 | Date | |
---|---|---|---|
|
be34b27ff9 | ||
|
2253884856 | ||
|
e5059a63f4 | ||
|
13a1012ffb | ||
|
24ac8add66 | ||
|
98a2c53463 | ||
|
69817ce07a | ||
|
b56c13b67b | ||
|
90241238fb | ||
|
5034faa2e4 | ||
|
0f6282a1b1 | ||
|
7e9de4aada | ||
|
42d3b3a50e | ||
|
c9b83759bc | ||
|
f1a55ce6db | ||
|
d0e75bb6fc | ||
|
2b210b4bb8 | ||
|
4765c11a46 | ||
|
03d56eddae | ||
|
d37bfab4cd | ||
|
d8f275d588 | ||
|
616bc4f43b | ||
|
b3433e598c | ||
|
05ba53ad3a | ||
|
545ed8bbbd | ||
|
2697ba9fb5 | ||
|
4447e2ac6f | ||
|
4a85da7297 | ||
|
112a027849 | ||
|
feb3bac856 | ||
|
88d0449d62 | ||
|
ba0bfd3a7e | ||
|
8d3d78307f | ||
|
6ba2efa3b0 | ||
|
a7d372a26a | ||
|
14e480f7e9 | ||
|
a379c93dd7 | ||
|
185389b983 | ||
|
3dc83cb306 | ||
|
a2c30e3667 | ||
|
ad7d4099b4 | ||
|
1c9f4786fb | ||
|
2f8bb1eb29 | ||
|
01bfe2f660 | ||
|
28a8b99f31 | ||
|
9810b48b25 | ||
|
28b2210b19 | ||
|
62639d1754 | ||
|
e7352bf715 | ||
|
b28877f5ee | ||
|
bc2fe29354 | ||
|
74f1cd732d | ||
|
9d97d7e6fb | ||
|
bd91807fe2 | ||
|
88ef8f25fa | ||
|
c420d3b943 | ||
|
5a6993009b | ||
|
08b10ebdad | ||
|
1511c079ab | ||
|
a26d58bf33 |
39 changed files with 732 additions and 199 deletions
|
@ -2,6 +2,7 @@ language: php
|
|||
|
||||
# For javascript behat tests we need sudo
|
||||
sudo: true
|
||||
dist: trusty
|
||||
|
||||
cache:
|
||||
directories:
|
||||
|
@ -32,7 +33,7 @@ before_install:
|
|||
- nvm install 8.9
|
||||
- nvm use 8.9
|
||||
- cd ../..
|
||||
- composer create-project -n --no-dev --prefer-dist blackboard-open-source/moodle-plugin-ci ci ^2
|
||||
- composer create-project -n --no-dev --prefer-dist moodlehq/moodle-plugin-ci ci ^3
|
||||
- export PATH="$(cd ci/bin; pwd):$(cd ci/vendor/bin; pwd):$PATH"
|
||||
|
||||
install:
|
||||
|
|
80
CHANGES.md
80
CHANGES.md
|
@ -2,7 +2,85 @@
|
|||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
Note - All hash comments refer to the issue number. Eg. #169 refers to https://github.com/markn86/moodle-mod_customcert/issues/169.
|
||||
Note - All hash comments refer to the issue number. Eg. #169 refers to https://github.com/mdjnelson/moodle-mod_customcert/issues/169.
|
||||
|
||||
## [3.6.7] - 2020-11-26
|
||||
|
||||
### Added
|
||||
|
||||
- Added ability to select outcomes in the Grade element (#329).
|
||||
- The Grade Item Name element now works with all grade items, whereas before it was just activities (#346).
|
||||
- Added enrolment start and end dates to the date element (#328).
|
||||
- Added username to userfield form element (#390).
|
||||
|
||||
### Changed
|
||||
|
||||
- Removed unnecessary and confusing 'exampledata' string.
|
||||
- Do not email those who can manage the certificate (#376).
|
||||
- Do not force the PDF to be downloaded, instead send the file inline to the browser (#153).
|
||||
- Updated the 'emailstudents_help', 'emailteachers_help' and 'emailothers_help' strings to warn users about prematurely emailing the certificate (#276).
|
||||
- Do not email out certificates that contain no elements (#276).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Certificates now get marked as viewed via the mobile app (#342).
|
||||
- Fix repositioning elements page when resizing the browser (#343).
|
||||
- Prevent error when duplicate issues exist when using the code element (#363).
|
||||
- Implemented get_objectid_mapping for the course_module_viewed.php event to avoid warning (#374).
|
||||
- Fixed exception being thrown when loading a template that has an image element but no image selected (#369).
|
||||
- Fixed issue with PDF being generated without a name (#333).
|
||||
|
||||
## [3.6.6] - 2020-03-12
|
||||
|
||||
### Added
|
||||
|
||||
- Added extra Behat steps for new elements (#309).
|
||||
|
||||
### Changed
|
||||
|
||||
- When copying a site template the site images are also copied to the course context and then those copied images are used.
|
||||
Before, the elements would simply point to the site images. However, this meant when performing a backup/restore the
|
||||
images were not stored in the backup file (#298).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed the displaying of names of a custom user field (#326).
|
||||
- Do not allow '0' as a value for width or height in QR code (#321).
|
||||
|
||||
## [3.6.5] - 2020-03-09
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed foreign key violation (#331).
|
||||
|
||||
## [3.6.4] - 2020-02-01
|
||||
|
||||
### Added
|
||||
|
||||
- Re-added 'code' column to user report (#264).
|
||||
- Add 'userfullname' variable for email subject (#316).
|
||||
|
||||
### Fixed
|
||||
|
||||
- Do not fail if multiple certificate issues (#304) and (#295).
|
||||
|
||||
## [3.6.3] - 2019-06-17
|
||||
|
||||
### Added
|
||||
|
||||
- Added ability to specify the current date for date related elements (#289).
|
||||
|
||||
### Changed
|
||||
|
||||
- String improvements for the 'Date range' element.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Use negative numbers for constants in the 'Date range' element. The reason being that we may have a module
|
||||
that has an id matching one of these positive values. Sites which are using the 'Date range' element (sites
|
||||
which are **not** using this element do **not** have to do anything) will need to re-edit each element, select
|
||||
the date item again and save. An upgrade step was not created because it is impossible to tell if the site does
|
||||
actually want the constant or if they actually want the date for the module.
|
||||
|
||||
## [3.6.2] - 2019-05-28
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ This requires Git being installed. If you do not have Git installed, please visi
|
|||
Once you have Git installed, simply visit your Moodle mod directory and clone the repository using the following command.
|
||||
|
||||
```
|
||||
git clone https://github.com/markn86/moodle-mod_customcert.git customcert
|
||||
git clone https://github.com/mdjnelson/moodle-mod_customcert.git customcert
|
||||
```
|
||||
|
||||
Then checkout the branch corresponding to the version of Moodle you are using with the following command. Make sure to replace MOODLE_32_STABLE with the version of Moodle you are using.
|
||||
|
|
|
@ -47,18 +47,18 @@ class element_factory {
|
|||
$classname = '\\customcertelement_' . $element->element . '\\element';
|
||||
|
||||
$data = new \stdClass();
|
||||
$data->id = isset($element->id) ? $element->id : null;
|
||||
$data->pageid = isset($element->pageid) ? $element->pageid : null;
|
||||
$data->name = isset($element->name) ? $element->name : get_string('pluginname', 'customcertelement_' . $element->element);
|
||||
$data->id = $element->id ?? null;
|
||||
$data->pageid = $element->pageid ?? null;
|
||||
$data->name = $element->name ?? get_string('pluginname', 'customcertelement_' . $element->element);
|
||||
$data->element = $element->element;
|
||||
$data->data = isset($element->data) ? $element->data : null;
|
||||
$data->font = isset($element->font) ? $element->font : null;
|
||||
$data->fontsize = isset($element->fontsize) ? $element->fontsize : null;
|
||||
$data->colour = isset($element->colour) ? $element->colour : null;
|
||||
$data->posx = isset($element->posx) ? $element->posx : null;
|
||||
$data->posy = isset($element->posy) ? $element->posy : null;
|
||||
$data->width = isset($element->width) ? $element->width : null;
|
||||
$data->refpoint = isset($element->refpoint) ? $element->refpoint : null;
|
||||
$data->data = $element->data ?? null;
|
||||
$data->font = $element->font ?? null;
|
||||
$data->fontsize = $element->fontsize ?? null;
|
||||
$data->colour = $element->colour ?? null;
|
||||
$data->posx = $element->posx ?? null;
|
||||
$data->posy = $element->posy ?? null;
|
||||
$data->width = $element->width ?? null;
|
||||
$data->refpoint = $element->refpoint ?? null;
|
||||
|
||||
// Ensure the necessary class exists.
|
||||
if (class_exists($classname)) {
|
||||
|
|
|
@ -462,70 +462,40 @@ class element_helper {
|
|||
* @return array the array of gradeable items in the course
|
||||
*/
|
||||
public static function get_grade_items($course) {
|
||||
global $DB;
|
||||
|
||||
// Array to store the grade items.
|
||||
$modules = array();
|
||||
|
||||
// Collect course modules data.
|
||||
$modinfo = get_fast_modinfo($course);
|
||||
$mods = $modinfo->get_cms();
|
||||
$sections = $modinfo->get_section_info_all();
|
||||
|
||||
// Create the section label depending on course format.
|
||||
$sectionlabel = get_string('section');
|
||||
if ($course->format == 'topics') {
|
||||
$sectionlabel = get_string('topic');
|
||||
} else if ($course->format == 'weeks') {
|
||||
$sectionlabel = get_string('week');
|
||||
}
|
||||
|
||||
// Loop through each course section.
|
||||
for ($i = 0; $i <= count($sections) - 1; $i++) {
|
||||
// Confirm the index exists, should always be true.
|
||||
if (isset($sections[$i])) {
|
||||
// Get the individual section.
|
||||
$section = $sections[$i];
|
||||
// Get the mods for this section.
|
||||
$sectionmods = explode(",", $section->sequence);
|
||||
// Loop through the section mods.
|
||||
foreach ($sectionmods as $sectionmod) {
|
||||
// Should never happen unless DB is borked.
|
||||
if (empty($mods[$sectionmod])) {
|
||||
continue;
|
||||
}
|
||||
$mod = $mods[$sectionmod];
|
||||
$instance = $DB->get_record($mod->modname, array('id' => $mod->instance));
|
||||
// Get the grade items for this activity.
|
||||
if ($gradeitems = grade_get_grade_items_for_activity($mod)) {
|
||||
$moditem = grade_get_grades($course->id, 'mod', $mod->modname, $mod->instance);
|
||||
$gradeitem = reset($moditem->items);
|
||||
if (isset($gradeitem->grademax)) {
|
||||
$modules[$mod->id] = $sectionlabel . ' ' . $section->section . ' : ' . $instance->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$arrgradeitems = array();
|
||||
|
||||
// Get other non-module related grade items.
|
||||
if ($gradeitems = \grade_item::fetch_all(['courseid' => $course->id])) {
|
||||
$arrgradeitems = [];
|
||||
foreach ($gradeitems as $gi) {
|
||||
// Skip the course and mod items since we already have them.
|
||||
if ($gi->itemtype == 'mod' || $gi->itemtype == 'course') {
|
||||
continue;
|
||||
if ($gi->is_course_item()) {
|
||||
continue; // Skipping for legacy reasons - this was added to individual elements.
|
||||
}
|
||||
|
||||
if ($gi->is_external_item()) {
|
||||
$cm = get_coursemodule_from_instance($gi->itemmodule, $gi->iteminstance, $course->id);
|
||||
$modcontext = \context_module::instance($cm->id);
|
||||
$modname = format_string($cm->name, true, array('context' => $modcontext));
|
||||
}
|
||||
|
||||
if ($gi->is_external_item() && !$gi->is_outcome_item()) {
|
||||
// Due to legacy reasons we are storing the course module ID here rather than the grade item id.
|
||||
// If we were to change we would need to provide upgrade steps to convert cm->id to gi->id.
|
||||
$arrgradeitems[$cm->id] = get_string('activity', 'mod_customcert') . ' : ' . $gi->get_name();
|
||||
} else if ($gi->is_external_item() && $gi->is_outcome_item()) {
|
||||
// Get the name of the activity.
|
||||
$optionname = get_string('gradeoutcome', 'mod_customcert') . ' : ' . $modname . " - " . $gi->get_name();
|
||||
$arrgradeitems['gradeitem:' . $gi->id] = $optionname;
|
||||
} else {
|
||||
$arrgradeitems['gradeitem:' . $gi->id] = get_string('gradeitem', 'grades') . ' : ' . $gi->get_name(true);
|
||||
}
|
||||
$arrgradeitems['gradeitem:' . $gi->id] = get_string('gradeitem', 'grades') . ' : ' . $gi->get_name(true);
|
||||
}
|
||||
|
||||
// Alphabetise this.
|
||||
asort($arrgradeitems);
|
||||
|
||||
// Merge results.
|
||||
$modules = $modules + $arrgradeitems;
|
||||
}
|
||||
|
||||
return $modules;
|
||||
return $arrgradeitems;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -42,4 +42,13 @@ class course_module_viewed extends \core\event\course_module_viewed {
|
|||
$this->data['objecttable'] = 'customcert';
|
||||
parent::init();
|
||||
}
|
||||
|
||||
public static function get_objectid_mapping() {
|
||||
return array('db' => 'customcert', 'restore' => 'customcert');
|
||||
}
|
||||
|
||||
public static function get_other_mapping() {
|
||||
// No need to map.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,6 +74,7 @@ class report_table extends \table_sql {
|
|||
$columns[] = $extrafield;
|
||||
}
|
||||
$columns[] = 'timecreated';
|
||||
$columns[] = 'code';
|
||||
|
||||
$headers = [];
|
||||
$headers[] = get_string('fullname');
|
||||
|
@ -81,6 +82,7 @@ class report_table extends \table_sql {
|
|||
$headers[] = get_user_field_name($extrafield);
|
||||
}
|
||||
$headers[] = get_string('receiveddate', 'customcert');
|
||||
$headers[] = get_string('code', 'customcert');
|
||||
|
||||
// Check if we were passed a filename, which means we want to download it.
|
||||
if ($download) {
|
||||
|
@ -101,6 +103,7 @@ class report_table extends \table_sql {
|
|||
$this->define_headers($headers);
|
||||
$this->collapsible(false);
|
||||
$this->sortable(true);
|
||||
$this->no_sorting('code');
|
||||
$this->no_sorting('download');
|
||||
$this->is_downloadable(true);
|
||||
|
||||
|
@ -135,6 +138,16 @@ class report_table extends \table_sql {
|
|||
return userdate($user->timecreated);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the code column.
|
||||
*
|
||||
* @param \stdClass $user
|
||||
* @return string
|
||||
*/
|
||||
public function col_code($user) {
|
||||
return $user->code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the download column.
|
||||
*
|
||||
|
|
|
@ -69,6 +69,18 @@ class email_certificate_task extends \core\task\scheduled_task {
|
|||
$htmlrenderer = $PAGE->get_renderer('mod_customcert', 'email', 'htmlemail');
|
||||
$textrenderer = $PAGE->get_renderer('mod_customcert', 'email', 'textemail');
|
||||
foreach ($customcerts as $customcert) {
|
||||
// Do not process an empty certificate.
|
||||
$sql = "SELECT ce.*
|
||||
FROM {customcert_elements} ce
|
||||
JOIN {customcert_pages} cp
|
||||
ON cp.id = ce.pageid
|
||||
JOIN {customcert_templates} ct
|
||||
ON ct.id = cp.templateid
|
||||
WHERE ct.contextid = :contextid";
|
||||
if (!$DB->record_exists_sql($sql, ['contextid' => $customcert->contextid])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the context.
|
||||
$context = \context::instance_by_id($customcert->contextid);
|
||||
|
||||
|
@ -112,6 +124,11 @@ class email_certificate_task extends \core\task\scheduled_task {
|
|||
continue;
|
||||
}
|
||||
|
||||
// Don't want to email those with the capability to manage the certificate.
|
||||
if (has_capability('mod/customcert:manage', $context, $enroluser->id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only email those with the capability to receive the certificate.
|
||||
if (!has_capability('mod/customcert:receiveissue', $context, $enroluser->id)) {
|
||||
continue;
|
||||
|
@ -127,7 +144,7 @@ class email_certificate_task extends \core\task\scheduled_task {
|
|||
|
||||
// Ensure the cert hasn't already been issued, e.g via the UI (view.php) - a race condition.
|
||||
$issueid = $DB->get_field('customcert_issues', 'id',
|
||||
array('userid' => $enroluser->id, 'customcertid' => $customcert->id));
|
||||
array('userid' => $enroluser->id, 'customcertid' => $customcert->id), IGNORE_MULTIPLE);
|
||||
if (empty($issueid)) {
|
||||
// Ok, issue them the certificate.
|
||||
$issueid = \mod_customcert\certificate::issue_certificate($customcert->id, $enroluser->id);
|
||||
|
@ -160,6 +177,7 @@ class email_certificate_task extends \core\task\scheduled_task {
|
|||
// Now, email the people we need to.
|
||||
foreach ($issuedusers as $user) {
|
||||
$userfullname = fullname($user);
|
||||
$info->userfullname = $userfullname;
|
||||
|
||||
// Now, get the PDF.
|
||||
$template = new \stdClass();
|
||||
|
|
|
@ -283,6 +283,16 @@ class template {
|
|||
$pdf->SetAutoPageBreak(true, 0);
|
||||
// Remove full-stop at the end, if it exists, to avoid "..pdf" being created and being filtered by clean_filename.
|
||||
$filename = rtrim($this->name, '.');
|
||||
|
||||
// This is the logic the TCPDF library uses when processing the name. This makes names
|
||||
// such as 'الشهادة' become empty, so set a default name in these cases.
|
||||
$filename = preg_replace('/[\s]+/', '_', $filename);
|
||||
$filename = preg_replace('/[^a-zA-Z0-9_\.-]/', '', $filename);
|
||||
|
||||
if (empty($filename)) {
|
||||
$filename = get_string('certificate', 'customcert');
|
||||
}
|
||||
|
||||
$filename = clean_filename($filename . '.pdf');
|
||||
// Loop through the pages and display their content.
|
||||
foreach ($pages as $page) {
|
||||
|
@ -305,10 +315,12 @@ class template {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($return) {
|
||||
return $pdf->Output('', 'S');
|
||||
}
|
||||
$pdf->Output($filename, 'D');
|
||||
|
||||
$pdf->Output($filename, 'I');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"name": "markn86/moodle-mod_customcert",
|
||||
"name": "mdjnelson/moodle-mod_customcert",
|
||||
"type": "moodle-mod",
|
||||
"require": {
|
||||
"composer/installers": "~1.0"
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for customcert"/>
|
||||
<KEY NAME="template" TYPE="foreign" FIELDS="templateid" REFTABLE="customcert_template" REFFIELDS="id"/>
|
||||
<KEY NAME="template" TYPE="foreign" FIELDS="templateid" REFTABLE="customcert_templates" REFFIELDS="id"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="customcert_templates" COMMENT="Stores each customcert template">
|
||||
|
@ -67,7 +67,7 @@
|
|||
</FIELDS>
|
||||
<KEYS>
|
||||
<KEY NAME="primary" TYPE="primary" FIELDS="id" COMMENT="Primary key for customcert_pages"/>
|
||||
<KEY NAME="template" TYPE="foreign" FIELDS="templateid" REFTABLE="customcert_template" REFFIELDS="id"/>
|
||||
<KEY NAME="template" TYPE="foreign" FIELDS="templateid" REFTABLE="customcert_templates" REFFIELDS="id"/>
|
||||
</KEYS>
|
||||
</TABLE>
|
||||
<TABLE NAME="customcert_elements" COMMENT="Stores the elements for a given page">
|
||||
|
|
|
@ -30,7 +30,7 @@ $addons = [
|
|||
'issueview' => [ // Handler unique name.
|
||||
'displaydata' => [
|
||||
'icon' => $CFG->wwwroot . '/mod/customcert/pix/icon.png',
|
||||
'class' => '',
|
||||
'class' => 'core-course-module-customcert-handler',
|
||||
],
|
||||
'delegate' => 'CoreCourseModuleDelegate', // Delegate (where to display the link to the plugin).
|
||||
'method' => 'mobile_view_activity', // Main function in \mod_customcert\output\mobile.
|
||||
|
|
|
@ -146,5 +146,25 @@ function xmldb_customcert_upgrade($oldversion) {
|
|||
upgrade_mod_savepoint(true, 2018051705, 'customcert');
|
||||
}
|
||||
|
||||
if ($oldversion < 2018120305) {
|
||||
$table = new xmldb_table('customcert');
|
||||
$index = new xmldb_index('templateid', XMLDB_INDEX_UNIQUE, ['templateid']);
|
||||
if ($dbman->index_exists($table, $index)) {
|
||||
$dbman->drop_index($table, $index);
|
||||
}
|
||||
$key = new xmldb_key('templateid', XMLDB_KEY_FOREIGN, ['templateid'], 'customcert_templates', ['id']);
|
||||
$dbman->add_key($table, $key);
|
||||
|
||||
$table = new xmldb_table('customcert_pages');
|
||||
$index = new xmldb_index('templateid', XMLDB_INDEX_UNIQUE, ['templateid']);
|
||||
if ($dbman->index_exists($table, $index)) {
|
||||
$dbman->drop_index($table, $index);
|
||||
}
|
||||
$key = new xmldb_key('templateid', XMLDB_KEY_FOREIGN, ['templateid'], 'customcert_templates', ['id']);
|
||||
$dbman->add_key($table, $key);
|
||||
|
||||
upgrade_mod_savepoint(true, 2018120305, 'customcert');
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ class element extends \mod_customcert\element {
|
|||
$customcert = $DB->get_record('customcert', array('templateid' => $page->templateid), '*', MUST_EXIST);
|
||||
// Now we can get the issue for this user.
|
||||
$issue = $DB->get_record('customcert_issues', array('userid' => $user->id, 'customcertid' => $customcert->id),
|
||||
'*', MUST_EXIST);
|
||||
'*', IGNORE_MULTIPLE);
|
||||
$code = $issue->code;
|
||||
}
|
||||
|
||||
|
|
|
@ -51,6 +51,21 @@ define('CUSTOMCERT_DATE_COURSE_START', '-3');
|
|||
*/
|
||||
define('CUSTOMCERT_DATE_COURSE_END', '-4');
|
||||
|
||||
/**
|
||||
* Date - Current date
|
||||
*/
|
||||
define('CUSTOMCERT_DATE_CURRENT_DATE', '-5');
|
||||
|
||||
/**
|
||||
* Date - Enrollment start
|
||||
*/
|
||||
define('CUSTOMCERT_DATE_ENROLMENT_START', '-6');
|
||||
|
||||
/**
|
||||
* Date - Entrollment end
|
||||
*/
|
||||
define('CUSTOMCERT_DATE_ENROLMENT_END', '-7');
|
||||
|
||||
require_once($CFG->dirroot . '/lib/grade/constants.php');
|
||||
|
||||
/**
|
||||
|
@ -73,10 +88,14 @@ class element extends \mod_customcert\element {
|
|||
// Get the possible date options.
|
||||
$dateoptions = array();
|
||||
$dateoptions[CUSTOMCERT_DATE_ISSUE] = get_string('issueddate', 'customcertelement_date');
|
||||
$dateoptions[CUSTOMCERT_DATE_CURRENT_DATE] = get_string('currentdate', 'customcertelement_date');
|
||||
$completionenabled = $CFG->enablecompletion && ($COURSE->id == SITEID || $COURSE->enablecompletion);
|
||||
if ($completionenabled) {
|
||||
$dateoptions[CUSTOMCERT_DATE_COMPLETION] = get_string('completiondate', 'customcertelement_date');
|
||||
}
|
||||
$dateoptions[CUSTOMCERT_DATE_ENROLMENT_START] = get_string('enrolmentstartdate', 'customcertelement_date');
|
||||
$dateoptions[CUSTOMCERT_DATE_ENROLMENT_END] = get_string('enrolmentenddate', 'customcertelement_date');
|
||||
|
||||
$dateoptions[CUSTOMCERT_DATE_COURSE_START] = get_string('coursestartdate', 'customcertelement_date');
|
||||
$dateoptions[CUSTOMCERT_DATE_COURSE_END] = get_string('courseenddate', 'customcertelement_date');
|
||||
$dateoptions[CUSTOMCERT_DATE_COURSE_GRADE] = get_string('coursegradedate', 'customcertelement_date');
|
||||
|
@ -141,10 +160,12 @@ class element extends \mod_customcert\element {
|
|||
$customcert = $DB->get_record('customcert', array('templateid' => $page->templateid), '*', MUST_EXIST);
|
||||
// Now we can get the issue for this user.
|
||||
$issue = $DB->get_record('customcert_issues', array('userid' => $user->id, 'customcertid' => $customcert->id),
|
||||
'*', MUST_EXIST);
|
||||
'*', IGNORE_MULTIPLE);
|
||||
|
||||
if ($dateitem == CUSTOMCERT_DATE_ISSUE) {
|
||||
$date = $issue->timecreated;
|
||||
} else if ($dateitem == CUSTOMCERT_DATE_CURRENT_DATE) {
|
||||
$date = time();
|
||||
} else if ($dateitem == CUSTOMCERT_DATE_COMPLETION) {
|
||||
// Get the last completion date.
|
||||
$sql = "SELECT MAX(c.timecompleted) as timecompleted
|
||||
|
@ -156,6 +177,26 @@ class element extends \mod_customcert\element {
|
|||
$date = $timecompleted->timecompleted;
|
||||
}
|
||||
}
|
||||
} else if ($dateitem == CUSTOMCERT_DATE_ENROLMENT_START) {
|
||||
// Get the enrolment start date.
|
||||
$sql = "SELECT ue.timestart FROM {enrol} e JOIN {user_enrolments} ue ON ue.enrolid = e.id
|
||||
WHERE e.courseid = :courseid
|
||||
AND ue.userid = :userid";
|
||||
if ($timestart = $DB->get_record_sql($sql, array('userid' => $issue->userid, 'courseid' => $courseid))) {
|
||||
if (!empty($timestart->timestart)) {
|
||||
$date = $timestart->timestart;
|
||||
}
|
||||
}
|
||||
} else if ($dateitem == CUSTOMCERT_DATE_ENROLMENT_END) {
|
||||
// Get the enrolment end date.
|
||||
$sql = "SELECT ue.timeend FROM {enrol} e JOIN {user_enrolments} ue ON ue.enrolid = e.id
|
||||
WHERE e.courseid = :courseid
|
||||
AND ue.userid = :userid";
|
||||
if ($timeend = $DB->get_record_sql($sql, array('userid' => $issue->userid, 'courseid' => $courseid))) {
|
||||
if (!empty($timeend->timeend)) {
|
||||
$date = $timeend->timeend;
|
||||
}
|
||||
}
|
||||
} else if ($dateitem == CUSTOMCERT_DATE_COURSE_START) {
|
||||
$date = $DB->get_field('course', 'startdate', array('id' => $courseid));
|
||||
} else if ($dateitem == CUSTOMCERT_DATE_COURSE_END) {
|
||||
|
@ -190,12 +231,7 @@ class element extends \mod_customcert\element {
|
|||
|
||||
// Ensure that a date has been set.
|
||||
if (!empty($date)) {
|
||||
$date = $this->get_date_format_string($date, $dateformat);
|
||||
// If we are previewing, we want to let the user know it's an example date so they don't get confused.
|
||||
if ($preview) {
|
||||
$date = get_string('exampledata', 'customcert', 'date') . ' ' . $date;
|
||||
}
|
||||
\mod_customcert\element_helper::render_content($pdf, $this, $date);
|
||||
\mod_customcert\element_helper::render_content($pdf, $this, $this->get_date_format_string($date, $dateformat));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,9 @@ $string['completiondate'] = 'Completion date';
|
|||
$string['courseenddate'] = 'Course end date';
|
||||
$string['coursegradedate'] = 'Course grade date';
|
||||
$string['coursestartdate'] = 'Course start date';
|
||||
$string['enrolmentenddate'] = 'Enrolment end date';
|
||||
$string['enrolmentstartdate'] = 'Enrolment start date';
|
||||
$string['currentdate'] = 'Current date';
|
||||
$string['dateformat'] = 'Date format';
|
||||
$string['dateformat_help'] = 'This is the format of the date that will be displayed';
|
||||
$string['dateitem'] = 'Date item';
|
||||
|
|
|
@ -24,6 +24,6 @@
|
|||
|
||||
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
|
||||
|
||||
$plugin->version = 2018120300; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2018120301; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2018120300; // Requires this Moodle version (3.6).
|
||||
$plugin->component = 'customcertelement_date';
|
||||
|
|
|
@ -77,32 +77,37 @@ class element extends \mod_customcert\element {
|
|||
/**
|
||||
* Date - Issue
|
||||
*/
|
||||
const DATE_ISSUE = 1;
|
||||
const DATE_ISSUE = -1;
|
||||
|
||||
/**
|
||||
* Date - Completion
|
||||
*/
|
||||
const DATE_COMPLETION = 2;
|
||||
const DATE_COMPLETION = -2;
|
||||
|
||||
/**
|
||||
* Date - Course start
|
||||
*/
|
||||
const DATE_COURSE_START = 3;
|
||||
const DATE_COURSE_START = -3;
|
||||
|
||||
/**
|
||||
* Date - Course end
|
||||
*/
|
||||
const DATE_COURSE_END = 4;
|
||||
const DATE_COURSE_END = -4;
|
||||
|
||||
/**
|
||||
* Date - Course grade date
|
||||
*/
|
||||
const DATE_COURSE_GRADE = 5;
|
||||
const DATE_COURSE_GRADE = -5;
|
||||
|
||||
/**
|
||||
* Date - Course current date
|
||||
*/
|
||||
const DATE_CURRENT_DATE = -6;
|
||||
|
||||
/**
|
||||
* This function renders the form elements when adding a customcert element.
|
||||
*
|
||||
* @param \mod_customcert\edit_element_form $mform the edit_form instance
|
||||
* @param \MoodleQuickForm $mform the edit form instance
|
||||
*/
|
||||
public function render_form_elements($mform) {
|
||||
global $COURSE;
|
||||
|
@ -110,6 +115,7 @@ class element extends \mod_customcert\element {
|
|||
// Get the possible date options.
|
||||
$dateoptions = array();
|
||||
$dateoptions[self::DATE_ISSUE] = get_string('issueddate', 'customcertelement_daterange');
|
||||
$dateoptions[self::DATE_CURRENT_DATE] = get_string('currentdate', 'customcertelement_daterange');
|
||||
$dateoptions[self::DATE_COMPLETION] = get_string('completiondate', 'customcertelement_daterange');
|
||||
$dateoptions[self::DATE_COURSE_START] = get_string('coursestartdate', 'customcertelement_daterange');
|
||||
$dateoptions[self::DATE_COURSE_END] = get_string('courseenddate', 'customcertelement_daterange');
|
||||
|
@ -178,6 +184,7 @@ class element extends \mod_customcert\element {
|
|||
$rangeoptions['startdate']['type'] = PARAM_INT;
|
||||
$rangeoptions['enddate']['type'] = PARAM_INT;
|
||||
$rangeoptions['recurring']['type'] = PARAM_INT;
|
||||
$rangeoptions['recurring']['helpbutton'] = ['recurring', 'customcertelement_daterange'];
|
||||
$rangeoptions['datestring']['type'] = PARAM_NOTAGS;
|
||||
$rangeoptions['rangedelete']['type'] = PARAM_BOOL;
|
||||
|
||||
|
@ -209,7 +216,7 @@ class element extends \mod_customcert\element {
|
|||
/**
|
||||
* Sets the data on the form when editing an element.
|
||||
*
|
||||
* @param \mod_customcert\edit_element_form $mform the edit_form instance
|
||||
* @param \MoodleQuickForm $mform the edit form instance
|
||||
*/
|
||||
public function definition_after_data($mform) {
|
||||
if (!empty($this->get_data()) && !$mform->isSubmitted()) {
|
||||
|
@ -345,6 +352,10 @@ class element extends \mod_customcert\element {
|
|||
$date = $issue->timecreated;
|
||||
break;
|
||||
|
||||
case self::DATE_CURRENT_DATE:
|
||||
$date = time();
|
||||
break;
|
||||
|
||||
case self::DATE_COMPLETION:
|
||||
// Get the last completion date.
|
||||
$sql = "SELECT MAX(c.timecompleted) as timecompleted
|
||||
|
@ -442,6 +453,8 @@ class element extends \mod_customcert\element {
|
|||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not a range is recurring.
|
||||
*
|
||||
* @param \stdClass $range Range object.
|
||||
*
|
||||
* @return bool
|
||||
|
@ -597,6 +610,7 @@ class element extends \mod_customcert\element {
|
|||
/**
|
||||
* Format date string based on different types of placeholders.
|
||||
*
|
||||
* @param string $datestring The date string
|
||||
* @param array $formatdata A list of format data.
|
||||
*
|
||||
* @return string
|
||||
|
|
|
@ -24,28 +24,30 @@
|
|||
|
||||
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
|
||||
|
||||
$string['addrange'] = 'Add another range';
|
||||
$string['completiondate'] = 'Completion date';
|
||||
$string['courseenddate'] = 'Course end date';
|
||||
$string['coursegradedate'] = 'Course grade date';
|
||||
$string['coursestartdate'] = 'Course start date';
|
||||
$string['currentdate'] = 'Current date';
|
||||
$string['dateitem'] = 'Date item';
|
||||
$string['dateitem_help'] = 'This will be the date that is printed on the certificate';
|
||||
$string['dateranges'] = 'Date ranges';
|
||||
$string['datestring'] = 'String';
|
||||
$string['end'] = 'End';
|
||||
$string['error:atleastone'] = 'You must have at least one date range configured';
|
||||
$string['error:datestring'] = 'You must provide string representation for the date range';
|
||||
$string['error:enddate'] = 'End date must occur after the start date';
|
||||
$string['error:recurring'] = 'Recurring range must not be longer than 12 months';
|
||||
$string['fallbackstring'] = 'Fallback string';
|
||||
$string['fallbackstring_help'] = 'This string will be displayed if no date range applies to a date. If the fallback string is not set, then there will be no output at all.';
|
||||
$string['help'] = 'Configure a string representation for each date range. Make sure your ranges do not overlap, otherwise the first matched date range will be applied. If no date range matches then the fallback string will be displayed (if it is set).<br/><br /> If you mark a date range as recurring, then the configured year will not be considered.';
|
||||
$string['placeholders'] = 'The following placeholders can be used in the string representation or fallback string. <br/><br /> {{range_first_year}} - first year of the matched range,<br/> {{range_last_year}} - last year of the matched range,<br/> {{recurring_range_first_year}} - first year of the matched recurring period,<br/> {{recurring_range_last_year}} - last year of the matched recurring period,<br/> {{current_year}} - the current year,<br/> {{date_year}} - a year of the users\'s date.';
|
||||
$string['help'] = 'Configure a string representation for your date ranges.<br /><br />If your ranges overlap the first matched date range will be applied.';
|
||||
$string['issueddate'] = 'Issued date';
|
||||
$string['placeholders'] = 'The following placeholders can be used in the string representation or fallback string. <br/><br /> {{range_first_year}} - first year of the matched range,<br/> {{range_last_year}} - last year of the matched range,<br/> {{recurring_range_first_year}} - first year of the matched recurring period,<br/> {{recurring_range_last_year}} - last year of the matched recurring period,<br/> {{current_year}} - the current year,<br/> {{date_year}} - a year of the users\'s date.';
|
||||
$string['pluginname'] = 'Date range';
|
||||
$string['privacy:metadata'] = 'The Date range plugin does not store any personal data.';
|
||||
$string['start'] = 'Start';
|
||||
$string['end'] = 'End';
|
||||
$string['datestring'] = 'String';
|
||||
$string['error:atleastone'] = 'You must have at least one date range configured';
|
||||
$string['error:datestring'] = 'You must provide string representation for the datarange';
|
||||
$string['error:enddate'] = 'End date must be after Start date';
|
||||
$string['error:recurring'] = 'Recurring range must not be longer than 12 months';
|
||||
$string['preview'] = 'Preview {$a}';
|
||||
$string['recurring'] = 'Recurring?';
|
||||
$string['setdeleted'] = 'Delete?';
|
||||
$string['addrange'] = 'Add another range';
|
||||
$string['privacy:metadata'] = 'The Date range plugin does not store any personal data.';
|
||||
$string['recurring'] = 'Recurring';
|
||||
$string['recurring_help'] = 'If you mark a date range as recurring then the configured year will not be considered.';
|
||||
$string['setdeleted'] = 'Delete';
|
||||
$string['start'] = 'Start';
|
||||
|
|
|
@ -27,6 +27,13 @@ global $CFG;
|
|||
|
||||
require_once($CFG->dirroot . '/mod/customcert/element/daterange/tests/fixtures/fake_datarange_element.php');
|
||||
|
||||
/**
|
||||
* Test datarange element.
|
||||
*
|
||||
* @package customcertelement_daterange
|
||||
* @copyright 2018 Dmitrii Metelkin <dmitriim@catalyst-au.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class customcertelement_daterange_element_test extends advanced_testcase {
|
||||
|
||||
/**
|
||||
|
|
|
@ -24,6 +24,13 @@
|
|||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
/**
|
||||
* Fake datarange element for testing.
|
||||
*
|
||||
* @package customcertelement_daterange
|
||||
* @copyright 2018 Dmitrii Metelkin <dmitriim@catalyst-au.net>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class fake_datarange_element extends \customcertelement_daterange\element {
|
||||
|
||||
/**
|
||||
|
|
|
@ -107,8 +107,7 @@ class element extends \mod_customcert\element {
|
|||
// If we are previewing this certificate then just show a demonstration grade.
|
||||
if ($preview) {
|
||||
$courseitem = \grade_item::fetch_course_item($courseid);
|
||||
$grade = grade_format_gradevalue('100', $courseitem, true, $gradeinfo->gradeformat);
|
||||
$grade = get_string('exampledata', 'customcert', 'grade') . ' ' . $grade;
|
||||
$grade = grade_format_gradevalue('100', $courseitem, true, $gradeinfo->gradeformat);;
|
||||
} else {
|
||||
if ($gradeitem == CUSTOMCERT_GRADE_COURSE) {
|
||||
$grade = \mod_customcert\element_helper::get_course_grade_info(
|
||||
|
|
|
@ -110,20 +110,40 @@ class element extends \mod_customcert\element {
|
|||
}
|
||||
|
||||
/**
|
||||
* Helper function that returns the category name.
|
||||
* Helper function that returns the grade item name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_grade_item_name() : string {
|
||||
global $DB;
|
||||
|
||||
// Get the course module information.
|
||||
$cm = $DB->get_record('course_modules', array('id' => $this->get_data()), '*', MUST_EXIST);
|
||||
$module = $DB->get_record('modules', array('id' => $cm->module), '*', MUST_EXIST);
|
||||
$gradeitem = $this->get_data();
|
||||
|
||||
// Get the name of the item.
|
||||
$itemname = $DB->get_field($module->name, 'name', array('id' => $cm->instance), MUST_EXIST);
|
||||
if (strpos($gradeitem, 'gradeitem:') === 0) {
|
||||
$gradeitemid = substr($gradeitem, 10);
|
||||
$gradeitem = \grade_item::fetch(['id' => $gradeitemid]);
|
||||
|
||||
return format_string($itemname, true, ['context' => \mod_customcert\element_helper::get_context($this->get_id())]);
|
||||
return $gradeitem->get_name();
|
||||
} else {
|
||||
if (!$cm = $DB->get_record('course_modules', array('id' => $gradeitem))) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (!$module = $DB->get_record('modules', array('id' => $cm->module))) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$params = [
|
||||
'itemtype' => 'mod',
|
||||
'itemmodule' => $module->name,
|
||||
'iteminstance' => $cm->instance,
|
||||
'courseid' => $cm->course,
|
||||
'itemnumber' => 0
|
||||
];
|
||||
|
||||
$gradeitem = \grade_item::fetch($params);
|
||||
|
||||
return $gradeitem->get_name();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -382,14 +382,14 @@ class element extends \mod_customcert\element {
|
|||
// Loop through the files uploaded in the system context.
|
||||
if ($files = $fs->get_area_files(\context_system::instance()->id, 'mod_customcert', 'image', false, 'filename', false)) {
|
||||
foreach ($files as $hash => $file) {
|
||||
$arrfiles[$file->get_id()] = $file->get_filename();
|
||||
$arrfiles[$file->get_id()] = get_string('systemimage', 'customcertelement_image', $file->get_filename());
|
||||
}
|
||||
}
|
||||
// Loop through the files uploaded in the course context.
|
||||
if ($files = $fs->get_area_files(\context_course::instance($COURSE->id)->id, 'mod_customcert', 'image', false,
|
||||
'filename', false)) {
|
||||
foreach ($files as $hash => $file) {
|
||||
$arrfiles[$file->get_id()] = $file->get_filename();
|
||||
$arrfiles[$file->get_id()] = get_string('courseimage', 'customcertelement_image', $file->get_filename());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -398,4 +398,60 @@ class element extends \mod_customcert\element {
|
|||
|
||||
return $arrfiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* This handles copying data from another element of the same type.
|
||||
*
|
||||
* @param \stdClass $data the form data
|
||||
* @return bool returns true if the data was copied successfully, false otherwise
|
||||
*/
|
||||
public function copy_element($data) {
|
||||
global $COURSE, $DB, $SITE;
|
||||
|
||||
$imagedata = json_decode($data->data);
|
||||
|
||||
// If we are in the site context we don't have to do anything, the image is already there.
|
||||
if ($COURSE->id == $SITE->id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$coursecontext = \context_course::instance($COURSE->id);
|
||||
$systemcontext = \context_system::instance();
|
||||
|
||||
$fs = get_file_storage();
|
||||
|
||||
// Check that a file has been selected.
|
||||
if (isset($imagedata->filearea)) {
|
||||
// If the course file doesn't exist, copy the system file to the course context.
|
||||
if (!$coursefile = $fs->get_file(
|
||||
$coursecontext->id,
|
||||
'mod_customcert',
|
||||
$imagedata->filearea,
|
||||
$imagedata->itemid,
|
||||
$imagedata->filepath,
|
||||
$imagedata->filename
|
||||
)) {
|
||||
$systemfile = $fs->get_file(
|
||||
$systemcontext->id,
|
||||
'mod_customcert',
|
||||
$imagedata->filearea,
|
||||
$imagedata->itemid,
|
||||
$imagedata->filepath,
|
||||
$imagedata->filename
|
||||
);
|
||||
|
||||
// We want to update the context of the file if it doesn't exist in the course context.
|
||||
$fieldupdates = [
|
||||
'contextid' => $coursecontext->id
|
||||
];
|
||||
$coursefile = $fs->create_file_from_storedfile($fieldupdates, $systemfile);
|
||||
}
|
||||
|
||||
// Set the image to the copied file in the course.
|
||||
$imagedata->fileid = $coursefile->get_id();
|
||||
$DB->set_field('customcert_elements', 'data', $this->save_unique_data($imagedata), ['id' => $this->get_id()]);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
$string['alphachannel'] = 'Alpha channel';
|
||||
$string['alphachannel_help'] = 'This value determines how transparent the image is. You can set the alpha channel from 0 (fully transparent) to 1 (fully opaque).';
|
||||
$string['courseimage'] = 'Course image: {$a}';
|
||||
$string['height'] = 'Height';
|
||||
$string['height_help'] = 'Height of the image in mm. If equal to zero, it is automatically calculated.';
|
||||
$string['image'] = 'Image';
|
||||
|
@ -31,5 +32,6 @@ $string['invalidheight'] = 'The height has to be a valid number greater than or
|
|||
$string['invalidwidth'] = 'The width has to be a valid number greater than or equal to 0.';
|
||||
$string['pluginname'] = 'Image';
|
||||
$string['privacy:metadata'] = 'The Image plugin does not store any personal data.';
|
||||
$string['systemimage'] = 'Site image: {$a}';
|
||||
$string['width'] = 'Width';
|
||||
$string['width_help'] = 'Width of the image in mm. If equal to zero, it is automatically calculated.';
|
||||
|
|
|
@ -37,7 +37,9 @@ require_once($CFG->libdir . '/tcpdf/tcpdf_barcodes_2d.php');
|
|||
*/
|
||||
class element extends \mod_customcert\element {
|
||||
|
||||
|
||||
/**
|
||||
* @var string The barcode type.
|
||||
*/
|
||||
const BARCODETYPE = 'QRCODE';
|
||||
|
||||
/**
|
||||
|
@ -70,8 +72,12 @@ class element extends \mod_customcert\element {
|
|||
$errors = [];
|
||||
|
||||
// Check if height is not set, or not numeric or less than 0.
|
||||
if ((!isset($data['height'])) || (!is_numeric($data['height'])) || ($data['height'] < 0)) {
|
||||
$errors['height'] = get_string('invalidheight', 'customcertelement_qrcode');
|
||||
if ((!isset($data['height'])) || (!is_numeric($data['height'])) || ($data['height'] <= 0)) {
|
||||
$errors['height'] = get_string('invalidheight', 'mod_customcert');
|
||||
}
|
||||
|
||||
if ((!isset($data['width'])) || (!is_numeric($data['width'])) || ($data['width'] <= 0)) {
|
||||
$errors['width'] = get_string('invalidwidth', 'mod_customcert');
|
||||
}
|
||||
|
||||
if ($this->showposxy) {
|
||||
|
|
|
@ -45,6 +45,7 @@ class element extends \mod_customcert\element {
|
|||
$userfields = array(
|
||||
'firstname' => get_user_field_name('firstname'),
|
||||
'lastname' => get_user_field_name('lastname'),
|
||||
'username' => get_user_field_name('username'),
|
||||
'email' => get_user_field_name('email'),
|
||||
'city' => get_user_field_name('city'),
|
||||
'country' => get_user_field_name('country'),
|
||||
|
@ -65,7 +66,7 @@ class element extends \mod_customcert\element {
|
|||
$arrcustomfields = \availability_profile\condition::get_custom_profile_fields();
|
||||
$customfields = array();
|
||||
foreach ($arrcustomfields as $key => $customfield) {
|
||||
$customfields[$customfield->id] = $key;
|
||||
$customfields[$customfield->id] = $customfield->name;
|
||||
}
|
||||
// Combine the two.
|
||||
$fields = $userfields + $customfields;
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
$string['activity'] = 'Activity';
|
||||
$string['addcertpage'] = 'Add page';
|
||||
$string['addelement'] = 'Add element';
|
||||
$string['awardedto'] = 'Awarded to';
|
||||
|
@ -83,12 +84,11 @@ $string['emailstudentcertificatelinktext'] = 'View certificate';
|
|||
$string['emailstudentgreeting'] = 'Dear {$a}';
|
||||
$string['emailstudentsubject'] = '{$a->coursefullname}: {$a->certificatename}';
|
||||
$string['emailstudents'] = 'Email students';
|
||||
$string['emailstudents_help'] = 'If set this will email the students a copy of the certificate when it becomes available.';
|
||||
$string['emailstudents_help'] = 'If set this will email the students a copy of the certificate when it becomes available. <strong>Warning:</strong> Setting this to \'Yes\' before you have finished creating the certificate will email the student an incomplete certificate.';
|
||||
$string['emailteachers'] = 'Email teachers';
|
||||
$string['emailteachers_help'] = 'If set this will email the teachers a copy of the certificate when it becomes available.';
|
||||
$string['emailteachers_help'] = 'If set this will email the teachers a copy of the certificate when it becomes available. <strong>Warning:</strong> Setting this to \'Yes\' before you have finished creating the certificate will email the teacher an incomplete certificate.';
|
||||
$string['emailothers'] = 'Email others';
|
||||
$string['emailothers_help'] = 'If set this will email the email addresses listed here (separated by a comma) with a copy of the certificate when it becomes available.';
|
||||
$string['exampledata'] = 'Example {$a}:';
|
||||
$string['emailothers_help'] = 'If set this will email the email addresses listed here (separated by a comma) with a copy of the certificate when it becomes available. <strong>Warning:</strong> Setting this field before you have finished creating the certificate will email the addresses an incomplete certificate.';
|
||||
$string['exampledatawarning'] = 'Some of these values may just be an example to ensure positioning of the elements is possible.';
|
||||
$string['font'] = 'Font';
|
||||
$string['font_help'] = 'The font used when generating this element.';
|
||||
|
@ -97,6 +97,7 @@ $string['fontcolour_help'] = 'The colour of the font.';
|
|||
$string['fontsize'] = 'Size';
|
||||
$string['fontsize_help'] = 'The size of the font in points.';
|
||||
$string['getcustomcert'] = 'View certificate';
|
||||
$string['gradeoutcome'] = 'Outcome';
|
||||
$string['height'] = 'Height';
|
||||
$string['height_help'] = 'This is the height of the certificate PDF in mm. For reference an A4 piece of paper is 297mm high and a letter is 279mm high.';
|
||||
$string['invalidcode'] = 'Invalid code supplied.';
|
||||
|
|
|
@ -34,6 +34,7 @@ define('NO_MOODLE_COOKIES', true);
|
|||
|
||||
require_once('../../../config.php');
|
||||
require_once($CFG->libdir . '/filelib.php');
|
||||
require_once($CFG->libdir . '/completionlib.php');
|
||||
require_once($CFG->dirroot . '/webservice/lib.php');
|
||||
|
||||
// Allow CORS requests.
|
||||
|
@ -54,6 +55,7 @@ if (empty($enabledfiledownload)) {
|
|||
}
|
||||
|
||||
$cm = get_coursemodule_from_instance('customcert', $certificateid, 0, false, MUST_EXIST);
|
||||
$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
|
||||
$certificate = $DB->get_record('customcert', ['id' => $certificateid], '*', MUST_EXIST);
|
||||
$template = $DB->get_record('customcert_templates', ['id' => $certificate->templateid], '*', MUST_EXIST);
|
||||
|
||||
|
@ -80,6 +82,10 @@ if (!$issue) {
|
|||
}
|
||||
|
||||
\mod_customcert\certificate::issue_certificate($certificate->id, $USER->id);
|
||||
|
||||
// Set the custom certificate as viewed.
|
||||
$completion = new completion_info($course);
|
||||
$completion->set_module_viewed($cm);
|
||||
}
|
||||
|
||||
// Now we want to generate the PDF.
|
||||
|
|
|
@ -119,6 +119,42 @@ Feature: Being able to manage elements in a certificate template
|
|||
| Width | 20 |
|
||||
| Reference point location | Top left |
|
||||
And I press "Save changes"
|
||||
# Date range.
|
||||
And I add the element "Date range" to page "1" of the "Custom certificate 1" certificate template
|
||||
And I set the following fields to these values:
|
||||
| Date item | Course start date |
|
||||
| Font | Helvetica |
|
||||
| Size | 20 |
|
||||
| Colour | #045ECD |
|
||||
| Width | 20 |
|
||||
| Reference point location | Top left |
|
||||
| Fallback string | {{range_first_year}} |
|
||||
| id_startdate_0_day | 24 |
|
||||
| id_startdate_0_month | October |
|
||||
| id_startdate_0_year | 2015 |
|
||||
| id_enddate_0_day | 21 |
|
||||
| id_enddate_0_month | March |
|
||||
| id_enddate_0_year | 2016 |
|
||||
| String | Oct to March |
|
||||
And I press "Save changes"
|
||||
And I should see "Date range" in the "elementstable" "table"
|
||||
And I click on ".edit-icon" "css_element" in the "Date range" "table_row"
|
||||
And the following fields match these values:
|
||||
| Date item | Course start date |
|
||||
| Font | Helvetica |
|
||||
| Size | 20 |
|
||||
| Colour | #045ECD |
|
||||
| Width | 20 |
|
||||
| Reference point location | Top left |
|
||||
| Fallback string | {{range_first_year}} |
|
||||
| id_startdate_0_day | 24 |
|
||||
| id_startdate_0_month | October |
|
||||
| id_startdate_0_year | 2015 |
|
||||
| id_enddate_0_day | 21 |
|
||||
| id_enddate_0_month | March |
|
||||
| id_enddate_0_year | 2016 |
|
||||
| String | Oct to March |
|
||||
And I press "Save changes"
|
||||
# Digital signature.
|
||||
And I add the element "Digital signature" to page "1" of the "Custom certificate 1" certificate template
|
||||
And I set the following fields to these values:
|
||||
|
@ -144,44 +180,44 @@ Feature: Being able to manage elements in a certificate template
|
|||
# Grade.
|
||||
And I add the element "Grade" to page "1" of the "Custom certificate 1" certificate template
|
||||
And I set the following fields to these values:
|
||||
| Grade item | Topic 0 : Assignment 1 |
|
||||
| Grade format | Percentage |
|
||||
| Font | Helvetica |
|
||||
| Size | 20 |
|
||||
| Colour | #045ECD |
|
||||
| Width | 20 |
|
||||
| Reference point location | Top left |
|
||||
| Grade item | Activity : Assignment 1 |
|
||||
| Grade format | Percentage |
|
||||
| Font | Helvetica |
|
||||
| Size | 20 |
|
||||
| Colour | #045ECD |
|
||||
| Width | 20 |
|
||||
| Reference point location | Top left |
|
||||
And I press "Save changes"
|
||||
And I should see "Grade" in the "elementstable" "table"
|
||||
And I click on ".edit-icon" "css_element" in the "Grade" "table_row"
|
||||
And the following fields match these values:
|
||||
| Grade item | Topic 0 : Assignment 1 |
|
||||
| Grade format | Percentage |
|
||||
| Font | Helvetica |
|
||||
| Size | 20 |
|
||||
| Colour | #045ECD |
|
||||
| Width | 20 |
|
||||
| Reference point location | Top left |
|
||||
| Grade item | Activity : Assignment 1 |
|
||||
| Grade format | Percentage |
|
||||
| Font | Helvetica |
|
||||
| Size | 20 |
|
||||
| Colour | #045ECD |
|
||||
| Width | 20 |
|
||||
| Reference point location | Top left |
|
||||
And I press "Save changes"
|
||||
# Grade item name.
|
||||
And I add the element "Grade item name" to page "1" of the "Custom certificate 1" certificate template
|
||||
And I set the following fields to these values:
|
||||
| Grade item | Topic 0 : Assignment 2 |
|
||||
| Font | Helvetica |
|
||||
| Size | 20 |
|
||||
| Colour | #045ECD |
|
||||
| Width | 20 |
|
||||
| Reference point location | Top left |
|
||||
| Grade item | Activity : Assignment 2 |
|
||||
| Font | Helvetica |
|
||||
| Size | 20 |
|
||||
| Colour | #045ECD |
|
||||
| Width | 20 |
|
||||
| Reference point location | Top left |
|
||||
And I press "Save changes"
|
||||
And I should see "Grade item name" in the "elementstable" "table"
|
||||
And I click on ".edit-icon" "css_element" in the "Grade item name" "table_row"
|
||||
And the following fields match these values:
|
||||
| Grade item | Topic 0 : Assignment 2 |
|
||||
| Font | Helvetica |
|
||||
| Size | 20 |
|
||||
| Colour | #045ECD |
|
||||
| Width | 20 |
|
||||
| Reference point location | Top left |
|
||||
| Grade item | Activity : Assignment 2 |
|
||||
| Font | Helvetica |
|
||||
| Size | 20 |
|
||||
| Colour | #045ECD |
|
||||
| Width | 20 |
|
||||
| Reference point location | Top left |
|
||||
And I press "Save changes"
|
||||
# Image.
|
||||
And I add the element "Image" to page "1" of the "Custom certificate 1" certificate template
|
||||
|
@ -287,6 +323,18 @@ Feature: Being able to manage elements in a certificate template
|
|||
| Width | 10 |
|
||||
| Height | 10 |
|
||||
And I press "Save changes"
|
||||
# QR Code.
|
||||
And I add the element "QR code" to page "1" of the "Custom certificate 1" certificate template
|
||||
And I set the following fields to these values:
|
||||
| Width | 25 |
|
||||
| Height | 15 |
|
||||
And I press "Save changes"
|
||||
And I should see "QR code" in the "elementstable" "table"
|
||||
And I click on ".edit-icon" "css_element" in the "QR code" "table_row"
|
||||
And the following fields match these values:
|
||||
| Width | 25 |
|
||||
| Height | 15 |
|
||||
And I press "Save changes"
|
||||
# Just to test there are no exceptions being thrown.
|
||||
And I follow "Reposition elements"
|
||||
And I press "Save and close"
|
||||
|
|
|
@ -180,14 +180,24 @@ class mod_customcert_element_helper_testcase extends advanced_testcase {
|
|||
$gc = $this->getDataGenerator()->create_grade_category(['courseid' => $course->id]);
|
||||
$gc = $DB->get_record('grade_items', ['itemtype' => 'category', 'iteminstance' => $gc->id]);
|
||||
|
||||
// Create an item attached to an outcome.
|
||||
$outcome = $this->getDataGenerator()->create_grade_outcome(['courseid' => $course->id, 'shortname' => 'outcome']);
|
||||
$go = $this->getDataGenerator()->create_grade_item(
|
||||
[
|
||||
'courseid' => $course->id,
|
||||
'outcomeid' => $outcome->id
|
||||
]
|
||||
);
|
||||
|
||||
// Confirm the function returns the correct number of grade items.
|
||||
$gradeitems = \mod_customcert\element_helper::get_grade_items($course);
|
||||
$this->assertCount(5, $gradeitems);
|
||||
$this->assertCount(6, $gradeitems);
|
||||
$this->assertArrayHasKey($assign1->cmid, $gradeitems);
|
||||
$this->assertArrayHasKey($assign2->cmid, $gradeitems);
|
||||
$this->assertArrayHasKey($assign3->cmid, $gradeitems);
|
||||
$this->assertArrayHasKey('gradeitem:' . $gi->id, $gradeitems);
|
||||
$this->assertArrayHasKey('gradeitem:' . $gc->id, $gradeitems);
|
||||
$this->assertArrayHasKey('gradeitem:' . $go->id, $gradeitems);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,8 +25,6 @@
|
|||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
global $CFG;
|
||||
|
||||
/**
|
||||
* Unit tests for the email certificate task.
|
||||
*
|
||||
|
@ -44,6 +42,32 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
|
|||
$this->resetAfterTest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the email certificate task when there are no elements.
|
||||
*/
|
||||
public function test_email_certificates_no_elements() {
|
||||
// Create a course.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
||||
// Create a user.
|
||||
$user1 = $this->getDataGenerator()->create_user();
|
||||
|
||||
// Create a custom certificate with no elements.
|
||||
$this->getDataGenerator()->create_module('customcert', ['course' => $course->id, 'emailstudents' => 1]);
|
||||
|
||||
// Enrol the user as a student
|
||||
$this->getDataGenerator()->enrol_user($user1->id, $course->id);
|
||||
|
||||
// Run the task.
|
||||
$sink = $this->redirectEmails();
|
||||
$task = new \mod_customcert\task\email_certificate_task();
|
||||
$task->execute();
|
||||
$emails = $sink->get_messages();
|
||||
|
||||
// Confirm that we did not send any emails because the certificate has no elements.
|
||||
$this->assertCount(0, $emails);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests the email certificate task for users without a capability to receive a certificate.
|
||||
*/
|
||||
|
@ -65,7 +89,23 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
|
|||
unassign_capability('mod/customcert:receiveissue', $roleids['student']);
|
||||
|
||||
// Create a custom certificate.
|
||||
$this->getDataGenerator()->create_module('customcert', ['course' => $course->id, 'emailstudents' => 1]);
|
||||
$customcert = $this->getDataGenerator()->create_module('customcert', ['course' => $course->id, 'emailstudents' => 1]);
|
||||
|
||||
// Create template object.
|
||||
$template = new stdClass();
|
||||
$template->id = $customcert->templateid;
|
||||
$template->name = 'A template';
|
||||
$template->contextid = context_course::instance($course->id)->id;
|
||||
$template = new \mod_customcert\template($template);
|
||||
|
||||
// Add a page to this template.
|
||||
$pageid = $template->add_page();
|
||||
|
||||
// Add an element to the page.
|
||||
$element = new stdClass();
|
||||
$element->pageid = $pageid;
|
||||
$element->name = 'Image';
|
||||
$DB->insert_record('customcert_elements', $element);
|
||||
|
||||
// Run the task.
|
||||
$sink = $this->redirectEmails();
|
||||
|
@ -103,6 +143,22 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
|
|||
$customcert = $this->getDataGenerator()->create_module('customcert', array('course' => $course->id,
|
||||
'emailstudents' => 1));
|
||||
|
||||
// Create template object.
|
||||
$template = new stdClass();
|
||||
$template->id = $customcert->templateid;
|
||||
$template->name = 'A template';
|
||||
$template->contextid = context_course::instance($course->id)->id;
|
||||
$template = new \mod_customcert\template($template);
|
||||
|
||||
// Add a page to this template.
|
||||
$pageid = $template->add_page();
|
||||
|
||||
// Add an element to the page.
|
||||
$element = new stdClass();
|
||||
$element->pageid = $pageid;
|
||||
$element->name = 'Image';
|
||||
$DB->insert_record('customcert_elements', $element);
|
||||
|
||||
// Ok, now issue this to one user.
|
||||
\mod_customcert\certificate::issue_certificate($customcert->id, $user1->id);
|
||||
|
||||
|
@ -169,9 +225,25 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
|
|||
$this->getDataGenerator()->enrol_user($user3->id, $course->id, $roleids['editingteacher']);
|
||||
|
||||
// Create a custom certificate.
|
||||
$this->getDataGenerator()->create_module('customcert', array('course' => $course->id,
|
||||
$customcert = $this->getDataGenerator()->create_module('customcert', array('course' => $course->id,
|
||||
'emailteachers' => 1));
|
||||
|
||||
// Create template object.
|
||||
$template = new stdClass();
|
||||
$template->id = $customcert->templateid;
|
||||
$template->name = 'A template';
|
||||
$template->contextid = context_course::instance($course->id)->id;
|
||||
$template = new \mod_customcert\template($template);
|
||||
|
||||
// Add a page to this template.
|
||||
$pageid = $template->add_page();
|
||||
|
||||
// Add an element to the page.
|
||||
$element = new stdClass();
|
||||
$element->pageid = $pageid;
|
||||
$element->name = 'Image';
|
||||
$DB->insert_record('customcert_elements', $element);
|
||||
|
||||
// Run the task.
|
||||
$sink = $this->redirectEmails();
|
||||
$task = new \mod_customcert\task\email_certificate_task();
|
||||
|
@ -192,7 +264,7 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
|
|||
* Tests the email certificate task for others.
|
||||
*/
|
||||
public function test_email_certificates_others() {
|
||||
global $CFG;
|
||||
global $CFG, $DB;
|
||||
|
||||
// Create a course.
|
||||
$course = $this->getDataGenerator()->create_course();
|
||||
|
@ -206,9 +278,25 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
|
|||
$this->getDataGenerator()->enrol_user($user2->id, $course->id);
|
||||
|
||||
// Create a custom certificate.
|
||||
$this->getDataGenerator()->create_module('customcert', array('course' => $course->id,
|
||||
$customcert = $this->getDataGenerator()->create_module('customcert', array('course' => $course->id,
|
||||
'emailothers' => 'testcustomcert@example.com, doo@dah'));
|
||||
|
||||
// Create template object.
|
||||
$template = new stdClass();
|
||||
$template->id = $customcert->templateid;
|
||||
$template->name = 'A template';
|
||||
$template->contextid = context_course::instance($course->id)->id;
|
||||
$template = new \mod_customcert\template($template);
|
||||
|
||||
// Add a page to this template.
|
||||
$pageid = $template->add_page();
|
||||
|
||||
// Add an element to the page.
|
||||
$element = new stdClass();
|
||||
$element->pageid = $pageid;
|
||||
$element->name = 'Image';
|
||||
$DB->insert_record('customcert_elements', $element);
|
||||
|
||||
// Run the task.
|
||||
$sink = $this->redirectEmails();
|
||||
$task = new \mod_customcert\task\email_certificate_task();
|
||||
|
@ -242,7 +330,23 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
|
|||
$this->getDataGenerator()->enrol_user($user1->id, $course->id);
|
||||
|
||||
// Create a custom certificate.
|
||||
$this->getDataGenerator()->create_module('customcert', array('course' => $course->id, 'emailstudents' => 1));
|
||||
$customcert = $this->getDataGenerator()->create_module('customcert', ['course' => $course->id, 'emailstudents' => 1]);
|
||||
|
||||
// Create template object.
|
||||
$template = new stdClass();
|
||||
$template->id = $customcert->templateid;
|
||||
$template->name = 'A template';
|
||||
$template->contextid = context_course::instance($course->id)->id;
|
||||
$template = new \mod_customcert\template($template);
|
||||
|
||||
// Add a page to this template.
|
||||
$pageid = $template->add_page();
|
||||
|
||||
// Add an element to the page.
|
||||
$element = new stdClass();
|
||||
$element->pageid = $pageid;
|
||||
$element->name = 'Image';
|
||||
$DB->insert_record('customcert_elements', $element);
|
||||
|
||||
// Remove the permission for the user to view the certificate.
|
||||
assign_capability('mod/customcert:view', CAP_PROHIBIT, $roleids['student'], \context_course::instance($course->id));
|
||||
|
@ -280,9 +384,25 @@ class mod_customcert_task_email_certificate_task_testcase extends advanced_testc
|
|||
$this->getDataGenerator()->enrol_user($user1->id, $course->id);
|
||||
|
||||
// Create a custom certificate.
|
||||
$this->getDataGenerator()->create_module('customcert', array('course' => $course->id, 'emailstudents' => 1,
|
||||
$customcert = $this->getDataGenerator()->create_module('customcert', array('course' => $course->id, 'emailstudents' => 1,
|
||||
'requiredtime' => '60'));
|
||||
|
||||
// Create template object.
|
||||
$template = new stdClass();
|
||||
$template->id = $customcert->templateid;
|
||||
$template->name = 'A template';
|
||||
$template->contextid = context_course::instance($course->id)->id;
|
||||
$template = new \mod_customcert\template($template);
|
||||
|
||||
// Add a page to this template.
|
||||
$pageid = $template->add_page();
|
||||
|
||||
// Add an element to the page.
|
||||
$element = new stdClass();
|
||||
$element->pageid = $pageid;
|
||||
$element->name = 'Image';
|
||||
$DB->insert_record('customcert_elements', $element);
|
||||
|
||||
// Run the task.
|
||||
$sink = $this->redirectEmails();
|
||||
$task = new \mod_customcert\task\email_certificate_task();
|
||||
|
|
|
@ -24,10 +24,10 @@
|
|||
|
||||
defined('MOODLE_INTERNAL') || die('Direct access to this script is forbidden.');
|
||||
|
||||
$plugin->version = 2018120302; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->version = 2018120307; // The current module version (Date: YYYYMMDDXX).
|
||||
$plugin->requires = 2018120300; // Requires this Moodle version (3.6).
|
||||
$plugin->cron = 0; // Period for cron to check this module (secs).
|
||||
$plugin->component = 'mod_customcert';
|
||||
|
||||
$plugin->maturity = MATURITY_STABLE;
|
||||
$plugin->release = "3.6.2"; // User-friendly version number.
|
||||
$plugin->release = "3.6.7"; // User-friendly version number.
|
||||
|
|
4
view.php
4
view.php
|
@ -139,7 +139,7 @@ if (!$downloadown && !$downloadissue) {
|
|||
if ($canreceive) {
|
||||
$linkname = get_string('getcustomcert', 'customcert');
|
||||
$link = new moodle_url('/mod/customcert/view.php', array('id' => $cm->id, 'downloadown' => true));
|
||||
$downloadbutton = new single_button($link, $linkname, 'post', true);
|
||||
$downloadbutton = new single_button($link, $linkname, 'get', true);
|
||||
$downloadbutton->class .= ' m-b-1'; // Seems a bit hackish, ahem.
|
||||
$downloadbutton = $OUTPUT->render($downloadbutton);
|
||||
}
|
||||
|
@ -179,6 +179,8 @@ if (!$downloadown && !$downloadissue) {
|
|||
redirect(new moodle_url('/mod/customcert/view.php', array('id' => $cm->id)));
|
||||
}
|
||||
|
||||
\core\session\manager::write_close();
|
||||
|
||||
// Now we want to generate the PDF.
|
||||
$template = new \mod_customcert\template($template);
|
||||
$template->generate_pdf(false, $userid);
|
||||
|
|
|
@ -80,24 +80,14 @@ Y.extend(Rearrange, Y.Base, {
|
|||
this.elements = params[2];
|
||||
|
||||
// Set the PDF dimensions.
|
||||
this.pdfx = Y.one('#pdf').getX();
|
||||
this.pdfy = Y.one('#pdf').getY();
|
||||
this.pdfwidth = parseFloat(Y.one('#pdf').getComputedStyle('width'));
|
||||
this.pdfheight = parseFloat(Y.one('#pdf').getComputedStyle('height'));
|
||||
this.setPdfDimensions();
|
||||
|
||||
// Set the boundaries.
|
||||
this.pdfleftboundary = this.pdfx;
|
||||
if (this.page.leftmargin) {
|
||||
this.pdfleftboundary += parseInt(this.page.leftmargin * this.pixelsinmm, 10);
|
||||
}
|
||||
|
||||
this.pdfrightboundary = this.pdfx + this.pdfwidth;
|
||||
if (this.page.rightmargin) {
|
||||
this.pdfrightboundary -= parseInt(this.page.rightmargin * this.pixelsinmm, 10);
|
||||
}
|
||||
this.setBoundaries();
|
||||
|
||||
this.setpositions();
|
||||
this.createevents();
|
||||
window.addEventListener("resize", this.checkWindownResize.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -130,6 +120,40 @@ Y.extend(Rearrange, Y.Base, {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the PDF dimensions.
|
||||
*/
|
||||
setPdfDimensions: function() {
|
||||
this.pdfx = Y.one('#pdf').getX();
|
||||
this.pdfy = Y.one('#pdf').getY();
|
||||
this.pdfwidth = parseFloat(Y.one('#pdf').getComputedStyle('width'));
|
||||
this.pdfheight = parseFloat(Y.one('#pdf').getComputedStyle('height'));
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the boundaries.
|
||||
*/
|
||||
setBoundaries: function() {
|
||||
this.pdfleftboundary = this.pdfx;
|
||||
if (this.page.leftmargin) {
|
||||
this.pdfleftboundary += parseInt(this.page.leftmargin * this.pixelsinmm, 10);
|
||||
}
|
||||
|
||||
this.pdfrightboundary = this.pdfx + this.pdfwidth;
|
||||
if (this.page.rightmargin) {
|
||||
this.pdfrightboundary -= parseInt(this.page.rightmargin * this.pixelsinmm, 10);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check browser resize and reset position.
|
||||
*/
|
||||
checkWindownResize: function() {
|
||||
this.setPdfDimensions();
|
||||
this.setBoundaries();
|
||||
this.setpositions();
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates the JS events for changing element positions.
|
||||
*/
|
||||
|
|
|
@ -1 +1 @@
|
|||
YUI.add("moodle-mod_customcert-rearrange",function(e,t){var n=function(){n.superclass.constructor.apply(this,[arguments])};e.extend(n,e.Base,{templateid:0,page:[],elements:[],pdfx:0,pdfy:0,pdfwidth:0,pdfheight:0,elementxy:0,pdfleftboundary:0,pdfrightboundary:0,pixelsinmm:3.779527559055,initializer:function(t){this.templateid=t[0],this.page=t[1],this.elements=t[2],this.pdfx=e.one("#pdf").getX(),this.pdfy=e.one("#pdf").getY(),this.pdfwidth=parseFloat(e.one("#pdf").getComputedStyle("width")),this.pdfheight=parseFloat(e.one("#pdf").getComputedStyle("height")),this.pdfleftboundary=this.pdfx,this.page.leftmargin&&(this.pdfleftboundary+=parseInt(this.page.leftmargin*this.pixelsinmm,10)),this.pdfrightboundary=this.pdfx+this.pdfwidth,this.page.rightmargin&&(this.pdfrightboundary-=parseInt(this.page.rightmargin*this.pixelsinmm,10)),this.setpositions(),this.createevents()},setpositions:function(){for(var t in this.elements){var n=this.elements[t],r=this.pdfx+n.posx*this.pixelsinmm,i=this.pdfy+n.posy*this.pixelsinmm,s=parseFloat(e.one("#element-"+n.id).getComputedStyle("width")),o=n.width*this.pixelsinmm;o&&s>o&&(s=o);switch(n.refpoint){case"1":r-=s/2;break;case"2":r=r-s+2}e.one("#element-"+n.id).setX(r),e.one("#element-"+n.id).setY(i)}},createevents:function(){e.one(".savepositionsbtn [type=submit]").on("click",function(e){this.savepositions(e)},this),e.one(".applypositionsbtn [type=submit]").on("click",function(e){this.savepositions(e),e.preventDefault()},this);var t=new e.DD.Delegate({container:"#pdf",nodes:".element"});t.on("drag:start",function(){var e=t.get("currentNode");this.elementxy=e.getXY()},this),t.on("drag:end",function(){var e=t.get("currentNode");this.isoutofbounds(e)&&e.setXY(this.elementxy)},this)},isoutofbounds:function(e){var t=parseFloat(e.getComputedStyle("width")),n=parseFloat(e.getComputedStyle("height")),r=e.getX(),i=r+t,s=e.getY(),o=s+n;return r<this.pdfleftboundary||i>this.pdfrightboundary?!0:s<this.pdfy||o>this.pdfy+this.pdfheight?!0:!1},savepositions:function(t){var n={tid:this.templateid,values:[]};for(var r in this.elements){var i=this.elements[r],s=e.one("#element-"+i.id),o=s.getX()-this.pdfx,u=s.getY()-this.pdfy,a=s.getData("refpoint"),f=parseFloat(s.getComputedStyle("width"));switch(a){case"1":o+=f/2;break;case"2":o+=f}n.values.push({id:i.id,posx:Math.round(parseFloat(o/this.pixelsinmm)),posy:Math.round(parseFloat(u/this.pixelsinmm))})}n.values=JSON.stringify(n.values),e.io(M.cfg.wwwroot+"/mod/customcert/ajax.php",{method:"POST",data:n,on:{failure:function(e,t){this.ajaxfailure(t)},success:function(){var e=t.currentTarget.ancestor("form",!0),n=e.getAttribute("action"),r=e.one("[name=pid]");if(r){var i=r.get("value");window.location=n+"?pid="+i}else{var s=e.one("[name=tid]").get("value");window.location=n+"?tid="+s}}},context:this}),t.preventDefault()},ajaxfailure:function(e){var t={name:e.status+" "+e.statusText,message:e.responseText};return new M.core.exception(t)}}),e.namespace("M.mod_customcert.rearrange").init=function(e,t,r){new n(e,t,r)}},"@VERSION@",{requires:["dd-delegate","dd-drag"]});
|
||||
YUI.add("moodle-mod_customcert-rearrange",function(e,t){var n=function(){n.superclass.constructor.apply(this,[arguments])};e.extend(n,e.Base,{templateid:0,page:[],elements:[],pdfx:0,pdfy:0,pdfwidth:0,pdfheight:0,elementxy:0,pdfleftboundary:0,pdfrightboundary:0,pixelsinmm:3.779527559055,initializer:function(e){this.templateid=e[0],this.page=e[1],this.elements=e[2],this.setPdfDimensions(),this.setBoundaries(),this.setpositions(),this.createevents(),window.addEventListener("resize",this.checkWindownResize.bind(this))},setpositions:function(){for(var t in this.elements){var n=this.elements[t],r=this.pdfx+n.posx*this.pixelsinmm,i=this.pdfy+n.posy*this.pixelsinmm,s=parseFloat(e.one("#element-"+n.id).getComputedStyle("width")),o=n.width*this.pixelsinmm;o&&s>o&&(s=o);switch(n.refpoint){case"1":r-=s/2;break;case"2":r=r-s+2}e.one("#element-"+n.id).setX(r),e.one("#element-"+n.id).setY(i)}},setPdfDimensions:function(){this.pdfx=e.one("#pdf").getX(),this.pdfy=e.one("#pdf").getY(),this.pdfwidth=parseFloat(e.one("#pdf").getComputedStyle("width")),this.pdfheight=parseFloat(e.one("#pdf").getComputedStyle("height"))},setBoundaries:function(){this.pdfleftboundary=this.pdfx,this.page.leftmargin&&(this.pdfleftboundary+=parseInt(this.page.leftmargin*this.pixelsinmm,10)),this.pdfrightboundary=this.pdfx+this.pdfwidth,this.page.rightmargin&&(this.pdfrightboundary-=parseInt(this.page.rightmargin*this.pixelsinmm,10))},checkWindownResize:function(){this.setPdfDimensions(),this.setBoundaries(),this.setpositions()},createevents:function(){e.one(".savepositionsbtn [type=submit]").on("click",function(e){this.savepositions(e)},this),e.one(".applypositionsbtn [type=submit]").on("click",function(e){this.savepositions(e),e.preventDefault()},this);var t=new e.DD.Delegate({container:"#pdf",nodes:".element"});t.on("drag:start",function(){var e=t.get("currentNode");this.elementxy=e.getXY()},this),t.on("drag:end",function(){var e=t.get("currentNode");this.isoutofbounds(e)&&e.setXY(this.elementxy)},this)},isoutofbounds:function(e){var t=parseFloat(e.getComputedStyle("width")),n=parseFloat(e.getComputedStyle("height")),r=e.getX(),i=r+t,s=e.getY(),o=s+n;return r<this.pdfleftboundary||i>this.pdfrightboundary?!0:s<this.pdfy||o>this.pdfy+this.pdfheight?!0:!1},savepositions:function(t){var n={tid:this.templateid,values:[]};for(var r in this.elements){var i=this.elements[r],s=e.one("#element-"+i.id),o=s.getX()-this.pdfx,u=s.getY()-this.pdfy,a=s.getData("refpoint"),f=parseFloat(s.getComputedStyle("width"));switch(a){case"1":o+=f/2;break;case"2":o+=f}n.values.push({id:i.id,posx:Math.round(parseFloat(o/this.pixelsinmm)),posy:Math.round(parseFloat(u/this.pixelsinmm))})}n.values=JSON.stringify(n.values),e.io(M.cfg.wwwroot+"/mod/customcert/ajax.php",{method:"POST",data:n,on:{failure:function(e,t){this.ajaxfailure(t)},success:function(){var e=t.currentTarget.ancestor("form",!0),n=e.getAttribute("action"),r=e.one("[name=pid]");if(r){var i=r.get("value");window.location=n+"?pid="+i}else{var s=e.one("[name=tid]").get("value");window.location=n+"?tid="+s}}},context:this}),t.preventDefault()},ajaxfailure:function(e){var t={name:e.status+" "+e.statusText,message:e.responseText};return new M.core.exception(t)}}),e.namespace("M.mod_customcert.rearrange").init=function(e,t,r){new n(e,t,r)}},"@VERSION@",{requires:["dd-delegate","dd-drag"]});
|
||||
|
|
|
@ -80,24 +80,14 @@ Y.extend(Rearrange, Y.Base, {
|
|||
this.elements = params[2];
|
||||
|
||||
// Set the PDF dimensions.
|
||||
this.pdfx = Y.one('#pdf').getX();
|
||||
this.pdfy = Y.one('#pdf').getY();
|
||||
this.pdfwidth = parseFloat(Y.one('#pdf').getComputedStyle('width'));
|
||||
this.pdfheight = parseFloat(Y.one('#pdf').getComputedStyle('height'));
|
||||
this.setPdfDimensions();
|
||||
|
||||
// Set the boundaries.
|
||||
this.pdfleftboundary = this.pdfx;
|
||||
if (this.page.leftmargin) {
|
||||
this.pdfleftboundary += parseInt(this.page.leftmargin * this.pixelsinmm, 10);
|
||||
}
|
||||
|
||||
this.pdfrightboundary = this.pdfx + this.pdfwidth;
|
||||
if (this.page.rightmargin) {
|
||||
this.pdfrightboundary -= parseInt(this.page.rightmargin * this.pixelsinmm, 10);
|
||||
}
|
||||
this.setBoundaries();
|
||||
|
||||
this.setpositions();
|
||||
this.createevents();
|
||||
window.addEventListener("resize", this.checkWindownResize.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -130,6 +120,40 @@ Y.extend(Rearrange, Y.Base, {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the PDF dimensions.
|
||||
*/
|
||||
setPdfDimensions: function() {
|
||||
this.pdfx = Y.one('#pdf').getX();
|
||||
this.pdfy = Y.one('#pdf').getY();
|
||||
this.pdfwidth = parseFloat(Y.one('#pdf').getComputedStyle('width'));
|
||||
this.pdfheight = parseFloat(Y.one('#pdf').getComputedStyle('height'));
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the boundaries.
|
||||
*/
|
||||
setBoundaries: function() {
|
||||
this.pdfleftboundary = this.pdfx;
|
||||
if (this.page.leftmargin) {
|
||||
this.pdfleftboundary += parseInt(this.page.leftmargin * this.pixelsinmm, 10);
|
||||
}
|
||||
|
||||
this.pdfrightboundary = this.pdfx + this.pdfwidth;
|
||||
if (this.page.rightmargin) {
|
||||
this.pdfrightboundary -= parseInt(this.page.rightmargin * this.pixelsinmm, 10);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check browser resize and reset position.
|
||||
*/
|
||||
checkWindownResize: function() {
|
||||
this.setPdfDimensions();
|
||||
this.setBoundaries();
|
||||
this.setpositions();
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates the JS events for changing element positions.
|
||||
*/
|
||||
|
|
50
yui/src/rearrange/js/rearrange.js
vendored
50
yui/src/rearrange/js/rearrange.js
vendored
|
@ -78,24 +78,14 @@ Y.extend(Rearrange, Y.Base, {
|
|||
this.elements = params[2];
|
||||
|
||||
// Set the PDF dimensions.
|
||||
this.pdfx = Y.one('#pdf').getX();
|
||||
this.pdfy = Y.one('#pdf').getY();
|
||||
this.pdfwidth = parseFloat(Y.one('#pdf').getComputedStyle('width'));
|
||||
this.pdfheight = parseFloat(Y.one('#pdf').getComputedStyle('height'));
|
||||
this.setPdfDimensions();
|
||||
|
||||
// Set the boundaries.
|
||||
this.pdfleftboundary = this.pdfx;
|
||||
if (this.page.leftmargin) {
|
||||
this.pdfleftboundary += parseInt(this.page.leftmargin * this.pixelsinmm, 10);
|
||||
}
|
||||
|
||||
this.pdfrightboundary = this.pdfx + this.pdfwidth;
|
||||
if (this.page.rightmargin) {
|
||||
this.pdfrightboundary -= parseInt(this.page.rightmargin * this.pixelsinmm, 10);
|
||||
}
|
||||
this.setBoundaries();
|
||||
|
||||
this.setpositions();
|
||||
this.createevents();
|
||||
window.addEventListener("resize", this.checkWindownResize.bind(this));
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -128,6 +118,40 @@ Y.extend(Rearrange, Y.Base, {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the PDF dimensions.
|
||||
*/
|
||||
setPdfDimensions: function() {
|
||||
this.pdfx = Y.one('#pdf').getX();
|
||||
this.pdfy = Y.one('#pdf').getY();
|
||||
this.pdfwidth = parseFloat(Y.one('#pdf').getComputedStyle('width'));
|
||||
this.pdfheight = parseFloat(Y.one('#pdf').getComputedStyle('height'));
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the boundaries.
|
||||
*/
|
||||
setBoundaries: function() {
|
||||
this.pdfleftboundary = this.pdfx;
|
||||
if (this.page.leftmargin) {
|
||||
this.pdfleftboundary += parseInt(this.page.leftmargin * this.pixelsinmm, 10);
|
||||
}
|
||||
|
||||
this.pdfrightboundary = this.pdfx + this.pdfwidth;
|
||||
if (this.page.rightmargin) {
|
||||
this.pdfrightboundary -= parseInt(this.page.rightmargin * this.pixelsinmm, 10);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check browser resize and reset position.
|
||||
*/
|
||||
checkWindownResize: function() {
|
||||
this.setPdfDimensions();
|
||||
this.setBoundaries();
|
||||
this.setpositions();
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates the JS events for changing element positions.
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue