Added drag & drop feature to rearrange elements
This commit is contained in:
parent
58d7312d9e
commit
9998fa2b4a
22 changed files with 854 additions and 6 deletions
|
@ -238,8 +238,12 @@ class mod_customcert_edit_form extends moodleform {
|
|||
$row->cells[] = $icons;
|
||||
$table->data[] = $row;
|
||||
}
|
||||
// Create link to order the elements.
|
||||
$link = html_writer::link(new moodle_url('/mod/customcert/rearrange.php', array('id' => $page->id)),
|
||||
get_string('rearrangeelements', 'customcert'));
|
||||
// Add the table to the form.
|
||||
$mform->addElement('static', 'elements_' . $page->id, get_string('elements', 'customcert'), html_writer::table($table));
|
||||
$mform->addElement('static', 'elements_' . $page->id, get_string('elements', 'customcert'), html_writer::table($table)
|
||||
. html_writer::tag( 'div', $link, array('style' => 'text-align:right')));
|
||||
$mform->addHelpButton('elements_' . $page->id, 'elements', 'customcert');
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,16 @@ class customcert_element_border extends customcert_element_base {
|
|||
$pdf->Line(0, 0, 0, $pdf->getPageHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the element in html.
|
||||
*
|
||||
* This function is used to render the element when we are using the
|
||||
* drag and drop interface to position it.
|
||||
*/
|
||||
public function render_html() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs validation on the element values.
|
||||
*
|
||||
|
|
|
@ -40,4 +40,18 @@ class customcert_element_categoryname extends customcert_element_base {
|
|||
|
||||
parent::render_content($pdf, $categoryname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the element in html.
|
||||
*
|
||||
* This function is used to render the element when we are using the
|
||||
* drag and drop interface to position it.
|
||||
*/
|
||||
public function render_html() {
|
||||
global $DB, $COURSE;
|
||||
|
||||
$categoryname = $DB->get_field('course_categories', 'name', array('id' => $COURSE->category), MUST_EXIST);
|
||||
|
||||
return parent::render_html_content($categoryname);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,4 +48,16 @@ class customcert_element_code extends customcert_element_base {
|
|||
|
||||
parent::render_content($pdf, $code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the element in html.
|
||||
*
|
||||
* This function is used to render the element when we are using the
|
||||
* drag and drop interface to position it.
|
||||
*/
|
||||
public function render_html() {
|
||||
$code = customcert_generate_code();
|
||||
|
||||
return parent::render_html_content($code);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,4 +38,16 @@ class customcert_element_coursename extends customcert_element_base {
|
|||
|
||||
parent::render_content($pdf, $COURSE->fullname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the element in html.
|
||||
*
|
||||
* This function is used to render the element when we are using the
|
||||
* drag and drop interface to position it.
|
||||
*/
|
||||
public function render_html() {
|
||||
global $COURSE;
|
||||
|
||||
return parent::render_html_content($COURSE->fullname);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -152,6 +152,44 @@ class customcert_element_date extends customcert_element_base {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the element in html.
|
||||
*
|
||||
* This function is used to render the element when we are using the
|
||||
* drag and drop interface to position it.
|
||||
*/
|
||||
public function render_html() {
|
||||
// If there is no element data, we have nothing to display.
|
||||
if (empty($this->element->data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Decode the information stored in the database.
|
||||
$dateinfo = json_decode($this->element->data);
|
||||
$dateformat = $dateinfo->dateformat;
|
||||
|
||||
$date = time();
|
||||
switch ($dateformat) {
|
||||
case 1:
|
||||
$certificatedate = userdate($date, '%B %d, %Y');
|
||||
break;
|
||||
case 2:
|
||||
$suffix = $this->get_ordinal_number_suffix(userdate($date, '%d'));
|
||||
$certificatedate = userdate($date, '%B %d' . $suffix . ', %Y');
|
||||
break;
|
||||
case 3:
|
||||
$certificatedate = userdate($date, '%d %B %Y');
|
||||
break;
|
||||
case 4:
|
||||
$certificatedate = userdate($date, '%B %Y');
|
||||
break;
|
||||
default:
|
||||
$certificatedate = userdate($date, get_string('strftimedate', 'langconfig'));
|
||||
}
|
||||
|
||||
return parent::render_html_content($certificatedate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data on the form when editing an element.
|
||||
*
|
||||
|
|
|
@ -183,7 +183,8 @@ abstract class customcert_element_base {
|
|||
* @param string $content the content to render
|
||||
*/
|
||||
public function render_content($pdf, $content) {
|
||||
$this->set_font($pdf);
|
||||
list($font, $attr) = $this->get_font();
|
||||
$pdf->setFont($font, $attr, $this->element->size);
|
||||
$fontcolour = TCPDF_COLORS::convertHTMLColorToDec($this->element->colour, $fontcolour);
|
||||
$pdf->SetTextColor($fontcolour['R'], $fontcolour['G'], $fontcolour['B']);
|
||||
|
||||
|
@ -226,6 +227,35 @@ abstract class customcert_element_base {
|
|||
$pdf->writeHTMLCell($w, 0, $x, $y, $content, 0, 0, false, true, $align);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the element in html.
|
||||
*
|
||||
* Must be overridden.
|
||||
*
|
||||
* This function is used to render the element when we are using the
|
||||
* drag and drop interface to position it.
|
||||
*/
|
||||
public abstract function render_html();
|
||||
|
||||
/**
|
||||
* Common behaviour for rendering specified content on the drag and drop page.
|
||||
*
|
||||
* @param string $content the content to render
|
||||
* @return string the html
|
||||
*/
|
||||
public function render_html_content($content) {
|
||||
list($font, $attr) = $this->get_font();
|
||||
$fontstyle = 'font-family: ' . $font;
|
||||
if (strpos($attr, 'B') !== false) {
|
||||
$fontstyle .= ': font-weight: bold';
|
||||
}
|
||||
if (strpos($attr, 'I') !== false) {
|
||||
$fontstyle .= ': font-style: italic';
|
||||
}
|
||||
$style = $fontstyle . '; color: ' . $this->element->colour . '; font-size: ' . $this->element->size . 'pt';
|
||||
return html_writer::tag('span', $content, array('style' => $style));
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles deleting any data this element may have introduced.
|
||||
* Can be overridden if more functionality is needed.
|
||||
|
@ -379,11 +409,11 @@ abstract class customcert_element_base {
|
|||
}
|
||||
|
||||
/**
|
||||
* Sets the font for the element.
|
||||
* Returns the font used for this element.
|
||||
*
|
||||
* @param pdf $pdf the pdf object
|
||||
* @return array the font and font attributes
|
||||
*/
|
||||
public function set_font($pdf) {
|
||||
public function get_font() {
|
||||
// Variable for the font.
|
||||
$font = $this->element->font;
|
||||
// Get the last two characters of the font name.
|
||||
|
@ -408,7 +438,7 @@ abstract class customcert_element_base {
|
|||
$font = substr($font, 0, -1);
|
||||
$attr .= 'B';
|
||||
}
|
||||
$pdf->setFont($font, $attr, $this->element->size);
|
||||
return array($font, $attr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -106,6 +106,29 @@ class customcert_element_grade extends customcert_element_base {
|
|||
parent::render_content($pdf, $grade);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the element in html.
|
||||
*
|
||||
* This function is used to render the element when we are using the
|
||||
* drag and drop interface to position it.
|
||||
*/
|
||||
public function render_html() {
|
||||
global $COURSE;
|
||||
|
||||
// If there is no element data, we have nothing to display.
|
||||
if (empty($this->element->data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Decode the information stored in the database.
|
||||
$gradeinfo = json_decode($this->element->data);
|
||||
|
||||
$courseitem = grade_item::fetch_course_item($COURSE->id);
|
||||
$grade = grade_format_gradevalue('100', $courseitem, true, $gradeinfo->gradeformat, 2);
|
||||
|
||||
return parent::render_html_content($grade);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data on the form when editing an element.
|
||||
*
|
||||
|
|
|
@ -78,6 +78,28 @@ class customcert_element_gradeitemname extends customcert_element_base {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the element in html.
|
||||
*
|
||||
* This function is used to render the element when we are using the
|
||||
* drag and drop interface to position it.
|
||||
*/
|
||||
public function render_html() {
|
||||
global $DB;
|
||||
|
||||
// Check that the grade item is not empty.
|
||||
if (!empty($this->element->data)) {
|
||||
// Get the course module information.
|
||||
$cm = $DB->get_record('course_modules', array('id' => $this->element->data), '*', MUST_EXIST);
|
||||
$module = $DB->get_record('modules', array('id' => $cm->module), '*', MUST_EXIST);
|
||||
|
||||
// Get the name of the item.
|
||||
$itemname = $DB->get_field($module->name, 'name', array('id' => $cm->instance), MUST_EXIST);
|
||||
|
||||
return parent::render_html_content($itemname);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data on the form when editing an element.
|
||||
*
|
||||
|
|
|
@ -151,6 +151,49 @@ class customcert_element_image extends customcert_element_base {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the element in html.
|
||||
*
|
||||
* This function is used to render the element when we are using the
|
||||
* drag and drop interface to position it.
|
||||
*/
|
||||
public function render_html() {
|
||||
// If there is no element data, we have nothing to display.
|
||||
if (empty($this->element->data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$imageinfo = json_decode($this->element->data);
|
||||
|
||||
// Get the image.
|
||||
$fs = get_file_storage();
|
||||
if ($file = $fs->get_file_by_hash($imageinfo->pathnamehash)) {
|
||||
$url = moodle_url::make_pluginfile_url($file->get_contextid(), 'mod_customcert', 'image', $file->get_itemid(),
|
||||
$file->get_filepath(), $file->get_filename());
|
||||
$fileimageinfo = $file->get_imageinfo();
|
||||
$whratio = $fileimageinfo['width'] / $fileimageinfo['height'];
|
||||
// The size of the images to use in the CSS style.
|
||||
$style = '';
|
||||
if ($imageinfo->width === 0 && $imageinfo->height === 0) {
|
||||
$style .= 'width: ' . $fileimageinfo['width'] . 'px; ';
|
||||
$style .= 'height: ' . $fileimageinfo['height'] . 'px';
|
||||
} else if ($imageinfo->width === 0) { // Then the height must be set.
|
||||
// We must get the width based on the height to keep the ratio.
|
||||
$style .= 'width: ' . ($imageinfo->height * $whratio) . 'mm; ';
|
||||
$style .= 'height: ' . $imageinfo->height . 'mm';
|
||||
} else if ($imageinfo->height === 0) { // Then the width must be set.
|
||||
$style .= 'width: ' . $imageinfo->width . 'mm; ';
|
||||
// We must get the height based on the width to keep the ratio.
|
||||
$style .= 'height: ' . ($imageinfo->width / $whratio) . 'mm';
|
||||
} else { // Must both be set.
|
||||
$style .= 'width: ' . $imageinfo->width . 'mm; ';
|
||||
$style .= 'height: ' . $imageinfo->height . 'mm';
|
||||
}
|
||||
|
||||
return html_writer::tag('img', '', array('src' => $url, 'style' => $style));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data on the form when editing an element.
|
||||
*
|
||||
|
|
|
@ -38,4 +38,16 @@ class customcert_element_studentname extends customcert_element_base {
|
|||
|
||||
parent::render_content($pdf, fullname($USER));
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the element in html.
|
||||
*
|
||||
* This function is used to render the element when we are using the
|
||||
* drag and drop interface to position it.
|
||||
*/
|
||||
public function render_html() {
|
||||
global $USER;
|
||||
|
||||
return parent::render_html_content(fullname($USER));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,6 +66,21 @@ class customcert_element_teachername extends customcert_element_base {
|
|||
parent::render_content($pdf, $teachername);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the element in html.
|
||||
*
|
||||
* This function is used to render the element when we are using the
|
||||
* drag and drop interface to position it.
|
||||
*/
|
||||
public function render_html() {
|
||||
global $DB;
|
||||
|
||||
$teacher = $DB->get_record('user', array('id' => $this->element->data));
|
||||
$teachername = fullname($teacher);
|
||||
|
||||
return parent::render_html_content($teachername);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to return the teachers for this course.
|
||||
*
|
||||
|
|
|
@ -61,6 +61,16 @@ class customcert_element_text extends customcert_element_base {
|
|||
parent::render_content($pdf, $this->element->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the element in html.
|
||||
*
|
||||
* This function is used to render the element when we are using the
|
||||
* drag and drop interface to position it.
|
||||
*/
|
||||
public function render_html() {
|
||||
return parent::render_html_content($this->element->data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data on the form when editing an element.
|
||||
*
|
||||
|
|
|
@ -106,6 +106,30 @@ class customcert_element_userfield extends customcert_element_base {
|
|||
parent::render_content($pdf, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the element in html.
|
||||
*
|
||||
* This function is used to render the element when we are using the
|
||||
* drag and drop interface to position it.
|
||||
*/
|
||||
public function render_html() {
|
||||
global $DB, $USER;
|
||||
|
||||
// The user field to display.
|
||||
$field = $this->element->data;
|
||||
// The value to display on the PDF.
|
||||
$value = '';
|
||||
if (is_number($field)) { // Must be a custom user profile field.
|
||||
if ($field = $DB->get_record('user_info_field', array('id' => $field))) {
|
||||
$value = $USER->profile[$field->shortname];
|
||||
}
|
||||
} else if (!empty($USER->$field)) { // Field in the user table.
|
||||
$value = $USER->$field;
|
||||
}
|
||||
|
||||
return parent::render_html_content($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data on the form when editing an element.
|
||||
*
|
||||
|
|
|
@ -30,6 +30,7 @@ $string['aligncenter'] = 'Center';
|
|||
$string['alignleft'] = 'Left align';
|
||||
$string['alignnone'] = 'No alignment';
|
||||
$string['alignright'] = 'Right align';
|
||||
$string['applypositions'] = 'Save positions & continue';
|
||||
$string['awardedto'] = 'Awarded to';
|
||||
$string['code'] = 'Code';
|
||||
$string['copy'] = 'Copy';
|
||||
|
@ -97,6 +98,8 @@ $string['posx'] = 'Position X';
|
|||
$string['posx_help'] = 'This is the position in mm from the top left corner you wish the element\'s reference point to locate in the x direction.';
|
||||
$string['posy'] = 'Postion Y';
|
||||
$string['posy_help'] = 'This is the position in mm from the top left corner you wish the element\'s reference point to locate in the y direction.';
|
||||
$string['rearrangeelements'] = 'Rearrange elements';
|
||||
$string['rearrangeelementsheading'] = 'Drag and drop elements to change where they are positioned on the certificate.';
|
||||
$string['receiveddate'] = 'Received date';
|
||||
$string['refpoint'] = 'Reference point location';
|
||||
$string['refpoint_help'] = 'This specifies which location of the element to be located at position X and position Y.';
|
||||
|
@ -104,6 +107,7 @@ $string['replacetemplate'] = 'Replace';
|
|||
$string['report'] = 'Report';
|
||||
$string['save'] = 'Save';
|
||||
$string['savechangespreview'] = 'Save changes and preview';
|
||||
$string['savepositions'] = 'Save positions';
|
||||
$string['savetemplate'] = 'Save template';
|
||||
$string['setprotection'] = 'Set protection';
|
||||
$string['setprotection_help'] = 'Choose the actions you wish to prevent users from performing on this certificate.';
|
||||
|
|
36
lib.php
36
lib.php
|
@ -226,6 +226,42 @@ function customcert_user_complete($course, $user, $mod, $customcert) {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serves certificate issues and other files.
|
||||
*
|
||||
* @param stdClass $course
|
||||
* @param stdClass $cm
|
||||
* @param context $context
|
||||
* @param string $filearea
|
||||
* @param array $args
|
||||
* @param bool $forcedownload
|
||||
* @return bool|nothing false if file not found, does not return anything if found - just send the file
|
||||
*/
|
||||
function customcert_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload) {
|
||||
global $CFG;
|
||||
|
||||
require_once($CFG->libdir . '/filelib.php');
|
||||
|
||||
// We are positioning the elements.
|
||||
if ($filearea === 'image') {
|
||||
if ($context->contextlevel == CONTEXT_MODULE) {
|
||||
require_login($course, false, $cm);
|
||||
} else if ($context->contextlevel == CONTEXT_SYSTEM && !has_capability('mod/certificate:manage', $context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$relativepath = implode('/', $args);
|
||||
$fullpath = '/' . $context->id . '/mod_customcert/image/' . $relativepath;
|
||||
|
||||
$fs = get_file_storage();
|
||||
if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
send_stored_file($file, 0, 0, $forcedownload);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @uses FEATURE_GROUPS
|
||||
* @uses FEATURE_GROUPINGS
|
||||
|
|
BIN
pix/dash.gif
Normal file
BIN
pix/dash.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 B |
BIN
pix/target.gif
Normal file
BIN
pix/target.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 56 B |
103
rearrange.php
Normal file
103
rearrange.php
Normal file
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
// This file is part of the customcert module for Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Handles position elements on the PDF via drag and drop.
|
||||
*
|
||||
* @package mod_customcert
|
||||
* @copyright 2013 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
require_once('../../config.php');
|
||||
require_once($CFG->dirroot . '/mod/customcert/locallib.php');
|
||||
|
||||
// The page of the customcert we are editing.
|
||||
$pid = required_param('id', PARAM_INT);
|
||||
|
||||
$page = $DB->get_record('customcert_pages', array('id' => $pid), '*', MUST_EXIST);
|
||||
$elements = $DB->get_records('customcert_elements', array('pageid' => $pid), 'sequence');
|
||||
$cm = get_coursemodule_from_instance('customcert', $page->customcertid, 0, false, MUST_EXIST);
|
||||
$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
|
||||
$context = context_module::instance($cm->id);
|
||||
|
||||
require_login($course, false, $cm);
|
||||
|
||||
require_capability('mod/customcert:manage', $context);
|
||||
|
||||
// Set the $PAGE settings.
|
||||
$PAGE->set_url(new moodle_url('/mod/customcert/rearrange.php', array('id' => $pid)));
|
||||
$PAGE->set_pagetype('mod-customcert-position');
|
||||
$PAGE->set_title(get_string('rearrangeelements', 'customcert'));
|
||||
$PAGE->set_heading($course->fullname);
|
||||
|
||||
// Include the JS we need.
|
||||
$module = array(
|
||||
'name' => 'mod_customcert',
|
||||
'fullpath' => '/mod/customcert/yui/src/rearrange.js',
|
||||
'requires' => array('dd-delegate', 'dd-drag')
|
||||
);
|
||||
$PAGE->requires->js_init_call('M.mod_customcert.rearrange.init', array($cm->id, $elements), false, $module);
|
||||
|
||||
// Create the buttons to save the position of the elements.
|
||||
$html = html_writer::start_tag('div', array('class' => 'buttons'));
|
||||
$html .= $OUTPUT->single_button(new moodle_url('/mod/customcert/edit.php', array('cmid' => $cm->id)),
|
||||
get_string('savepositions', 'customcert'), 'get', array('class' => 'savepositionsbtn'));
|
||||
$html .= $OUTPUT->single_button(new moodle_url('/mod/customcert/rearrange.php', array('id' => $pid)),
|
||||
get_string('applypositions', 'customcert'), 'get', array('class' => 'applypositionsbtn'));
|
||||
$html .= $OUTPUT->single_button(new moodle_url('/mod/customcert/edit.php', array('cmid' => $cm->id)),
|
||||
get_string('cancel'), 'get', array('class' => 'cancelbtn'));
|
||||
$html .= html_writer::end_tag('div');
|
||||
|
||||
$style = 'height: ' . $page->height . 'mm; line-height: normal;';
|
||||
if ($page->margin) {
|
||||
$style .= 'width: ' . ($page->width - $page->margin) . 'mm;';
|
||||
$style .= 'background-image: url(' . new moodle_url('/mod/customcert/pix/dash') . ');';
|
||||
$style .= 'background-repeat: repeat-y;';
|
||||
$style .= 'background-position-x: ' . ($page->width - $page->margin) . 'mm;';
|
||||
$style .= 'padding-right: ' . $page->margin . 'mm;';
|
||||
} else {
|
||||
$style .= 'width: ' . $page->width . 'mm;';
|
||||
}
|
||||
|
||||
// Create the div that represents the PDF.
|
||||
$html .= html_writer::start_tag('div', array('id' => 'pdf', 'style' => $style));
|
||||
if ($elements) {
|
||||
foreach ($elements as $element) {
|
||||
// Get an instance of the element class.
|
||||
if ($e = customcert_get_element_instance($element)) {
|
||||
switch ($element->refpoint) {
|
||||
case CUSTOMCERT_REF_POINT_TOPRIGHT:
|
||||
$class = 'element refpoint-right';
|
||||
break;
|
||||
case CUSTOMCERT_REF_POINT_TOPCENTER:
|
||||
$class = 'element refpoint-center';
|
||||
break;
|
||||
case CUSTOMCERT_REF_POINT_TOPLEFT:
|
||||
default:
|
||||
$class = 'element refpoint-left';
|
||||
}
|
||||
$html .= html_writer::tag('div', $e->render_html(), array('class' => $class, 'id' => 'element-' . $element->id));
|
||||
}
|
||||
}
|
||||
}
|
||||
$html .= html_writer::end_tag('div');
|
||||
|
||||
echo $OUTPUT->header();
|
||||
echo $OUTPUT->heading(get_string('editcustomcert', 'customcert'));
|
||||
echo $OUTPUT->heading(get_string('rearrangeelementsheading', 'customcert'), 4);
|
||||
echo $html;
|
||||
echo $OUTPUT->footer();
|
56
rest.php
Normal file
56
rest.php
Normal file
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
// This file is part of the customcert module for Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Handles AJAX requests for the customcert module.
|
||||
*
|
||||
* @package mod_customcert
|
||||
* @copyright 2013 Mark Nelson <markn@moodle.com>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
|
||||
if (!defined('AJAX_SCRIPT')) {
|
||||
define('AJAX_SCRIPT', true);
|
||||
}
|
||||
|
||||
require_once(__DIR__ . '/../../config.php');
|
||||
|
||||
$cmid = required_param('cmid', PARAM_INT);
|
||||
$values = required_param('values', PARAM_RAW);
|
||||
$values = json_decode($values);
|
||||
|
||||
$cm = get_coursemodule_from_id('customcert', $cmid, 0, false, MUST_EXIST);
|
||||
$course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
|
||||
$context = context_module::instance($cm->id);
|
||||
$elements = $DB->get_records_sql('SELECT * FROM {customcert_elements} e
|
||||
JOIN {customcert_pages} p ON e.pageid = p.id
|
||||
WHERE p.customcertid = ?', array($cm->instance));
|
||||
|
||||
// Check that the user is able to perform the change.
|
||||
require_login($course, false, $cm);
|
||||
require_capability('mod/customcert:manage', $context);
|
||||
|
||||
// Loop through the data
|
||||
foreach ($values as $value) {
|
||||
// if (array_key_exists($value->id, $elements)) {
|
||||
// Perform the update.
|
||||
$element = new stdClass();
|
||||
$element->id = $value->id;
|
||||
$element->posx = $value->posx;
|
||||
$element->posy = $value->posy;
|
||||
$DB->update_record('customcert_elements', $element);
|
||||
// }
|
||||
}
|
47
styles.css
47
styles.css
|
@ -10,3 +10,50 @@
|
|||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
#page-mod-customcert-position .savepositionsbtn,
|
||||
#page-mod-customcert-position .applypositionsbtn,
|
||||
#page-mod-customcert-position .cancelbtn {
|
||||
float:left
|
||||
}
|
||||
|
||||
#page-mod-customcert-position .element {
|
||||
display:inline-block;
|
||||
position: absolute;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
#page-mod-customcert-position .element:before {
|
||||
content: "";
|
||||
display: block;
|
||||
background-image: url([[pix:mod_customcert|target]]);
|
||||
background-repeat: no-repeat;
|
||||
width: 100%;
|
||||
height: 9px;
|
||||
float: left;
|
||||
}
|
||||
|
||||
#page-mod-customcert-position .element:hover {
|
||||
cursor:move;
|
||||
}
|
||||
|
||||
#page-mod-customcert-position .element.refpoint-left:before {
|
||||
background-position: left top;
|
||||
margin: -4px -5px -5px -4px;
|
||||
}
|
||||
|
||||
#page-mod-customcert-position .element.refpoint-center:before {
|
||||
background-position: center top;
|
||||
margin: -4px 0 -5px 0;
|
||||
}
|
||||
|
||||
#page-mod-customcert-position .element.refpoint-right:before {
|
||||
background-position: right top;
|
||||
margin: -4px -5px -5px 4px;
|
||||
}
|
||||
|
||||
#page-mod-customcert-position #pdf {
|
||||
clear:both;
|
||||
border-style:solid;
|
||||
border-width:1px;
|
||||
}
|
333
yui/src/rearrange.js
vendored
Normal file
333
yui/src/rearrange.js
vendored
Normal file
|
@ -0,0 +1,333 @@
|
|||
M.mod_customcert = {};
|
||||
|
||||
|
||||
M.mod_customcert.rearrange = {
|
||||
|
||||
/**
|
||||
* The course module id.
|
||||
*/
|
||||
cmid : 0,
|
||||
|
||||
/**
|
||||
* The custom certificate elements to display.
|
||||
*/
|
||||
elements : Array(),
|
||||
|
||||
/**
|
||||
* Store the X coordinates of the top left of the pdf div.
|
||||
*/
|
||||
pdfx : 0,
|
||||
|
||||
/**
|
||||
* Store the Y coordinates of the top left of the pdf div.
|
||||
*/
|
||||
pdfy : 0,
|
||||
|
||||
/**
|
||||
* Store the width of the pdf div.
|
||||
*/
|
||||
pdfwidth : 0,
|
||||
|
||||
/**
|
||||
* Store the height of the pdf div.
|
||||
*/
|
||||
pdfheight : 0,
|
||||
|
||||
/**
|
||||
* Store the location of the element before we move.
|
||||
*/
|
||||
elementxy : 0,
|
||||
|
||||
/**
|
||||
* The number of pixels in a mm.
|
||||
*/
|
||||
pixelsinmm : 3.779527559055, //'3.779528',
|
||||
|
||||
/**
|
||||
* Initialise.
|
||||
*
|
||||
* @param Y
|
||||
* @param elements
|
||||
*/
|
||||
init : function(Y, cmid, elements) {
|
||||
// Set the course module id.
|
||||
this.cmid = cmid;
|
||||
// Set the elements.
|
||||
this.elements = elements;
|
||||
|
||||
// Set the PDF dimensions.
|
||||
this.pdfx = Y.one('#pdf').getX();
|
||||
this.pdfy = Y.one('#pdf').getY();
|
||||
this.pdfwidth = parseFloat(Y.one('#pdf').getComputedStyle('width'), 10);
|
||||
this.pdfheight = parseFloat(Y.one('#pdf').getComputedStyle('height'), 10);
|
||||
|
||||
this.set_data(Y);
|
||||
this.set_positions(Y);
|
||||
this.create_events(Y);
|
||||
// this.set_positions(Y); // move here
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the additional data for the elements.
|
||||
*
|
||||
* @param Y
|
||||
*/
|
||||
set_data : function(Y) {
|
||||
// Go through the elements and set their reference points.
|
||||
for (var key in this.elements) {
|
||||
var element = this.elements[key];
|
||||
Y.one('#element-' + element['id']).setData('refpoint', element['refpoint']);
|
||||
Y.one('#element-' + element['id']).setData('width', element['width']);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the current position of the elements.
|
||||
*
|
||||
* @param Y
|
||||
*/
|
||||
set_positions : function(Y) {
|
||||
// Go through the elements and set their positions.
|
||||
for (var key in this.elements) {
|
||||
var element = this.elements[key];
|
||||
var posx = this.pdfx + element['posx'] * this.pixelsinmm;
|
||||
var posy = this.pdfy + element['posy'] * this.pixelsinmm;
|
||||
var nodewidth = parseFloat(Y.one('#element-' + element['id']).getComputedStyle('width'), 10);
|
||||
var maxwidth = element['width'] * this.pixelsinmm;
|
||||
|
||||
if (maxwidth && (nodewidth > maxwidth)) {
|
||||
nodewidth = maxwidth;
|
||||
}
|
||||
Y.one('#element-' + element['id']).setStyle('width', nodewidth + 'px');
|
||||
|
||||
switch (element['refpoint']) {
|
||||
case '1': // Top-center
|
||||
posx -= nodewidth / 2;
|
||||
break;
|
||||
case '2': // Top-right
|
||||
posx = posx - nodewidth + 2;
|
||||
break;
|
||||
}
|
||||
|
||||
Y.one('#element-' + element['id']).setX(posx);
|
||||
Y.one('#element-' + element['id']).setY(posy);
|
||||
|
||||
this.resize_if_required(Y.one('#element-' + element['id']));
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Creates the JS events for changing element positions.
|
||||
*
|
||||
* @param Y
|
||||
*/
|
||||
create_events : function(Y) {
|
||||
// Trigger a save event when save button is pushed.
|
||||
Y.one('.savepositionsbtn input[type=submit]').on('click', function(e) {
|
||||
this.save_positions(e);
|
||||
}, this);
|
||||
|
||||
// Trigger a save event when apply button is pushed.
|
||||
Y.one('.applypositionsbtn input[type=submit]').on('click', function(e) {
|
||||
this.save_positions(e);
|
||||
e.preventDefault();
|
||||
}, this);
|
||||
|
||||
// Define the container and the elements that are draggable.
|
||||
var del = new Y.DD.Delegate({
|
||||
container: '#pdf',
|
||||
nodes: '.element'
|
||||
});
|
||||
|
||||
// When we start dragging keep track of it's position as we may set it back.
|
||||
del.on('drag:start', function() {
|
||||
var node = del.get('currentNode');
|
||||
this.elementxy = node.getXY();
|
||||
this.elementwidth = node.getComputedStyle('width');
|
||||
}, this);
|
||||
|
||||
// When we finish the dragging action check that the node is in bounds,
|
||||
// if not, set it back to where it was.
|
||||
del.on('drag:end', function() {
|
||||
var node = del.get('currentNode');
|
||||
this.resize_if_required(node);
|
||||
if (this.is_out_of_bounds(node)) {
|
||||
node.setXY(this.elementxy);
|
||||
node.setStyle('width', this.elementwidth);
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Resizes the element if required.
|
||||
*
|
||||
* @param node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
resize_if_required : function(node) {
|
||||
var refpoint = node.getData('refpoint');
|
||||
var maxwidth = node.getData('width') * this.pixelsinmm;
|
||||
var maxallowedwidth = 0;
|
||||
var oldwidth = 0;
|
||||
|
||||
// Get the width and height of the node.
|
||||
var nodewidth = parseFloat(node.getComputedStyle('width'), 10);
|
||||
var nodeheight = parseFloat(node.getComputedStyle('height'), 10);
|
||||
|
||||
// Store the positions of each edge of the node.
|
||||
var left = node.getX();
|
||||
var right = left + nodewidth;
|
||||
var top = node.getY();
|
||||
var bottom = top + nodeheight;
|
||||
|
||||
node.setStyle('width', 'initial');
|
||||
|
||||
oldwidth = nodewidth;
|
||||
nodewidth = parseFloat(node.getComputedStyle('width'), 10);
|
||||
|
||||
switch (refpoint) {
|
||||
case '1': // Top-center
|
||||
left = left + (oldwidth - nodewidth) / 2;
|
||||
if (maxwidth && nodewidth > maxwidth) {
|
||||
left = left + (nodewidth - maxwidth) / 2;
|
||||
nodewidth = maxwidth;
|
||||
node.setStyle('width', nodewidth + 'px');
|
||||
}
|
||||
maxallowedwidth = 2 * Math.min(left + nodewidth / 2 - this.pdfx, this.pdfx + this.pdfwidth - (left + nodewidth / 2));
|
||||
if (maxallowedwidth > 0 && nodewidth > maxallowedwidth) {
|
||||
left = left + (nodewidth - maxallowedwidth) / 2;
|
||||
nodewidth = maxallowedwidth;
|
||||
node.setStyle('width', nodewidth + 'px');
|
||||
}
|
||||
break;
|
||||
case '2': // Top-right
|
||||
left = left + oldwidth - nodewidth;
|
||||
if (maxwidth && nodewidth > maxwidth) {
|
||||
left = left + nodewidth - maxwidth;
|
||||
nodewidth = maxwidth;
|
||||
node.setStyle('width', nodewidth + 'px');
|
||||
}
|
||||
maxallowedwidth = left + nodewidth - this.pdfx;
|
||||
if (maxallowedwidth > 0 && nodewidth > maxallowedwidth) {
|
||||
left = this.pdfx;
|
||||
nodewidth = maxallowedwidth;
|
||||
node.setStyle('width', nodewidth + 'px');
|
||||
}
|
||||
break;
|
||||
case '0': // Top-left
|
||||
default:
|
||||
if (maxwidth && nodewidth > maxwidth) {
|
||||
nodewidth = maxwidth;
|
||||
node.setStyle('width', nodewidth + 'px');
|
||||
}
|
||||
maxallowedwidth = this.pdfx + this.pdfwidth - left;
|
||||
if (maxallowedwidth > 0 && nodewidth > maxallowedwidth) {
|
||||
nodewidth = maxallowedwidth;
|
||||
node.setStyle('width', nodewidth + 'px');
|
||||
}
|
||||
}
|
||||
|
||||
node.setX(left);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true if any part of the element is placed outside of the PDF div, false otherwise.
|
||||
*
|
||||
* @param node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
is_out_of_bounds : function(node) {
|
||||
// Get the width and height of the node.
|
||||
var nodewidth = parseFloat(node.getComputedStyle('width'), 10);
|
||||
var nodeheight = parseFloat(node.getComputedStyle('height'), 10);
|
||||
|
||||
// Store the positions of each edge of the node.
|
||||
var left = node.getX();
|
||||
var right = left + nodewidth;
|
||||
var top = node.getY();
|
||||
var bottom = top + nodeheight;
|
||||
|
||||
// Check if it is out of bounds horizontally.
|
||||
if ((left < this.pdfx) || (right > (this.pdfx + this.pdfwidth))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if it is out of bounds vertically.
|
||||
if ((top < this.pdfy) || (bottom > (this.pdfy + this.pdfheight))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Perform an AJAX call and save the positions of the elements.
|
||||
*
|
||||
* @param e
|
||||
*/
|
||||
save_positions : function(e) {
|
||||
// The parameters to send the AJAX call.
|
||||
var params = {
|
||||
cmid: this.cmid,
|
||||
values: []
|
||||
};
|
||||
|
||||
// Go through the elements and save their positions.
|
||||
for (var key in this.elements) {
|
||||
var element = this.elements[key];
|
||||
var node = Y.one('#element-' + element['id']);
|
||||
|
||||
// Get the current X and Y positions for this element.
|
||||
var posx = node.getX() - this.pdfx;
|
||||
var posy = node.getY() - this.pdfy;
|
||||
|
||||
var nodewidth = parseFloat(node.getComputedStyle('width'), 10);
|
||||
|
||||
switch (element['refpoint']) {
|
||||
case '1': // Top-center
|
||||
posx += nodewidth / 2;
|
||||
break;
|
||||
case '2': // Top-right
|
||||
posx += nodewidth;
|
||||
break;
|
||||
}
|
||||
|
||||
// Set the parameters to pass to the AJAX request.
|
||||
params.values.push({
|
||||
id: element['id'],
|
||||
posx: Math.round(parseFloat(posx / this.pixelsinmm, 10)),
|
||||
posy: Math.round(parseFloat(posy / this.pixelsinmm, 10))
|
||||
});
|
||||
}
|
||||
|
||||
params.values = JSON.stringify(params.values);
|
||||
|
||||
// Save these positions.
|
||||
Y.io(M.cfg.wwwroot + '/mod/customcert/rest.php', {
|
||||
method: 'POST',
|
||||
data: params,
|
||||
on: {
|
||||
failure: function(tid, response) {
|
||||
this.ajax_failure(response);
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
context: this
|
||||
})
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles any failures during an AJAX call.
|
||||
*
|
||||
* @param response
|
||||
* @returns {M.core.exception}
|
||||
*/
|
||||
ajax_failure : function(response) {
|
||||
var e = {
|
||||
name: response.status + ' ' + response.statusText,
|
||||
message: response.responseText
|
||||
};
|
||||
return new M.core.exception(e);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue