Finished level management
On assigning the block to a course, a skill needs to be selected in the config, instead of creating a new skill by default
This commit is contained in:
parent
6b16559201
commit
fa285134cb
52
amd/src/debugger.js
Normal file
52
amd/src/debugger.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*eslint no-var: "error"*/
|
||||
/*eslint no-console: "off"*/
|
||||
/*eslint-env es6*/
|
||||
// Put this file in path/to/plugin/amd/src
|
||||
// You can call it anything you like
|
||||
|
||||
define([], function () {
|
||||
|
||||
return (function (name) {
|
||||
let handle = name;
|
||||
let output_enabled = false;
|
||||
|
||||
return {
|
||||
write: function debugger_write() {
|
||||
if (output_enabled) {
|
||||
let args = Array.prototype.slice.call(arguments);
|
||||
args.unshift(handle + ": ");
|
||||
console.info.apply(console, args);
|
||||
}
|
||||
},
|
||||
info: function debugger_info() {
|
||||
if (output_enabled) {
|
||||
let args = Array.prototype.slice.call(arguments);
|
||||
args.unshift(handle + ": ");
|
||||
console.info.apply(console, args);
|
||||
}
|
||||
},
|
||||
warn: function debugger_warn() {
|
||||
if (output_enabled) {
|
||||
let args = Array.prototype.slice.call(arguments);
|
||||
args.unshift(handle + ": ");
|
||||
console.warn.apply(console, args);
|
||||
}
|
||||
},
|
||||
error: function debugger_error() {
|
||||
if (output_enabled) {
|
||||
let args = Array.prototype.slice.call(arguments);
|
||||
args.unshift(handle + ": ");
|
||||
console.error.apply(console, args);
|
||||
}
|
||||
},
|
||||
enable: function debugger_enable() {
|
||||
output_enabled = true;
|
||||
},
|
||||
|
||||
disable: function debugger_disable() {
|
||||
output_enabled = false;
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
});
|
22
amd/src/handlers.js
Normal file
22
amd/src/handlers.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
/*eslint no-var: "error"*/
|
||||
/*eslint no-console: "off"*/
|
||||
/*eslint-env es6*/
|
||||
// Put this file in path/to/plugin/amd/src
|
||||
// You can call it anything you like
|
||||
|
||||
define([], function () {
|
||||
let debug_enabled = false;
|
||||
|
||||
let self = {
|
||||
fail_report_exception: function fail_report_exception(ex) {
|
||||
if (ex.error != undefined) {
|
||||
console.error("Error from webservice: ", ex.error, "\n", ex.debuginfo, "\n---Stack trace---\n", ex.stacktrace, "\n", ex);
|
||||
}
|
||||
else {
|
||||
console.error("Exception from webservice: ", ex.message, "\n", ex.debuginfo, "\n---Stack trace---\n", ex.backtrace, "\n", ex);
|
||||
}
|
||||
|
||||
},
|
||||
};
|
||||
return self;
|
||||
});
|
235
amd/src/jquery.animate-shadow.js
Normal file
235
amd/src/jquery.animate-shadow.js
Normal file
|
@ -0,0 +1,235 @@
|
|||
/**!
|
||||
* @preserve Shadow animation 1.11
|
||||
* http://www.bitstorm.org/jquery/shadow-animation/
|
||||
* Copyright 2011, 2013 Edwin Martin
|
||||
* Contributors: Mark Carver, Xavier Lepretre and Jason Redding
|
||||
* Released under the MIT and GPL licenses.
|
||||
*/
|
||||
|
||||
define(['jquery'], function (jQuery) {
|
||||
|
||||
return jQuery(function($, undefined) {
|
||||
/**
|
||||
* Check whether the browser supports RGBA color mode.
|
||||
*
|
||||
* Author Mehdi Kabab <http://pioupioum.fr>
|
||||
* @return {boolean} True if the browser support RGBA. False otherwise.
|
||||
*/
|
||||
function isRGBACapable() {
|
||||
var $script = $('script:first'),
|
||||
color = $script.css('color'),
|
||||
result = false;
|
||||
if (/^rgba/.test(color)) {
|
||||
result = true;
|
||||
} else {
|
||||
try {
|
||||
result = (color !== $script.css('color', 'rgba(0, 0, 0, 0.5)').css('color'));
|
||||
$script.css('color', color);
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
$script.removeAttr('style');
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
$.extend(true, $, {
|
||||
support: {
|
||||
'rgba': isRGBACapable()
|
||||
}
|
||||
});
|
||||
|
||||
/*************************************/
|
||||
|
||||
// First define which property to use
|
||||
var styles = $('html').prop('style');
|
||||
var boxShadowProperty;
|
||||
$.each(['boxShadow', 'MozBoxShadow', 'WebkitBoxShadow'], function(i, property) {
|
||||
var val = styles[property];
|
||||
if (typeof val !== 'undefined') {
|
||||
boxShadowProperty = property;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
// Extend the animate-function
|
||||
if (boxShadowProperty) {
|
||||
$['Tween']['propHooks']['boxShadow'] = {
|
||||
get: function(tween) {
|
||||
return $(tween.elem).css(boxShadowProperty);
|
||||
},
|
||||
set: function(tween) {
|
||||
var style = tween.elem.style;
|
||||
var p_begin = parseShadows($(tween.elem)[0].style[boxShadowProperty] || $(tween.elem).css(boxShadowProperty));
|
||||
var p_end = parseShadows(tween.end);
|
||||
var maxShadowCount = Math.max(p_begin.length, p_end.length);
|
||||
var i;
|
||||
for(i = 0; i < maxShadowCount; i++) {
|
||||
p_end[i] = $.extend({}, p_begin[i], p_end[i]);
|
||||
if (p_begin[i]) {
|
||||
if (!('color' in p_begin[i]) || $.isArray(p_begin[i].color) === false) {
|
||||
p_begin[i].color = p_end[i].color || [0, 0, 0, 0];
|
||||
}
|
||||
} else {
|
||||
p_begin[i] = parseShadows('0 0 0 0 rgba(0,0,0,0)')[0];
|
||||
}
|
||||
}
|
||||
tween['run'] = function(progress) {
|
||||
var rs = calculateShadows(p_begin, p_end, progress);
|
||||
style[boxShadowProperty] = rs;
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Calculate an in-between shadow.
|
||||
function calculateShadows(beginList, endList, pos) {
|
||||
var shadows = [];
|
||||
$.each(beginList, function(i) {
|
||||
var parts = [], begin = beginList[i], end = endList[i];
|
||||
|
||||
if (begin.inset) {
|
||||
parts.push('inset');
|
||||
}
|
||||
if (typeof end.left !== 'undefined') {
|
||||
parts.push(parseFloat(begin.left + pos * (end.left - begin.left)) + 'px '
|
||||
+ parseFloat(begin.top + pos * (end.top - begin.top)) + 'px');
|
||||
}
|
||||
if (typeof end.blur !== 'undefined') {
|
||||
parts.push(parseFloat(begin.blur + pos * (end.blur - begin.blur)) + 'px');
|
||||
}
|
||||
if (typeof end.spread !== 'undefined') {
|
||||
parts.push(parseFloat(begin.spread + pos * (end.spread - begin.spread)) + 'px');
|
||||
}
|
||||
if (typeof end.color !== 'undefined') {
|
||||
var color = 'rgb' + ($.support['rgba'] ? 'a' : '') + '('
|
||||
+ parseInt((begin.color[0] + pos * (end.color[0] - begin.color[0])), 10) + ','
|
||||
+ parseInt((begin.color[1] + pos * (end.color[1] - begin.color[1])), 10) + ','
|
||||
+ parseInt((begin.color[2] + pos * (end.color[2] - begin.color[2])), 10);
|
||||
if ($.support['rgba']) {
|
||||
color += ',' + parseFloat(begin.color[3] + pos * (end.color[3] - begin.color[3]));
|
||||
}
|
||||
color += ')';
|
||||
parts.push(color);
|
||||
}
|
||||
shadows.push(parts.join(' '));
|
||||
});
|
||||
return shadows.join(', ');
|
||||
}
|
||||
|
||||
// Parse the shadow value and extract the values.
|
||||
function parseShadows(shadow) {
|
||||
var parsedShadows = [];
|
||||
var parsePosition = 0;
|
||||
var parseLength = shadow.length;
|
||||
|
||||
function findInset() {
|
||||
var m = /^inset\b/.exec(shadow.substring(parsePosition));
|
||||
if (m !== null && m.length > 0) {
|
||||
parsedShadow.inset = true;
|
||||
parsePosition += m[0].length;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function findOffsets() {
|
||||
var m = /^(-?[0-9\.]+)(?:px)?\s+(-?[0-9\.]+)(?:px)?(?:\s+(-?[0-9\.]+)(?:px)?)?(?:\s+(-?[0-9\.]+)(?:px)?)?/.exec(shadow.substring(parsePosition));
|
||||
if (m !== null && m.length > 0) {
|
||||
parsedShadow.left = parseInt(m[1], 10);
|
||||
parsedShadow.top = parseInt(m[2], 10);
|
||||
parsedShadow.blur = (m[3] ? parseInt(m[3], 10) : 0);
|
||||
parsedShadow.spread = (m[4] ? parseInt(m[4], 10) : 0);
|
||||
parsePosition += m[0].length;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function findColor() {
|
||||
var m = /^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})/.exec(shadow.substring(parsePosition));
|
||||
if (m !== null && m.length > 0) {
|
||||
parsedShadow.color = [parseInt(m[1], 16), parseInt(m[2], 16), parseInt(m[3], 16), 1];
|
||||
parsePosition += m[0].length;
|
||||
return true;
|
||||
}
|
||||
m = /^#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])/.exec(shadow.substring(parsePosition));
|
||||
if (m !== null && m.length > 0) {
|
||||
parsedShadow.color = [parseInt(m[1], 16) * 17, parseInt(m[2], 16) * 17, parseInt(m[3], 16) * 17, 1];
|
||||
parsePosition += m[0].length;
|
||||
return true;
|
||||
}
|
||||
m = /^rgb\(\s*([0-9\.]+)\s*,\s*([0-9\.]+)\s*,\s*([0-9\.]+)\s*\)/.exec(shadow.substring(parsePosition));
|
||||
if (m !== null && m.length > 0) {
|
||||
parsedShadow.color = [parseInt(m[1], 10), parseInt(m[2], 10), parseInt(m[3], 10), 1];
|
||||
parsePosition += m[0].length;
|
||||
return true;
|
||||
}
|
||||
m = /^rgba\(\s*([0-9\.]+)\s*,\s*([0-9\.]+)\s*,\s*([0-9\.]+)\s*,\s*([0-9\.]+)\s*\)/.exec(shadow.substring(parsePosition));
|
||||
if (m !== null && m.length > 0) {
|
||||
parsedShadow.color = [parseInt(m[1], 10), parseInt(m[2], 10), parseInt(m[3], 10), parseFloat(m[4])];
|
||||
parsePosition += m[0].length;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function findWhiteSpace() {
|
||||
var m = /^\s+/.exec(shadow.substring(parsePosition));
|
||||
if (m !== null && m.length > 0) {
|
||||
parsePosition += m[0].length;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function findComma() {
|
||||
var m = /^\s*,\s*/.exec(shadow.substring(parsePosition));
|
||||
if (m !== null && m.length > 0) {
|
||||
parsePosition += m[0].length;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function normalizeShadow(shadow) {
|
||||
if ($.isPlainObject(shadow)) {
|
||||
var i, sColor, cLength = 0, color = [];
|
||||
if ($.isArray(shadow.color)) {
|
||||
sColor = shadow.color;
|
||||
cLength = sColor.length;
|
||||
}
|
||||
for(i = 0; i < 4; i++) {
|
||||
if (i < cLength) {
|
||||
color.push(sColor[i]);
|
||||
} else if (i === 3) {
|
||||
color.push(1);
|
||||
} else {
|
||||
color.push(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $.extend({
|
||||
'left': 0,
|
||||
'top': 0,
|
||||
'blur': 0,
|
||||
'spread': 0
|
||||
}, shadow);
|
||||
}
|
||||
var parsedShadow = normalizeShadow();
|
||||
|
||||
while (parsePosition < parseLength) {
|
||||
if (findInset()) {
|
||||
findWhiteSpace();
|
||||
} else if (findOffsets()) {
|
||||
findWhiteSpace();
|
||||
} else if (findColor()) {
|
||||
findWhiteSpace();
|
||||
} else if (findComma()) {
|
||||
parsedShadows.push(normalizeShadow(parsedShadow));
|
||||
parsedShadow = {};
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
parsedShadows.push(normalizeShadow(parsedShadow));
|
||||
return parsedShadows;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
|
@ -18,7 +18,7 @@ define([], function () {
|
|||
//if (!window.jscolor) { window.jscolor = (function () {
|
||||
return (function () {
|
||||
|
||||
console.info("Initializing JSColor");
|
||||
//console.info("Initializing JSColor");
|
||||
|
||||
var jsc = {
|
||||
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
/*eslint no-var: "error"*/
|
||||
/*eslint-env es6*/
|
||||
// Put this file in path/to/plugin/amd/src
|
||||
// You can call it anything you like
|
||||
|
||||
define(['jquery', 'core/str', 'core/ajax', 'block_gradelevel/jscolor'], function ($, str, ajax, jscolor) {
|
||||
define(['jquery', 'block_gradelevel/jquery.animate-shadow', 'core/str', 'core/ajax', 'block_gradelevel/jscolor',
|
||||
'block_gradelevel/handlers', 'block_gradelevel/debugger'], function ($, $shadow, str, ajax, jscolor, handlers, Debugger) {
|
||||
|
||||
let debug = new Debugger("leveleditor");
|
||||
debug.enable();
|
||||
|
||||
let skill_id = null;
|
||||
let $skill_table = null;
|
||||
|
||||
|
@ -13,15 +20,12 @@ define(['jquery', 'core/str', 'core/ajax', 'block_gradelevel/jscolor'], function
|
|||
skill_id = Number($skill_table.attr('data-skill'));
|
||||
|
||||
if (!skill_id && skill_id !== 0 && skill_id !== '0') {
|
||||
console.error("Cannot find configured skill id");
|
||||
debug.error("Cannot find configured skill id");
|
||||
return;
|
||||
}
|
||||
|
||||
// load and fill the level table
|
||||
self.refresh();
|
||||
|
||||
// make sure all uint type numbers are not able to go below 0
|
||||
$(document).on('change', "input[type=number].uint", function (evt) {
|
||||
$(document).on('input', "input[type=number].uint", function (evt) {
|
||||
let $this = $(this);
|
||||
if ($this.val() < 0) {
|
||||
$this.val(0);
|
||||
|
@ -35,6 +39,8 @@ define(['jquery', 'core/str', 'core/ajax', 'block_gradelevel/jscolor'], function
|
|||
|
||||
// On click handler for save changes button
|
||||
$("button[data-action=savechanges]").on('click', self.submit);
|
||||
// On click handler for save changes button
|
||||
$("button[data-action=resetlevels]").on('click', self.resetlevels);
|
||||
|
||||
|
||||
},
|
||||
|
@ -53,7 +59,7 @@ define(['jquery', 'core/str', 'core/ajax', 'block_gradelevel/jscolor'], function
|
|||
$skill_table.find("tbody").append($newtr);
|
||||
},
|
||||
refresh: function refresh() {
|
||||
console.info("Attempting to refresh");
|
||||
debug.info("Attempting to refresh");
|
||||
|
||||
// perform refresh call
|
||||
let promises = ajax.call([{
|
||||
|
@ -82,7 +88,7 @@ define(['jquery', 'core/str', 'core/ajax', 'block_gradelevel/jscolor'], function
|
|||
level_data.push(row);
|
||||
});
|
||||
|
||||
//console.info("Attempting to submit", level_data);
|
||||
//debug.info("Attempting to submit", level_data);
|
||||
|
||||
// perform ajax call
|
||||
let promises = ajax.call([{
|
||||
|
@ -91,27 +97,54 @@ define(['jquery', 'core/str', 'core/ajax', 'block_gradelevel/jscolor'], function
|
|||
}]);
|
||||
|
||||
// and link promise returns to callbacks
|
||||
promises[0].done(self.success_refill_table).fail(self.fail_report_exception);
|
||||
promises[0].done(self.success_refill_table).fail(handlers.fail_report_exception);
|
||||
},
|
||||
resetlevels: function resetlevels(evt) {
|
||||
let $table = $("table#level_config");
|
||||
|
||||
// Send a request to delete all rows
|
||||
let level_data = [];
|
||||
$table.find("tbody tr[data-rowid]").each(function () {
|
||||
let $this = $(this);
|
||||
let row = {
|
||||
id: Number($this.attr('data-rowid')),
|
||||
points: -255, // means: delete row
|
||||
badgecolor: "", // totally irrelevent when requesting a delete
|
||||
}
|
||||
|
||||
level_data.push(row);
|
||||
});
|
||||
|
||||
//debug.info("Attempting to submit", level_data);
|
||||
|
||||
// perform ajax call
|
||||
let promises = ajax.call([{
|
||||
methodname: 'block_gradelevel_submit_levels',
|
||||
args: { skill_id: skill_id, levels: level_data },
|
||||
}]);
|
||||
|
||||
// and link promise returns to callbacks
|
||||
promises[0].done(self.success_refill_table).fail(handlers.fail_report_exception);
|
||||
},
|
||||
success_refill_table: function success_refill_table(response) {
|
||||
//console.info("Response from webservice: ", response);
|
||||
//debug.info("Response from webservice: ", response);
|
||||
let $tbody = $skill_table.find('tbody');
|
||||
$tbody.empty();
|
||||
for (let idx in response) {
|
||||
let lvl = response[idx];
|
||||
//console.info("Level:", lvl);
|
||||
//debug.info("Level:", lvl);
|
||||
self.add_levelrow(lvl.id, lvl.points, lvl.badgecolor);
|
||||
}
|
||||
let $inputs = $tbody.find("input[data-name='points']");
|
||||
|
||||
let orig_border = $inputs.css('border-left-color');
|
||||
$inputs
|
||||
.animate({ boxShadow: '0px 0px 5px 3px #3FDFCF'}, 400)
|
||||
.delay(200)
|
||||
.animate({ boxShadow: 'none'}, 800);
|
||||
|
||||
},
|
||||
fail_report_exception: function fail_report_exception(ex) {
|
||||
if (ex.error != undefined) {
|
||||
console.error("Error from webservice: ", ex.error, "\n" , ex.debuginfo, "\n---Stack trace---\n", ex.stacktrace, "\n", ex);
|
||||
}
|
||||
else {
|
||||
console.error("Exception from webservice: ", ex.message, "\n", ex.debuginfo, "\n---Stack trace---\n", ex.backtrace, "\n", ex);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
|
||||
};
|
||||
return self;
|
||||
|
|
|
@ -1,23 +1,39 @@
|
|||
/*eslint no-var: "error"*/
|
||||
/*eslint-env es6*/
|
||||
// Put this file in path/to/plugin/amd/src
|
||||
// You can call it anything you like
|
||||
|
||||
define(['jquery', 'core/str', 'core/ajax'], function ($, str, ajax) {
|
||||
define(['jquery', 'core/str', 'core/ajax','block_gradelevel/debugger' ], function ($, str, ajax, Debugger) {
|
||||
let debug = Debugger("renderbadge");
|
||||
//debug.enable();
|
||||
|
||||
let self = {
|
||||
init: function init() {
|
||||
|
||||
|
||||
// Put whatever you like here. $ is available
|
||||
// to you as normal.
|
||||
$("figure.levelbadge").each(function () {
|
||||
let props = self.fetchProperties(this);
|
||||
let $this = $(this);
|
||||
let $canvas = $("<canvas height= '"+props.height +"' width = '"+props.width+"'/>");
|
||||
//console.info("$canvas", $canvas, $canvas[0]);
|
||||
$('canvas', this).remove();// clear out any existing canvas
|
||||
$this.append($canvas); // Put the canvas in there
|
||||
self.render($canvas[0], props);
|
||||
self.setup_badge(this,true);
|
||||
});
|
||||
|
||||
},
|
||||
setup_badge: function setup_Badge(figure, allowskip) {
|
||||
let $figure = $(figure);
|
||||
let props = $(figure).data('badge-props');
|
||||
debug.info("Setting up skill badge on ", figure, props);
|
||||
if (props && allowskip) {
|
||||
debug.info(" skill badge was already configured. Skipping process...");
|
||||
}
|
||||
else {
|
||||
props = self.fetchProperties(figure);
|
||||
let $canvas = $("<canvas height= '" + props.height + "' width = '" + props.width + "'/>");
|
||||
$('canvas', figure).remove();// clear out any existing canvas
|
||||
$figure.append($canvas); // Put the new canvas in there
|
||||
self.render($canvas[0], props);
|
||||
// Store properties
|
||||
$figure.data("badge-props", props);
|
||||
}
|
||||
},
|
||||
render: function render(canvas, props) {
|
||||
let ctx = canvas.getContext("2d");
|
||||
// Color configuration
|
||||
|
@ -61,9 +77,9 @@ define(['jquery', 'core/str', 'core/ajax'], function ($, str, ajax) {
|
|||
scale: 0.7, // scale to this fraction of image size
|
||||
}
|
||||
}
|
||||
//console.info("Config", config);
|
||||
//console.info("Colors", colors);
|
||||
//console.info("Props", props);
|
||||
debug.info(" Config", config);
|
||||
debug.info(" Colors", colors);
|
||||
debug.info(" Props", props);
|
||||
|
||||
// draw main circle
|
||||
let baseGradient = ctx.createRadialGradient(
|
||||
|
@ -72,7 +88,7 @@ define(['jquery', 'core/str', 'core/ajax'], function ($, str, ajax) {
|
|||
(config.size ) * colors.radialGradient.r0,
|
||||
config.size * colors.radialGradient.x1,
|
||||
config.size * colors.radialGradient.y1,
|
||||
(config.size ) * colors.radialGradient.r1,
|
||||
(config.size ) * colors.radialGradient.r1
|
||||
);
|
||||
baseGradient.addColorStop(0, colors.lightPoint);
|
||||
baseGradient.addColorStop(1, colors.base);
|
||||
|
@ -157,9 +173,9 @@ define(['jquery', 'core/str', 'core/ajax'], function ($, str, ajax) {
|
|||
imPos.x = (config.size * config.icon.x) - (imPos.w / 2);
|
||||
imPos.y = (config.size * config.icon.y) - (imPos.h / 2);
|
||||
|
||||
ctx.drawImage(this, 15, 15, 120, 120);//imPos.x, imPos.y, imPos.w, imPos.h);
|
||||
ctx.drawImage(this, imPos.x, imPos.y, imPos.w, imPos.h);
|
||||
}
|
||||
//console.info("Image: ",props.image);
|
||||
//debug.info("Image: ",props.image);
|
||||
iconImg.src = props.image;
|
||||
}
|
||||
|
||||
|
|
196
amd/src/skilleditor.js
Normal file
196
amd/src/skilleditor.js
Normal file
|
@ -0,0 +1,196 @@
|
|||
/*eslint no-var: "error"*/
|
||||
/*eslint-env es6*/
|
||||
// Put this file in path/to/plugin/amd/src
|
||||
// You can call it anything you like
|
||||
|
||||
define(['jquery', 'core/str', 'core/ajax', 'core/config', 'block_gradelevel/renderbadge', 'block_gradelevel/handlers',
|
||||
'block_gradelevel/debugger', 'core/modal_factory','core/modal_events'], function ($, str, ajax, mdlcfg, renderbadge, handlers, Debugger, ModalFactory, ModalEvents) {
|
||||
|
||||
let debug = Debugger("skilleditor");
|
||||
debug.enable();
|
||||
|
||||
let $skillset_div = null;
|
||||
const uploadFilter = ".png,.svg";
|
||||
|
||||
let self = {
|
||||
init: function init() {
|
||||
// Find skill table and skill id
|
||||
$skillset_div = $("div#skill_set");
|
||||
// Run initialization code on all items.
|
||||
debug.info("Initializing editors");
|
||||
$skillset_div.find("li.skill_info").each(function () {
|
||||
self.initialize_item(this);
|
||||
});
|
||||
|
||||
debug.info("Attaching function to addskill link");
|
||||
$skillset_div.find("a[data-action='addskill']").on('click', function (ev) {
|
||||
let promises = ajax.call([{
|
||||
methodname: 'block_gradelevel_add_skill',
|
||||
args: { name: null, icon: null },
|
||||
}]);
|
||||
|
||||
// and link promise returns to callbacks
|
||||
promises[0].fail(handlers.fail_report_exception).done(function (data) {
|
||||
let $newskill = $(data.html);
|
||||
$skillset_div.find('ul').append($newskill);
|
||||
$newskill.each(function () {
|
||||
self.initialize_item(this);
|
||||
});
|
||||
$newskill.find('figure.levelbadge').each(function () {
|
||||
renderbadge.setup_badge(this);
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
},
|
||||
initialize_item: function initialize_item(li) {
|
||||
let $li = $(li);
|
||||
let skill_id = $li.data('id');
|
||||
|
||||
// Attach edit name pencil
|
||||
$li.find("a[data-action='editname']").on('click', function (evt) {
|
||||
let $span = $li.find("figcaption span[data-type='label']");
|
||||
if ($span.length > 0) {
|
||||
let name = $span.text();
|
||||
let $input = $("<input type='text'/>").val(name);// value='" + name + "' />");
|
||||
|
||||
$span.replaceWith($input);
|
||||
$input.on("keyup", function input_keypress(e) {
|
||||
let keycode = (e.keyCode ? e.keyCode : e.which);
|
||||
if (keycode == '13') {
|
||||
debug.info("Saving name");
|
||||
// save the new name
|
||||
let new_name = $input.val();
|
||||
|
||||
let promises = ajax.call([{
|
||||
methodname: 'block_gradelevel_update_skill',
|
||||
args: { id: skill_id, name: new_name, icon: null },
|
||||
}]);
|
||||
|
||||
// and link promise returns to callbacks
|
||||
promises[0].fail(handlers.fail_report_exception).done(function (data) {
|
||||
$input.replaceWith($("<span data-type='label'>" + data.name + "</span>"));
|
||||
});
|
||||
|
||||
}
|
||||
if (keycode == '27') {
|
||||
debug.info("Cancelled editing");
|
||||
$input.replaceWith($("<span data-type='label'>" + name + "</span>"));
|
||||
}
|
||||
}).on("focusout", function input_cancel(e) {
|
||||
debug.info("Cancelled editing");
|
||||
$input.replaceWith($("<span data-type='label'>" + name + "</span>"));
|
||||
});
|
||||
$input.focus();
|
||||
|
||||
}
|
||||
else {
|
||||
let $textinput = $li.find("figurecaption input[type=text]");
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
// Attach edit icon pencil
|
||||
$li.find("a[data-action='editicon']").on('click', function (ev) {
|
||||
let $uploader = $("<input type='file' style='display: none;' accept='" + uploadFilter + "'/>");
|
||||
|
||||
$uploader.on('change', function (ev) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
let file = ev.originalEvent.target.files[0];
|
||||
let fr = new FileReader();
|
||||
$(fr).on('load', function (ev) {
|
||||
let dataURI = ev.target.result;
|
||||
|
||||
let promises = ajax.call([{
|
||||
methodname: 'block_gradelevel_update_skill',
|
||||
args: { id: skill_id, name: null, icon: dataURI },
|
||||
}]);
|
||||
|
||||
// and link promise returns to callbacks
|
||||
promises[0].fail(handlers.fail_report_exception).done(function (data) {
|
||||
|
||||
let $figure = $li.find("figure.levelbadge");
|
||||
|
||||
$figure.empty();
|
||||
$figure.append($("<img style='display:none;' src='"+data.icon+"'/>"));
|
||||
|
||||
$figure.each(function () {
|
||||
renderbadge.setup_badge(this);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
$uploader.remove(); // delete the uploader after it's done
|
||||
});
|
||||
fr.readAsDataURL(file);
|
||||
|
||||
});
|
||||
$li.append($uploader);
|
||||
$uploader.trigger('click');
|
||||
|
||||
});
|
||||
|
||||
// Attach edit levels link
|
||||
$li.find("a[data-action='editlevels']").attr('href', mdlcfg.wwwroot + "/blocks/gradelevel/cfg_skilllevels.php?skill_id=" + skill_id);
|
||||
|
||||
// Attach delete function to any existing functional delete link
|
||||
$li.find("a[data-action='deleteskill']").each(function () {
|
||||
let $trigger = $(this);
|
||||
// Attach delete button code
|
||||
ModalFactory.create({
|
||||
type: ModalFactory.types.SAVE_CANCEL,
|
||||
title: str.get_string('title_confirmdelete', 'block_gradelevel'),
|
||||
body: str.get_string('dialog_confirmdeleteskill', 'block_gradelevel'),
|
||||
}, $trigger).done(function (modal) {
|
||||
// Do what you want with your new modal.
|
||||
debug.info("Modal done", modal);
|
||||
modal.setSaveButtonText(str.get_string('delete', 'core'));
|
||||
modal.getRoot().on(ModalEvents.save, function (e) {
|
||||
debug.info("Delete Confirmed");
|
||||
//e.preventDefault(); if you don't want to close the window
|
||||
|
||||
// call the delete function
|
||||
let promises = ajax.call([{
|
||||
methodname: 'block_gradelevel_delete_skill',
|
||||
args: { id: skill_id},
|
||||
}]);
|
||||
|
||||
// and link promise returns to callbacks
|
||||
promises[0].fail(handlers.fail_report_exception).done(function (data) {
|
||||
|
||||
if (data.deleted) {
|
||||
$li.remove();
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
},
|
||||
success_refill_table: function success_refill_table(response) {
|
||||
//console.info("Response from webservice: ", response);
|
||||
let $tbody = $skill_table.find('tbody');
|
||||
$tbody.empty();
|
||||
for (let idx in response) {
|
||||
let lvl = response[idx];
|
||||
//console.info("Level:", lvl);
|
||||
self.add_levelrow(lvl.id, lvl.points, lvl.badgecolor);
|
||||
}
|
||||
},
|
||||
fail_report_exception: function fail_report_exception(ex) {
|
||||
if (ex.error != undefined) {
|
||||
console.error("Error from webservice: ", ex.error, "\n" , ex.debuginfo, "\n---Stack trace---\n", ex.stacktrace, "\n", ex);
|
||||
}
|
||||
else {
|
||||
console.error("Exception from webservice: ", ex.message, "\n", ex.debuginfo, "\n---Stack trace---\n", ex.backtrace, "\n", ex);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
};
|
||||
return self;
|
||||
});
|
|
@ -24,13 +24,6 @@ class block_gradelevel extends block_base {
|
|||
|
||||
// find or create the levelset for this course
|
||||
$this->levelset = block_gradelevel_levelset::find_by_course($COURSE->id);
|
||||
if(empty($this->levelset))
|
||||
{
|
||||
// create a new levelset with the name of this course and attach
|
||||
$this->levelset = block_gradelevel_levelset::create_new($COURSE->shortname);
|
||||
$this->levelset->attach_course($COURSE->id);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// The PHP tag and the curly bracket for the class definition
|
||||
|
@ -43,6 +36,7 @@ class block_gradelevel extends block_base {
|
|||
}
|
||||
|
||||
public function get_content() {
|
||||
global $CFG;
|
||||
global $USER;
|
||||
global $COURSE;
|
||||
|
||||
|
@ -52,28 +46,34 @@ class block_gradelevel extends block_base {
|
|||
|
||||
$this->content = new stdClass;
|
||||
|
||||
// below can be a single call to $this->levelset->get_user_leveldata() once the need for debugging (fixed point total) is gone
|
||||
$pointstotal = $this->levelset->get_levelset_grade($USER->id);
|
||||
$level_info = $this->levelset->calculate_level($pointstotal);
|
||||
if(empty($this->levelset))
|
||||
{
|
||||
$this->content->text = "<figure class='dummybadge'><img height='150px' width='150px' src='{$CFG->wwwroot}/blocks/gradelevel/pix/brokenbadge.svg' /></figure>";
|
||||
$this->content->footer = get_string("unattached_course",'block_gradelevel');
|
||||
}
|
||||
else {
|
||||
// below can be a single call to $this->levelset->get_user_leveldata() once the need for debugging (fixed point total) is gone
|
||||
$pointstotal = $this->levelset->get_levelset_grade($USER->id);
|
||||
$level_info = $this->levelset->calculate_level($pointstotal);
|
||||
|
||||
$this->content->text = $this->levelset->render_badge($pointstotal);
|
||||
$this->content->text = $this->levelset->render_badge($pointstotal);
|
||||
|
||||
if($level_info->levelup_total > 0)
|
||||
{
|
||||
$this->content->footer = "<div class='pointinfo'>".get_string('levelup_at','block_gradelevel')." <span class='currentpoints'>{$level_info->points_in_level}</span>/<span class='leveluppoints'>{$level_info->levelup_total}</span></div>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->content->footer = "<div class='pointinfo complete'>".get_string('levelup_done','block_gradelevel')."</div>";
|
||||
}
|
||||
if($level_info->levelup_total > 0)
|
||||
{
|
||||
$this->content->footer = "<div class='pointinfo'>".get_string('levelup_at','block_gradelevel')." <span class='currentpoints'>{$level_info->points_in_level}</span>/<span class='leveluppoints'>{$level_info->levelup_total}</span></div>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->content->footer = "<div class='pointinfo complete'>".get_string('levelup_done','block_gradelevel')."</div>";
|
||||
}
|
||||
|
||||
$coursecontext = context_course::instance($COURSE->id);
|
||||
$coursecontext = context_course::instance($COURSE->id);
|
||||
|
||||
if(has_capability('block/gradelevel:viewresults', $coursecontext))
|
||||
{
|
||||
$this->content->footer .= "\n<div class='teachermode'><a href='#'>".get_string('teacher_view_results','block_gradelevel')."</a></div>";
|
||||
}
|
||||
|
||||
if(has_capability('block/gradelevel:viewresults', $coursecontext))
|
||||
{
|
||||
$this->content->footer .= "\n<div class='teachermode'><a href='#'>".get_string('teacher_view_results','block_gradelevel')."</a></div>";
|
||||
}
|
||||
}
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
|
|
48
cfg_skilllevels.php
Normal file
48
cfg_skilllevels.php
Normal file
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
if(isset($_SERVER['SCRIPT_FILENAME']))
|
||||
{
|
||||
// If SCRIPT_FILENAME is set, use that so the symlinked directories the developmen environment uses are handled correctly
|
||||
$root = dirname(dirname(dirname($_SERVER['SCRIPT_FILENAME'])));
|
||||
error_log("Using {$root}/config.php");
|
||||
require_once($root."/config.php");
|
||||
}
|
||||
else
|
||||
{
|
||||
// If not, assume the cwd is not symlinked and proceed as we are used to
|
||||
require_once("../../config.php");
|
||||
}
|
||||
|
||||
// HOW DID WE ENSURE ONLY ADMINS CAN VIEW THIS PAGE?
|
||||
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
|
||||
|
||||
admin_externalpage_setup("block_gradelevel_config_skills");
|
||||
|
||||
|
||||
$skill_id = required_param('skill_id', PARAM_INT);
|
||||
|
||||
$systemcontext = context_system::instance();
|
||||
// Check if user has capability to manage skills
|
||||
require_capability('block/gradelevel:skillmanager', $systemcontext);
|
||||
|
||||
$skill = block_gradelevel_levelset::find_by_id($skill_id);
|
||||
|
||||
$PAGE->requires->js_call_amd('block_gradelevel/renderbadge', 'init');
|
||||
$PAGE->requires->js_call_amd('block_gradelevel/skilleditor', 'init');
|
||||
$PAGE->requires->js_call_amd('block_gradelevel/leveleditor', 'init');
|
||||
|
||||
print $OUTPUT->header();
|
||||
|
||||
// render skill editor
|
||||
print $OUTPUT->heading(get_string('cfgpage_editskill','block_gradelevel')." ".$skill->getName());
|
||||
print block_gradelevel_skillmgmtservice::render_skill_editor($skill_id);
|
||||
|
||||
// render level editor
|
||||
print $OUTPUT->heading(get_string('cfgpage_skilllevels','block_gradelevel'));
|
||||
print block_gradelevel_skillmgmtservice::render_leveltable($skill_id);
|
||||
|
||||
// add back button to return to skill management page
|
||||
$cfg_skills_url = $CFG->wwwroot."/blocks/gradelevel/cfg_skills.php";
|
||||
print "<button onclick='window.location=\"{$cfg_skills_url}\";'>".get_string('back','core')."</button>";
|
||||
print $OUTPUT->footer();
|
35
cfg_skills.php
Normal file
35
cfg_skills.php
Normal file
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
if(isset($_SERVER['SCRIPT_FILENAME']))
|
||||
{
|
||||
// If SCRIPT_FILENAME is set, use that so the symlinked directories the developmen environment uses are handled correctly
|
||||
$root = dirname(dirname(dirname($_SERVER['SCRIPT_FILENAME'])));
|
||||
error_log("Using {$root}/config.php");
|
||||
require_once($root."/config.php");
|
||||
}
|
||||
else
|
||||
{
|
||||
// If not, assume the cwd is not symlinked and proceed as we are used to
|
||||
require_once("../../config.php");
|
||||
}
|
||||
|
||||
// HOW DID WE ENSURE ONLY ADMINS CAN VIEW THIS PAGE?
|
||||
|
||||
require_once($CFG->libdir.'/adminlib.php');
|
||||
|
||||
|
||||
admin_externalpage_setup("block_gradelevel_config_skills");
|
||||
|
||||
$systemcontext = context_system::instance();
|
||||
// Check if user has capability to manage skills
|
||||
require_capability('block/gradelevel:skillmanager', $systemcontext);
|
||||
|
||||
|
||||
$PAGE->requires->js_call_amd('block_gradelevel/skilleditor', 'init');
|
||||
$PAGE->requires->js_call_amd('block_gradelevel/renderbadge', 'init');
|
||||
|
||||
print $OUTPUT->header();
|
||||
print $OUTPUT->heading(get_string('cfgpage_skills', 'block_gradelevel'));
|
||||
|
||||
// render page for skill level 0 (global)
|
||||
print block_gradelevel_skillmgmtservice::render_skill_list(0);
|
||||
print $OUTPUT->footer();
|
|
@ -141,9 +141,11 @@ class block_gradelevel_levelset {
|
|||
return null; // return null if no current levelset linked
|
||||
}
|
||||
|
||||
static public function find_by_id($id)
|
||||
static public function find_by_id(int $id)
|
||||
{
|
||||
$levelset = $DB->get_record('block_gradelevel_levelset', array('id' => array_values($records)[0]->levelset_id));
|
||||
global $DB;
|
||||
|
||||
$levelset = $DB->get_record('block_gradelevel_levelset', array('id' => $id));
|
||||
if($levelset)
|
||||
{
|
||||
return new static($levelset->id,$levelset);
|
||||
|
@ -397,7 +399,6 @@ class block_gradelevel_levelset {
|
|||
// If we have levels defined, use those, otherwise use the global levels
|
||||
if(!empty($this->levels))
|
||||
{
|
||||
print ("EXSTING_LEVELS");
|
||||
if(array_values($this->levels)[0]->points > 0)
|
||||
{
|
||||
// insert level 0
|
||||
|
@ -411,16 +412,13 @@ class block_gradelevel_levelset {
|
|||
if(!empty($lvl->badgecolor)) {
|
||||
$color = $lvl->badgecolor;
|
||||
}
|
||||
elseif(isset($this->global_levels[$i]))
|
||||
{
|
||||
$color = $this->global_levels[$i]->badgecolor;
|
||||
}
|
||||
else
|
||||
{
|
||||
$color = static::UNDEFINED_BADGE_COLOR;
|
||||
}
|
||||
|
||||
$level_info[$lvl->points];
|
||||
$level_info[$lvl->points] = $color;
|
||||
$i++;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -458,7 +456,7 @@ class block_gradelevel_levelset {
|
|||
$info = $this->calculate_level($points);
|
||||
|
||||
$image = $this->getIcon();
|
||||
if(strncmp($image,"data: ",6) != 0)
|
||||
if(strncmp($image,"data:",5) != 0)
|
||||
{
|
||||
$image_url = $CFG->wwwroot.$image;
|
||||
}
|
||||
|
@ -487,7 +485,7 @@ class block_gradelevel_levelset {
|
|||
$levels = $this->badgelevels();
|
||||
$maxpoints = array_pop(array_keys($levels));
|
||||
|
||||
return $this->render_badge($maxpoints,$size);
|
||||
return $this->render_badge($maxpoints, $size);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -8,8 +8,8 @@ require_once($CFG->dirroot.'/grade/querylib.php');
|
|||
|
||||
class block_gradelevel_skillmgmtservice extends external_api
|
||||
{
|
||||
const DEBUG = false; // enable debug logging
|
||||
const DEMOBADGE_SIZE = 100; // size of demo badge
|
||||
const DEBUG = true; // enable debug logging
|
||||
const DEMOBADGE_SIZE = 150; // size of demo badge
|
||||
|
||||
private static function log($message)
|
||||
{
|
||||
|
@ -199,28 +199,6 @@ class block_gradelevel_skillmgmtservice extends external_api
|
|||
$systemcontext = context_system::instance();
|
||||
self::validate_context($systemcontext);
|
||||
|
||||
if(skill_id == 0)
|
||||
{
|
||||
// Check if user has capability to manage global levels
|
||||
require_capability('block/gradelevel:managelevels', $systemcontext);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if user has teacher or manager capability in any of the attached courses
|
||||
$capability = false;
|
||||
$courses = self::list_courses($skill_id);
|
||||
foreach($courses as $course_id)
|
||||
{
|
||||
$coursecontext = context_course::instance($course_id);
|
||||
$capability |= has_capability('block/gradelevel:changelevels', $coursecontext);
|
||||
}
|
||||
|
||||
if(!$capability)
|
||||
{
|
||||
throw new Exception("Access denied - you do not have editing capabilities for one of the attached courses");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach($levels as $lvl_raw)
|
||||
{
|
||||
|
@ -273,13 +251,35 @@ class block_gradelevel_skillmgmtservice extends external_api
|
|||
|
||||
$levels = $DB->get_records('block_gradelevel_levels', array('levelset_id' => $skill_id));
|
||||
|
||||
// Sort by points
|
||||
usort( $levels, function( $a, $b) {
|
||||
return ( $a->points < $b->points ) ? -1 : 1;
|
||||
} );
|
||||
if($skill_id == 0 || count($levels) > 0)
|
||||
{
|
||||
// If global level, or skills are defined, return those
|
||||
|
||||
// Sort by points
|
||||
usort( $levels, function( $a, $b) {
|
||||
return ( $a->points < $b->points ) ? -1 : 1;
|
||||
} );
|
||||
|
||||
|
||||
return $levels;
|
||||
return $levels;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Else, return a nameless clone of the default levels).
|
||||
$levels = $DB->get_records('block_gradelevel_levels', array('levelset_id' => 0));
|
||||
|
||||
// Sort by points
|
||||
usort( $levels, function( $a, $b) {
|
||||
return ( $a->points < $b->points ) ? -1 : 1;
|
||||
} );
|
||||
|
||||
foreach($levels as $lvl)
|
||||
{
|
||||
$lvl->id = -255; // replace level id with -255, which is code for "new level" when returned
|
||||
}
|
||||
|
||||
return $levels;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -316,35 +316,51 @@ class block_gradelevel_skillmgmtservice extends external_api
|
|||
|
||||
}
|
||||
|
||||
public static function update_skill(int $id, string $name, string $icon )
|
||||
public static function update_skill(int $id, $name, $icon )
|
||||
{
|
||||
global $CFG, $DB;
|
||||
|
||||
$skill = $DB->get_record('block_gradelevel_levelset', array('id' => $id));
|
||||
|
||||
$skill->name = $name;
|
||||
$skill->icon = $icon;
|
||||
if($name != null){
|
||||
$skill->name = $name;
|
||||
}
|
||||
|
||||
if($icon != null){
|
||||
$skill->icon = $icon;
|
||||
}
|
||||
|
||||
$DB->update_record('block_gradelevel_levelset',$skill);
|
||||
|
||||
|
||||
$skill->html = block_gradelevel_levelset::find_by_id($skill->id)->render_demo_badge(static::DEMOBADGE_SIZE);
|
||||
|
||||
return $skill;
|
||||
}
|
||||
|
||||
public static function add_skill(string $name, string $icon)
|
||||
public static function add_skill($name, $icon)
|
||||
{
|
||||
global $CFG, $DB;
|
||||
|
||||
$skill = stdObj;
|
||||
$skill = new stdClass;
|
||||
|
||||
$skill->name = $name;
|
||||
$skill->icon = $icon;
|
||||
if(empty($name)){
|
||||
$skill->name = get_string('defaults_name','block_gradelevel');
|
||||
}
|
||||
else {
|
||||
$skill->name = $name;
|
||||
}
|
||||
if(empty($icon)){
|
||||
$skill->icon = "/blocks/gradelevel/pix/undefinedskill.svg";
|
||||
}
|
||||
else {
|
||||
$skill->icon = $icon;
|
||||
}
|
||||
|
||||
$id = $DB->insert_record('block_gradelevel_levelset',$skill, true);
|
||||
|
||||
$skill->id = $id;
|
||||
$skill->html = block_gradelevel_levelset::find_by_id($skill->id)->render_demo_badge(static::DEMOBADGE_SIZE);
|
||||
$skill->html = static::single_skill_editor_item(block_gradelevel_levelset::find_by_id($skill->id));
|
||||
|
||||
return $skill;
|
||||
}
|
||||
|
@ -353,10 +369,14 @@ class block_gradelevel_skillmgmtservice extends external_api
|
|||
{
|
||||
global $CFG, $DB;
|
||||
|
||||
$result = stdObj;
|
||||
$result->id = $id;
|
||||
$skill = block_gradelevel_levelset::find_by_id($id);
|
||||
if(count($skill->list_courses()) > 0)
|
||||
{
|
||||
throw new Exception("Cannot delete skills that have courses attached");
|
||||
}
|
||||
|
||||
$result->id = ($DB->delete_record('block_gradelevel_levelset',array('id' => $id)))?true:false;
|
||||
$result = array('id' => $id);
|
||||
$result['deleted'] = ($DB->delete_records('block_gradelevel_levelset',array('id' => $id)))?true:false;
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
@ -368,7 +388,7 @@ class block_gradelevel_skillmgmtservice extends external_api
|
|||
$levels = static::list_levels($skill_id);
|
||||
|
||||
$s = "<p>".get_string('levelcfg_description','block_gradelevel')."</p>";
|
||||
$s .= "<table id='level_config' data-skill='{$skill_id}'>";
|
||||
$s .= "<table id='level_config' class='level_config' data-skill='{$skill_id}'>";
|
||||
$s .= "<thead><tr><th>".get_string('levelcfg_head_points','block_gradelevel')."</th><th>".get_string('levelcfg_head_color','block_gradelevel')."</th></tr></thead>";
|
||||
$s .= "<tbody>";
|
||||
foreach($levels as $lvl)
|
||||
|
@ -380,7 +400,12 @@ class block_gradelevel_skillmgmtservice extends external_api
|
|||
$s .= "</tbody>";
|
||||
$s .= "<tfoot><tr><td class='block_gradelevel_addlevel' colspan='2'><a data-action='addlevel' href='#' onclick='return false;'>".get_string("levelcfg_addlevel",'block_gradelevel')."</a></td></td></tfoot>";
|
||||
$s .= "</table>";
|
||||
$s .= "<p><button data-action='savechanges'>".get_string('savechanges','core')."</button></p>";
|
||||
$s .= "<p><button data-action='savechanges'>".get_string('savechanges','core')."</button>";
|
||||
if($skill_id > 0)
|
||||
{
|
||||
$s .= " <button data-action='resetlevels'>".get_string('cfg_resetlevels','block_gradelevel')."</button>";
|
||||
}
|
||||
$s .= "</p>";
|
||||
|
||||
return $s;
|
||||
|
||||
|
@ -388,19 +413,61 @@ class block_gradelevel_skillmgmtservice extends external_api
|
|||
|
||||
public static function render_skill_list()
|
||||
{
|
||||
global $CFG;
|
||||
$skills = block_gradelevel_levelset::list_all();
|
||||
|
||||
$s = "<div class='skill_set'><ul>";
|
||||
// Sort by points
|
||||
usort( $skills, function( $a, $b) {
|
||||
return ( $a->getName() < $b->getName()) ? -1 : 1;
|
||||
} );
|
||||
|
||||
$s = "<div id='skill_set' class='skill_set'><ul>";
|
||||
foreach($skills as $skill)
|
||||
{
|
||||
$skill_id = $skill->getId();
|
||||
$s .= "<li class='skill_info' data-id='{$skill_id}'>".$skill->render_demo_badge(DEMOBADGE_SIZE);
|
||||
$s .= "<figcaption data-for='name'>".$skill->getName()."</figcaption>";
|
||||
$s .= "</li>";
|
||||
$s .= static::single_skill_editor_item($skill);
|
||||
}
|
||||
|
||||
$s .= "</ul>";
|
||||
$s .= "<a href='#' onclick='return false;' data-action='addskill'>".get_string('cfg_addskill','block_gradelevel')."</a>";
|
||||
$s .= "</div>";
|
||||
|
||||
return $s;
|
||||
}
|
||||
|
||||
public static function render_skill_editor(int $skill_id)
|
||||
{
|
||||
$skill = block_gradelevel_levelset::find_by_id($skill_id);
|
||||
|
||||
$s = "<div id='skill_set' class='skill_set'><ul>";
|
||||
$s .= static::single_skill_editor_item($skill,true);
|
||||
$s .= "</ul></div>";
|
||||
|
||||
return $s;
|
||||
}
|
||||
|
||||
private static function single_skill_editor_item($skill,$single=false)
|
||||
{
|
||||
global $OUTPUT;
|
||||
|
||||
$skill_id = $skill->getId();
|
||||
$s = "<li class='skill_info' data-id='{$skill_id}'>";
|
||||
if(!$single){
|
||||
$s .= "<a data-action='editlevels' href='#'>";
|
||||
}
|
||||
$s .= $skill->render_demo_badge(static::DEMOBADGE_SIZE)."</a>";
|
||||
|
||||
if(!$single){
|
||||
$s .= "<a data-action='editlevels' href='#'>";
|
||||
if(count($skill->list_courses()) ){
|
||||
$s .= "<a class='deleteskill' data-action='deleteskill' onclick='return false;' href='#'><i class='icon fa fa-minus-circle fa-fw' title='".get_string('tooltip_deleteskill','block_gradelevel')."'></i></a>";
|
||||
}
|
||||
}
|
||||
|
||||
$s .= "<a class='editicon' data-action='editicon' onclick='return false;' href='#'><i class='icon fa fa-pencil fa-fw' title='".get_string('tooltip_editicon','block_gradelevel')."'></i></a>";
|
||||
$s .= "<figcaption data-for='name'><span data-type='label'>".$skill->getName()."</span>";
|
||||
$s .= "<a class='editname' data-action='editname' onclick='return false;' href='#'><i class='icon fa fa-pencil fa-fw' title='".get_string('tooltip_editname','block_gradelevel')."'></i></a>";
|
||||
$s .= "</figcaption></li>";
|
||||
return $s;
|
||||
}
|
||||
|
||||
}
|
|
@ -13,35 +13,35 @@ class block_gradelevel_edit_form extends block_edit_form {
|
|||
// Section header title according to language file.
|
||||
$mform->addElement('header', 'config_header', get_string('blocksettings', 'block'));
|
||||
|
||||
// A sample string variable with a default value.
|
||||
$mform->addElement('text', 'levelset_name', get_string('levelset_name', 'block_gradelevel'));
|
||||
|
||||
$icon = $levelset->getIcon();
|
||||
if(strncmp($icon,"data: ",6) != 0)
|
||||
$skills = block_gradelevel_levelset::list_all();
|
||||
// sort by name
|
||||
usort( $skills, function( $a, $b) {
|
||||
return ( $a->getName() < $b->getName()) ? -1 : 1;
|
||||
} );
|
||||
|
||||
$options = array( '-1' => get_string('edit_noneskill', 'block_gradelevel'));
|
||||
foreach($skills as $skill)
|
||||
{
|
||||
$icon = $CFG->wwwroot.$icon;
|
||||
$options[$skill->getId()] = $skill->getName();
|
||||
}
|
||||
|
||||
$icon_title = get_string('levelset_icon_cur', 'block_gradelevel');
|
||||
$mform->addElement('html',"<div class='form-group row fitem'><div class='col-md-3'>{$icon_title}</div><div class='col-md-9'><figure class='levelset_icon'><img src='{$icon}' /></figure></div></div>");
|
||||
|
||||
// A sample string variable with a default value.
|
||||
$mform->addElement('filepicker', 'levelset_icon', get_string('levelset_icon_new', 'block_gradelevel'), null,
|
||||
array('maxbytes' => $maxbytes, 'accepted_types' => array('.png', '.svg')));
|
||||
|
||||
$mform->addElement('header', 'config_header', get_string('levelset_levels', 'block_gradelevel'));
|
||||
$mform->addElement('html',print block_gradelevel_managelevelservice::render_leveltable(0));
|
||||
$mform->addElement('select', 'attached_skill', get_string('edit_pickskill', 'block_gradelevel'), $options);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public function set_data($defaults)
|
||||
{
|
||||
global $COURSE;
|
||||
|
||||
$defaults->attached_skill = -1;
|
||||
// retrieve levelset
|
||||
$levelset = $this->block->levelset;
|
||||
$skill = block_gradelevel_levelset::find_by_course($COURSE->id);
|
||||
if(isset($skill)){
|
||||
$defaults->attached_skill = $skill->getId();
|
||||
}
|
||||
|
||||
$defaults->levelset_name = $levelset->getName();
|
||||
|
||||
$defaults->levelset_icon = $levelset->getIcon();
|
||||
|
||||
parent::set_data($defaults);
|
||||
}
|
||||
|
@ -61,50 +61,26 @@ class block_gradelevel_edit_form extends block_edit_form {
|
|||
|
||||
protected function save_data($data)
|
||||
{
|
||||
global $COURSE;
|
||||
// retrieve levelset
|
||||
$levelset = $this->block->levelset;
|
||||
|
||||
$this->debug("data: ".print_r($data,true));
|
||||
|
||||
|
||||
if(isset($data->levelset_name)){
|
||||
$levelset->setName($data->levelset_name);
|
||||
}
|
||||
|
||||
if(isset($data->levelset_icon))
|
||||
if(isset($data->attached_skill))
|
||||
{
|
||||
$filename = $this->get_new_filename('levelset_icon');
|
||||
$contents = $this->get_file_content('levelset_icon');
|
||||
|
||||
$imageData = base64_encode($contents);
|
||||
|
||||
$pi = pathinfo($filename);
|
||||
if($pi['extension'] == 'svg')
|
||||
$currentskill = block_gradelevel_levelset::find_by_course($COURSE->id);
|
||||
if(isset($currentskill))
|
||||
{
|
||||
$mime = "image/svg+xml";
|
||||
}
|
||||
else if($pi['extension'] == 'png')
|
||||
{
|
||||
$mime = "image/png";
|
||||
}
|
||||
else
|
||||
{
|
||||
$mime = "binary/octet-stream"; // no idea what it is
|
||||
$this->debug("deetaching...");
|
||||
$currentskill->detach_course($COURSE->id);
|
||||
}
|
||||
|
||||
|
||||
$dataSrc = 'data: '.$mime.';base64,'.$imageData;
|
||||
|
||||
$levelset->setIcon($dataSrc);
|
||||
$skill = block_gradelevel_levelset::find_by_id($data->attached_skill);
|
||||
if(isset($skill)){
|
||||
$this->debug("attaching...");
|
||||
$skill->attach_course($COURSE->id);
|
||||
}
|
||||
}
|
||||
|
||||
$this->debug("levelset: ".print_r($levelset,true));
|
||||
|
||||
$levelset->save_data();
|
||||
}
|
||||
|
||||
|
||||
|
||||
private function debug($msg)
|
||||
{
|
||||
error_log($msg, 3, '/tmp/moodledevlog.log');
|
||||
|
|
|
@ -7,16 +7,18 @@ $string['gradelevel:myaddinstance'] = 'Add a new Grade Level block to the My Moo
|
|||
$string['blockstring'] = 'Text in the block';
|
||||
$string['levelup_at'] = 'Next level: ';
|
||||
$string['levelup_done'] = 'Complete';
|
||||
$string['unattached_course'] = 'Please attach this course to a skill in the block settings';
|
||||
|
||||
$string['teacher_view_results'] = 'View student results';
|
||||
|
||||
$string['levelset_name'] = "Skill name";
|
||||
$string['levelset_icon_cur'] = "Current skill icon (for level badge)";
|
||||
$string['levelset_icon_new'] = "New skill icon (for level badge)";
|
||||
$string['edit_pickskill'] = "Attach to skill";
|
||||
$string['edit_noneskill'] = "None";
|
||||
|
||||
$string['cfgpage_generic'] = "Grade Level settings";
|
||||
$string['cfgpage_globallevels'] = "Default levels";
|
||||
|
||||
$string['cfgpage_skilllevels'] = "Edit levels";
|
||||
$string['cfgpage_skills'] = "Manage skills";
|
||||
$string['cfgpage_editskill'] = "Edit skill";
|
||||
|
||||
$string['descconfig'] = "Configuration for Grade Level block";
|
||||
|
||||
|
@ -34,3 +36,16 @@ $string['levelcfg_description'] = "Levels will be sorted based on points. Make s
|
|||
$string['levelcfg_head_points'] = "Points";
|
||||
$string['levelcfg_head_color'] = "Medal color";
|
||||
$string['levelcfg_addlevel'] = "Add level";
|
||||
|
||||
$string['tooltip_editicon'] = "Edit icon";
|
||||
$string['tooltip_editname'] = "Edit name";
|
||||
$string['tooltip_deleteskill'] = "Delete skill";
|
||||
$string['tooltip_deleteskill_disabled'] = "Cannot delete skill, because there are attached courses";
|
||||
|
||||
$string['defaults_name'] = "New skill";
|
||||
$string['cfg_resetlevels'] = "Reset levels to default";
|
||||
$string['cfg_addskill'] = "Add skill";
|
||||
|
||||
$string['title_confirmdelete'] = "Confirm delete";
|
||||
$string['dialog_confirmdeleteskill'] = "Are you sure you want to delete this skill?";
|
||||
//$string[''] = "";
|
||||
|
|
2601
pix/brokenbadge.svg
Normal file
2601
pix/brokenbadge.svg
Normal file
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 92 KiB |
21
settings.php
21
settings.php
|
@ -18,16 +18,23 @@ $settings->add(new admin_setting_configtext(
|
|||
));
|
||||
|
||||
|
||||
$ADMIN->add("block_gradelevel", $settings);
|
||||
|
||||
// Add the default levels page
|
||||
$external = new admin_externalpage(
|
||||
'block_gradelevel_default_levels',
|
||||
get_string('cfgpage_globallevels', 'block_gradelevel'),
|
||||
$CFG->wwwroot . '/blocks/gradelevel/globallevels.php'
|
||||
);
|
||||
$ADMIN->add("block_gradelevel", new admin_externalpage(
|
||||
'block_gradelevel_default_levels',
|
||||
get_string('cfgpage_globallevels', 'block_gradelevel'),
|
||||
$CFG->wwwroot . '/blocks/gradelevel/cfg_globallevels.php'
|
||||
)
|
||||
);
|
||||
|
||||
$ADMIN->add("block_gradelevel", $settings);
|
||||
$ADMIN->add("block_gradelevel", $external);
|
||||
// Add the skill configpage
|
||||
$ADMIN->add("block_gradelevel", new admin_externalpage(
|
||||
'block_gradelevel_config_skills',
|
||||
get_string('cfgpage_skills', 'block_gradelevel'),
|
||||
$CFG->wwwroot . '/blocks/gradelevel/cfg_skills.php'
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
$settings = null;
|
86
styles.css
86
styles.css
|
@ -1,4 +1,4 @@
|
|||
figure.levelbadge {
|
||||
figure.levelbadge, figure.dummybadge {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
@ -6,17 +6,19 @@ div.pointinfo {
|
|||
text-align: center;
|
||||
font-family: "Open Sans", Arial, helvetica, sans-serif;
|
||||
}
|
||||
div.pointinfo.complete {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.pointinfo span.currentpoints {
|
||||
font-weight: bold;
|
||||
}
|
||||
div.pointinfo.complete {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.pointinfo span.currentpoints {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.pointinfo span.leveluppoints {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.pointinfo span.leveluppoints {
|
||||
font-weight: bold;
|
||||
}
|
||||
div.teachermode {
|
||||
text-align: center;
|
||||
}
|
||||
|
@ -29,6 +31,70 @@ input.jscolor[type=text] {
|
|||
width: 5em;
|
||||
}
|
||||
|
||||
|
||||
div.skill_set ul {
|
||||
padding-left: 0px;
|
||||
margin-left: 0px;
|
||||
}
|
||||
|
||||
div.skill_set li.skill_info {
|
||||
position: relative; /* needed to have absolute positions be relative to this li */
|
||||
list-style: none;
|
||||
display: inline-block;
|
||||
width: 220px;
|
||||
height: 220px;
|
||||
border-color: #ccc;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
|
||||
div.skill_set li.skill_info figcaption {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div.skill_set li.skill_info input[type=text] {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
div.skill_set li.skill_info a.editicon {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
div.skill_set li.skill_info a.deleteskill {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 7px;
|
||||
}
|
||||
div.skill_set li.skill_info a.deleteskill i.icon {
|
||||
color: red;
|
||||
}
|
||||
|
||||
div.skill_set li.skill_info a.deleteskill i.icon.disabled {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
div.skill_set li.skill_info a.editname {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
table.level_config tr[data-rowid='-255'] {
|
||||
}
|
||||
|
||||
table.level_config tr[data-rowid='-255'] td {
|
||||
|
||||
}
|
||||
|
||||
table.level_config tr[data-rowid='-255'] input[data-name='points'] {
|
||||
background-color: #F0F0F0;
|
||||
}
|
||||
|
||||
|
||||
figure.levelset_icon {
|
||||
background-color: #ccc;
|
||||
background-image: -moz-linear-gradient(45deg, #aaa 25%, transparent 25%), -moz-linear-gradient(-45deg, #aaa 25%, transparent 25%), -moz-linear-gradient(45deg, transparent 75%, #aaa 75%), -moz-linear-gradient(-45deg, transparent 75%, #aaa 75%);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<?php
|
||||
$plugin->component = 'block_gradelevel'; // Recommended since 2.0.2 (MDL-26035). Required since 3.0 (MDL-48494)
|
||||
$plugin->version = 2018092101; // YYYYMMDDHH (year, month, day, 24-hr time)
|
||||
$plugin->version = 2018092300; // YYYYMMDDHH (year, month, day, 24-hr time)
|
||||
$plugin->requires = 2018050800; // YYYYMMDDHH (This is the release version for Moodle 3.5)
|
Loading…
Reference in New Issue
Block a user