Added drag & drop feature to rearrange elements

This commit is contained in:
Shamim Rezaie 2015-08-05 15:38:35 +10:00 committed by Mark Nelson
parent 58d7312d9e
commit 9998fa2b4a
22 changed files with 854 additions and 6 deletions

View file

@ -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');
}

View file

@ -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.
*

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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.
*

View file

@ -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);
}
/**

View file

@ -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.
*

View file

@ -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.
*

View file

@ -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.
*

View file

@ -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));
}
}

View file

@ -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.
*

View file

@ -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.
*

View file

@ -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.
*

View file

@ -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
View file

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 B

BIN
pix/target.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 B

103
rearrange.php Normal file
View 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
View 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);
// }
}

View file

@ -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
View 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);
}
}