Commit of mytreestudyplan

This commit is contained in:
Peter-Martijn Kuipers 2022-06-26 20:05:36 +02:00
parent c2cb225fa6
commit e8e2603679
45 changed files with 289 additions and 8286 deletions

3
.gitignore vendored
View File

@ -1,2 +1,3 @@
/.vs
/node_modules
/amd/build

11
LICENSE
View File

@ -1,7 +1,4 @@
Copyright 2018 P.M. Kuipers
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Copyright (C) 2022 Peter-Martijn Kuipers
This program 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 2 of the License, or (at your option) any later version.
This program 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 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 , USA. Also add information on how to contact you by electronic and paper mail.

View File

@ -1 +0,0 @@
define([],function(){return function(n){let o=!1;return{write:function(){if(o){let o=Array.prototype.slice.call(arguments);o.unshift(n+": "),console.info.apply(console,o)}},info:function(){if(o){let o=Array.prototype.slice.call(arguments);o.unshift(n+": "),console.info.apply(console,o)}},warn:function(){if(o){let o=Array.prototype.slice.call(arguments);o.unshift(n+": "),console.warn.apply(console,o)}},error:function(){if(o){let o=Array.prototype.slice.call(arguments);o.unshift(n+": "),console.error.apply(console,o)}},enable:function(){o=!0},disable:function(){o=!1}}}});

View File

@ -1 +0,0 @@
define([],function(){return{fail_report_exception:function(e){void 0!=e.error?console.error("Error from webservice: ",e.error,"\n",e.debuginfo,"\n---Stack trace---\n",e.stacktrace,"\n",e):console.error("Exception from webservice: ",e.message,"\n",e.debuginfo,"\n---Stack trace---\n",e.backtrace,"\n",e)}}});

View File

@ -1 +0,0 @@
define(["jquery"],function(r){return r(function(r){r.extend(!0,r,{support:{rgba:function(){var e=r("script:first"),t=e.css("color"),s=!1;if(/^rgba/.test(t))s=!0;else try{s=t!==e.css("color","rgba(0, 0, 0, 0.5)").css("color"),e.css("color",t)}catch(r){}return e.removeAttr("style"),s}()}});var e,t=r("html").prop("style");function s(e){var t=[],s=0,n=e.length;function o(){var r=/^(-?[0-9\.]+)(?:px)?\s+(-?[0-9\.]+)(?:px)?(?:\s+(-?[0-9\.]+)(?:px)?)?(?:\s+(-?[0-9\.]+)(?:px)?)?/.exec(e.substring(s));return null!==r&&r.length>0&&(i.left=parseInt(r[1],10),i.top=parseInt(r[2],10),i.blur=r[3]?parseInt(r[3],10):0,i.spread=r[4]?parseInt(r[4],10):0,s+=r[0].length,!0)}function l(){var r=/^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})/.exec(e.substring(s));return null!==r&&r.length>0?(i.color=[parseInt(r[1],16),parseInt(r[2],16),parseInt(r[3],16),1],s+=r[0].length,!0):null!==(r=/^#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])/.exec(e.substring(s)))&&r.length>0?(i.color=[17*parseInt(r[1],16),17*parseInt(r[2],16),17*parseInt(r[3],16),1],s+=r[0].length,!0):null!==(r=/^rgb\(\s*([0-9\.]+)\s*,\s*([0-9\.]+)\s*,\s*([0-9\.]+)\s*\)/.exec(e.substring(s)))&&r.length>0?(i.color=[parseInt(r[1],10),parseInt(r[2],10),parseInt(r[3],10),1],s+=r[0].length,!0):null!==(r=/^rgba\(\s*([0-9\.]+)\s*,\s*([0-9\.]+)\s*,\s*([0-9\.]+)\s*,\s*([0-9\.]+)\s*\)/.exec(e.substring(s)))&&r.length>0&&(i.color=[parseInt(r[1],10),parseInt(r[2],10),parseInt(r[3],10),parseFloat(r[4])],s+=r[0].length,!0)}function a(){var r=/^\s+/.exec(e.substring(s));return null!==r&&r.length>0&&(s+=r[0].length,!0)}function p(){var r=/^\s*,\s*/.exec(e.substring(s));return null!==r&&r.length>0&&(s+=r[0].length,!0)}function u(e){if(r.isPlainObject(e)){var t,s,n=0,o=[];for(r.isArray(e.color)&&(n=(s=e.color).length),t=0;t<4;t++)t<n?o.push(s[t]):3===t?o.push(1):o.push(0)}return r.extend({left:0,top:0,blur:0,spread:0},e)}for(var c,i=u();s<n;)if(void 0,null!==(c=/^inset\b/.exec(e.substring(s)))&&c.length>0&&(i.inset=!0,s+=c[0].length,1))a();else if(o())a();else if(l())a();else{if(!p())break;t.push(u(i)),i={}}return t.push(u(i)),t}r.each(["boxShadow","MozBoxShadow","WebkitBoxShadow"],function(r,s){if(void 0!==t[s])return e=s,!1}),e&&(r.Tween.propHooks.boxShadow={get:function(t){return r(t.elem).css(e)},set:function(t){var n,o=t.elem.style,l=s(r(t.elem)[0].style[e]||r(t.elem).css(e)),a=s(t.end),p=Math.max(l.length,a.length);for(n=0;n<p;n++)a[n]=r.extend({},l[n],a[n]),l[n]?"color"in l[n]&&!1!==r.isArray(l[n].color)||(l[n].color=a[n].color||[0,0,0,0]):l[n]=s("0 0 0 0 rgba(0,0,0,0)")[0];t.run=function(t){var s,n,p,u,c=(s=l,n=a,p=t,u=[],r.each(s,function(e){var t=[],o=s[e],l=n[e];if(o.inset&&t.push("inset"),void 0!==l.left&&t.push(parseFloat(o.left+p*(l.left-o.left))+"px "+parseFloat(o.top+p*(l.top-o.top))+"px"),void 0!==l.blur&&t.push(parseFloat(o.blur+p*(l.blur-o.blur))+"px"),void 0!==l.spread&&t.push(parseFloat(o.spread+p*(l.spread-o.spread))+"px"),void 0!==l.color){var a="rgb"+(r.support.rgba?"a":"")+"("+parseInt(o.color[0]+p*(l.color[0]-o.color[0]),10)+","+parseInt(o.color[1]+p*(l.color[1]-o.color[1]),10)+","+parseInt(o.color[2]+p*(l.color[2]-o.color[2]),10);r.support.rgba&&(a+=","+parseFloat(o.color[3]+p*(l.color[3]-o.color[3]))),a+=")",t.push(a)}u.push(t.join(" "))}),u.join(", "));o[e]=c}}})})});

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
define(["jquery","block_gradelevel/jquery.animate-shadow","core/str","core/ajax","block_gradelevel/jscolor","block_gradelevel/handlers","block_gradelevel/debugger"],function(e,t,l,a,n,i,o){let d=new o("leveleditor");d.enable();let r=null,s=null,c={init:function(){s=e("table#level_config"),(r=Number(s.attr("data-skill")))||0===r||"0"===r?(e(document).on("input","input[type=number].uint",function(t){let l=e(this);l.val()<0&&l.val(0)}),e("a[data-action=addlevel]").on("click",function(e){c.add_levelrow(-255,"","7F7F7F")}),e("button[data-action=savechanges]").on("click",c.submit),e("button[data-action=resetlevels]").on("click",c.resetlevels)):d.error("Cannot find configured skill id")},add_levelrow:function(t,l,a){let i=e("<tr data-rowid='"+t+"'><td><input data-name='points' type='number' class='uint' value='"+l+"'></td><td><input type='text' data-name='color' class='jscolor' value='"+a+"'></td></tr>");i.find("input.jscolor").each(function(){new n(this)}),s.find("tbody").append(i)},refresh:function(){d.info("Attempting to refresh"),a.call([{methodname:"block_gradelevel_list_levels",args:{skill_id:r}}])[0].done(c.success_refill_table).fail(c.fail_report_exception)},submit:function(t){let l=[];e("table#level_config").find("tbody tr[data-rowid]").each(function(){let t=e(this),a={id:Number(t.attr("data-rowid")),points:t.find("input[data-name=points]").val(),badgecolor:t.find("input[data-name=color]").val()};""===a.points&&(a.points=-255),a.points=Number(a.points),l.push(a)}),a.call([{methodname:"block_gradelevel_submit_levels",args:{skill_id:r,levels:l}}])[0].done(c.success_refill_table).fail(i.fail_report_exception)},resetlevels:function(t){let l=[];e("table#level_config").find("tbody tr[data-rowid]").each(function(){let t=e(this),a={id:Number(t.attr("data-rowid")),points:-255,badgecolor:""};l.push(a)}),a.call([{methodname:"block_gradelevel_submit_levels",args:{skill_id:r,levels:l}}])[0].done(c.success_refill_table).fail(i.fail_report_exception)},success_refill_table:function(e){let t=s.find("tbody");t.empty();for(let t in e){let l=e[t];c.add_levelrow(l.id,l.points,l.badgecolor)}t.find("input[data-name='points']").animate({boxShadow:"0px 0px 5px 3px #3FDFCF"},400).delay(200).animate({boxShadow:"none"},800)}};return c});

View File

@ -1 +0,0 @@
define(["jquery","core/str","core/ajax","block_gradelevel/debugger"],function(e,t,i,r){let l=r("renderbadge");function n(e){if(/^#([A-Fa-f0-9]{3})$/.test(e)){let t=e.substring(1).split(""),i="0x"+[t[0],t[0],t[1],t[1],t[2],t[2]].join("");return"rgb("+[i>>16&255,i>>8&255,255&i].join(",")+")"}if(/^#([A-Fa-f0-9]{6})$/.test(e)){let t="0x"+e.substring(1).split("").join("");return"rgb("+[t>>16&255,t>>8&255,255&t].join(",")+")"}if(/^#([A-Fa-f0-9]{8})$/.test(e)){let t=e.substring(1).split(""),i="0x"+[t[0],t[1],t[2],t[3],t[4],t[5]].join(""),r="0x"+[t[6],t[7]].join("");return"rgba("+[i>>16&255,i>>8&255,255&i].join(",")+","+r/255+")"}throw Error("Invalid hex code: "+e)}l.enable();let a={init:function(){l.info("Setting up badge renderers"),e("figure.levelbadge").each(function(){a.setup_badge(this,!0)})},setup_badge:function(t,i){let r=e(t),n=e(t).data("badge-props");if(l.info("Setting up skill badge on ",t,n),n&&i)l.info(" skill badge was already configured. Skipping process...");else{n=a.fetchProperties(t);let i=e("<canvas height= '"+n.height+"' width = '"+n.width+"'/>");e("canvas",t).remove(),r.append(i),a.render(i[0],n),r.data("badge-props",n)}},render:function(e,t){let i=e.getContext("2d"),r={base:t.color,light:a.shadeBlendConvert(.6,t.color),dark:a.shadeBlendConvert(.3,t.color),lightPoint:a.shadeBlendConvert(.8,t.color),reflection:{lightest:"#ffffff51",darkest:"#ffffff20"},radialGradient:{x0:.75,y0:.25,r0:.05,x1:.6,y1:.4,r1:.4},levelText:"white"},s={size:Math.min(t.height,t.width),borderWidth:.05,reflection:{angle:-20,offset:.125},levelText:{x:.5,y:.9,size:.2,font:"Open Sans, Arial, helvetica, sans-serif"},icon:{x:.5,y:.47,scale:.7}};l.info(" Config",s),l.info(" Colors",r),l.info(" Props",t);let o=i.createRadialGradient(s.size*r.radialGradient.x0,s.size*r.radialGradient.y0,s.size*r.radialGradient.r0,s.size*r.radialGradient.x1,s.size*r.radialGradient.y1,s.size*r.radialGradient.r1);o.addColorStop(0,n(r.lightPoint)),o.addColorStop(1,n(r.base)),i.beginPath(),i.fillStyle=o,i.arc(.5*s.size,.5*s.size,s.size/2,0,2*Math.PI),i.fill();let d=Math.asin(s.reflection.offset),h=s.reflection.angle/360*2*Math.PI;l.info("rflAngleRad:",h);let f=i.createLinearGradient((.5-s.reflection.offset*Math.sin(h))/2*s.size,(.5+s.reflection.offset*Math.cos(h))/2*s.size,Math.sin(h)/2*s.size,Math.cos(h)/2*s.size);l.info("rflGradient",f),f.addColorStop(0,n(r.reflection.lightest)),f.addColorStop(1,n(r.reflection.darkest)),i.beginPath(),i.fillStyle=f,i.arc(.5*s.size,.5*s.size,s.size/2,0+d+h,Math.PI-d+h),i.fill(),l.info("Starting with border");let g=s.size*s.borderWidth;if(i.beginPath(),i.strokeStyle=r.light,i.lineWidth=g,i.arc(.5*s.size,.5*s.size,s.size/2-g/2,0,2*Math.PI),i.stroke(),i.beginPath(),i.strokeStyle=r.dark,i.lineWidth=g,i.arc(.5*s.size,.5*s.size,s.size/2-g/2,0-Math.PI/2,2*t.progress*Math.PI-Math.PI/2),i.stroke(),t.level&&(i.font=s.size*s.levelText.size+"px "+s.levelText.font,i.fillStyle=r.levelText,i.textAlign="center",i.fillText(""+t.level,s.size*s.levelText.x,s.size*s.levelText.y)),t.image){let e=new Image;e.onload=function(){let e={x:0,y:0,w:s.size*s.icon.scale,h:s.size*s.icon.scale};this.width>this.height?e.h*=this.height/this.width:e.w*=this.width/this.height,e.x=s.size*s.icon.x-e.w/2,e.y=s.size*s.icon.y-e.h/2,i.drawImage(this,e.x,e.y,e.w,e.h)},e.src=t.image}},fetchProperties:function(t){let i=e(t),r=i.find("img"),l=null;return r.length>0&&(l=r.attr("src")),{progress:i.attr("data-progress"),width:i.attr("data-width"),height:i.attr("data-height"),color:"#"+i.attr("data-color"),level:i.attr("data-level"),image:l}},shadeBlendConvert:function(e,t,i){if("number"!=typeof e||e<-1||e>1||"string"!=typeof t||"r"!=t[0]&&"#"!=t[0]||i&&"string"!=typeof i)return null;this.sbcRip||(this.sbcRip=(e=>{let t=e.length,i={};if(t>9){if((e=e.split(",")).length<3||e.length>4)return null;i[0]=r(e[0].split("(")[1]),i[1]=r(e[1]),i[2]=r(e[2]),i[3]=e[3]?parseFloat(e[3]):-1}else{if(8==t||6==t||t<4)return null;t<6&&(e="#"+e[1]+e[1]+e[2]+e[2]+e[3]+e[3]+(t>4?e[4]+""+e[4]:"")),e=r(e.slice(1),16),i[0]=e>>16&255,i[1]=e>>8&255,i[2]=255&e,i[3]=-1,9!=t&&5!=t||(i[3]=l(i[2]/255*1e4)/1e4,i[2]=i[1],i[1]=i[0],i[0]=e>>24&255)}return i}));var r=parseInt,l=Math.round,n=t.length>9,a=(n="string"==typeof i?i.length>9||"c"==i&&!n:n,e<0),s=(e=a?-1*e:e,i=i&&"c"!=i?i:a?"#000000":"#FFFFFF",this.sbcRip(t)),o=this.sbcRip(i);return s&&o?n?"rgb"+(s[3]>-1||o[3]>-1?"a(":"(")+l((o[0]-s[0])*e+s[0])+","+l((o[1]-s[1])*e+s[1])+","+l((o[2]-s[2])*e+s[2])+(s[3]<0&&o[3]<0?")":","+(s[3]>-1&&o[3]>-1?l(1e4*((o[3]-s[3])*e+s[3]))/1e4:o[3]<0?s[3]:o[3])+")"):"#"+(4294967296+16777216*l((o[0]-s[0])*e+s[0])+65536*l((o[1]-s[1])*e+s[1])+256*l((o[2]-s[2])*e+s[2])+(s[3]>-1&&o[3]>-1?l(255*((o[3]-s[3])*e+s[3])):o[3]>-1?l(255*o[3]):s[3]>-1?l(255*s[3]):255)).toString(16).slice(1,s[3]>-1||o[3]>-1?void 0:-2):null}};return a});

View File

@ -1 +0,0 @@
define(["jquery","core/str","core/ajax","core/config","block_gradelevel/renderbadge","block_gradelevel/handlers","block_gradelevel/debugger","core/modal_factory","core/modal_events"],function(e,t,i,l,n,a,o,d,c){let r=o("skilleditor");r.enable();let f=null;let s={init:function(){f=e("div#skill_set"),r.info("Initializing editors"),f.find("li.skill_info").each(function(){s.initialize_item(this)}),r.info("Attaching function to addskill link"),f.find("a[data-action='addskill']").on("click",function(t){i.call([{methodname:"block_gradelevel_add_skill",args:{name:null,icon:null}}])[0].fail(a.fail_report_exception).done(function(t){let i=e(t.html);f.find("ul").append(i),i.each(function(){s.initialize_item(this)}),i.find("figure.levelbadge").each(function(){n.setup_badge(this)})})})},initialize_item:function(o){let f=e(o),s=f.data("id");f.find("a[data-action='editname']").on("click",function(t){let l=f.find("figcaption span[data-type='label']");if(l.length>0){let t=l.text(),n=e("<input type='text'/>").val(t);l.replaceWith(n),n.on("keyup",function(l){let o=l.keyCode?l.keyCode:l.which;if("13"==o){r.info("Saving name");let t=n.val();i.call([{methodname:"block_gradelevel_update_skill",args:{id:s,name:t,icon:null}}])[0].fail(a.fail_report_exception).done(function(t){n.replaceWith(e("<span data-type='label'>"+t.name+"</span>"))})}"27"==o&&(r.info("Cancelled editing"),n.replaceWith(e("<span data-type='label'>"+t+"</span>")))}).on("focusout",function(i){r.info("Cancelled editing"),n.replaceWith(e("<span data-type='label'>"+t+"</span>"))}),n.focus()}else f.find("figurecaption input[type=text]")}),f.find("a[data-action='editicon']").on("click",function(t){let l=e("<input type='file' style='display: none;' accept='.png,.svg'/>");l.on("change",function(t){t.stopPropagation(),t.preventDefault();let o=t.originalEvent.target.files[0],d=new FileReader;e(d).on("load",function(t){let o=t.target.result;i.call([{methodname:"block_gradelevel_update_skill",args:{id:s,name:null,icon:o}}])[0].fail(a.fail_report_exception).done(function(t){let i=f.find("figure.levelbadge");i.empty(),i.append(e("<img style='display:none;' src='"+t.icon+"'/>")),i.each(function(){n.setup_badge(this)})}),l.remove()}),d.readAsDataURL(o)}),f.append(l),l.trigger("click")}),f.find("a[data-action='editlevels']").attr("href",l.wwwroot+"/blocks/gradelevel/cfg_skilllevels.php?skill_id="+s),f.find("a[data-action='deleteskill']").each(function(){let l=e(this);d.create({type:d.types.SAVE_CANCEL,title:t.get_string("title_confirmdelete","block_gradelevel"),body:t.get_string("dialog_confirmdeleteskill","block_gradelevel")},l).done(function(e){r.info("Modal done",e),e.setSaveButtonText(t.get_string("delete","core")),e.getRoot().on(c.save,function(e){r.info("Delete Confirmed"),i.call([{methodname:"block_gradelevel_delete_skill",args:{id:s}}])[0].fail(a.fail_report_exception).done(function(e){e.deleted&&f.remove()})})})})}};return s});

View File

@ -0,0 +1,111 @@
/*eslint no-var: "error" */
/*eslint no-unused-vars: "off" */
/*eslint linebreak-style: "off" */
/*eslint no-trailing-spaces: "off" */
/*eslint-env es6*/
// Put this file in path/to/plugin/amd/src
// You can call it anything you like
import {call} from 'core/ajax';
import notification from 'core/notification';
import Vue from 'local_treestudyplan/vue';
import RVComponents from 'local_treestudyplan/report-viewer-components';
import TSComponents from 'local_treestudyplan/treestudyplan-components';
import Debugger from 'local_treestudyplan/debugger';
import {load_strings} from 'local_treestudyplan/string-helper';
import {ProcessStudyplans, fixLineWrappers} from 'local_treestudyplan/studyplan-processor';
import PortalVue from 'local_treestudyplan/portal-vue';
import BootstrapVue from 'local_treestudyplan/bootstrap-vue';
Vue.use(TSComponents);
Vue.use(RVComponents);
Vue.use(PortalVue);
Vue.use(BootstrapVue);
let debug = new Debugger("mytreestudyplan");
debug.enable();
let strings = load_strings({
studyplan: {
},
});
/**
* Initialize the Page
*/
/**
* Initialize the Page
* @param {string} type Type of page to show
* @param {Object} arg Arguments passed
*/
export function init(type="myreport",arg) {
// Make sure on window resize, the line wrappers are repositioned, to fix scrolling issues
window.addEventListener('resize',fixLineWrappers);
let app = new Vue({
el: '#block_mytreestudyplan',
data: {
"studyplans": [],
},
mounted() {
let call_method;
let call_args;
if(type == "teacher"){
call_method = 'local_treestudyplan_get_teacher_studyplan';
call_args = {};
}
else if(type == "teaching"){
call_method = 'local_treestudyplan_get_teaching_studyplans';
call_args = {};
}
else{
call_method = 'local_treestudyplan_get_own_studyplan';
call_args = {};
}
call([{
methodname: call_method,
args: call_args
}])[0].done(function(response){
debug.info("Studyplans:",response);
const timingval = { future: 0, present: 1, past: 2, };
response.sort((a,b) => {
const timinga = TSComponents.studyplanTiming(a);
const timingb = TSComponents.studyplanTiming(b);
let t = timingval[timinga] - timingval[timingb];
if(t == 0){
// sort by start date if timing is equal
t = new Date(b.startdate).getTime() - new Date(a.startdate).getTime();
if (t == 0) {
// sort by name if timing is equal
t = a.name.localeCompare(b.name);
}
}
return t;
});
app.studyplans = ProcessStudyplans(response);
}).fail(notification.exception);
},
created() {
this.$root.$on('redrawLines',()=>{
// Ugly hack, but currently the only way to properly fix scrollablility in the lines
fixLineWrappers();
});
},
updated() {
// Ugly hack, but currently the only way to properly fix scrollablility in the lines
setTimeout(fixLineWrappers, 50);
},
methods: {
},
});
}

View File

@ -1,51 +0,0 @@
/*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 (handle) {
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;
}
};
});
});

View File

@ -1,22 +0,0 @@
/*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 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;
});

View File

@ -1,238 +0,0 @@
/*eslint max-len: ["error", { "code": 150 }]*/
/**!
* @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($) {
/**
* 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;
}
});
});

File diff suppressed because it is too large Load Diff

View File

@ -1,151 +0,0 @@
/*eslint no-var: "error" */
/*eslint no-unused-vars: "off" */
/*eslint-env es6*/
// Put this file in path/to/plugin/amd/src
// You can call it anything you like
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;
let self = {
init: function init() {
// Find skill table and skill id
$skill_table = $("table#level_config");
skill_id = Number($skill_table.attr('data-skill'));
if (!skill_id && skill_id !== 0 && skill_id !== '0') {
debug.error("Cannot find configured skill id");
return;
}
// make sure all uint type numbers are not able to go below 0
$(document).on('input', "input[type=number].uint", function (e) {
let $this = $(this);
if ($this.val() < 0) {
$this.val(0);
}
});
// On click handler for add level link
$("a[data-action=addlevel]").on('click', function (e) {
self.add_levelrow(-255, '', '7F7F7F');
});
// 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);
},
add_levelrow: function (id, points, color) {
// create new row
let $newtr = $("<tr data-rowid='"+id+"'>"
+ "<td><input data-name='points' type='number' class='uint' value='"+points+"'></td>"
+ "<td><input type='text' data-name='color' class='jscolor' value='"+color+"'></td></tr>");
// apply jscolor to new row
$newtr.find("input.jscolor").each(function () {
let picker = new jscolor(this);
});
// and add to the body of the table
$skill_table.find("tbody").append($newtr);
},
refresh: function refresh() {
debug.info("Attempting to refresh");
// perform refresh call
let promises = ajax.call([{
methodname: 'block_gradelevel_list_levels',
args: { skill_id: skill_id },
}]);
// and link promise returns to callbacks
promises[0].done(self.success_refill_table).fail(self.fail_report_exception);
},
submit: function submit(evt) {
let $table = $("table#level_config");
let level_data = [];
$table.find("tbody tr[data-rowid]").each(function () {
let $this = $(this);
let row = {
id: Number($this.attr('data-rowid')),
points: $this.find("input[data-name=points]").val(),
badgecolor: $this.find("input[data-name=color]").val(),
};
if (row.points === "") { row.points = -255; }
row.points = Number(row.points);
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);
},
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) {
//debug.info("Response from webservice: ", response);
let $tbody = $skill_table.find('tbody');
$tbody.empty();
for (let idx in response) {
let lvl = response[idx];
//debug.info("Level:", lvl);
self.add_levelrow(lvl.id, lvl.points, lvl.badgecolor);
}
let $inputs = $tbody.find("input[data-name='points']");
$inputs
.animate({ boxShadow: '0px 0px 5px 3px #3FDFCF'}, 400)
.delay(200)
.animate({ boxShadow: 'none'}, 800);
},
};
return self;
});

View File

@ -1,254 +0,0 @@
/*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/debugger' ], function ($, str, ajax, Debugger) {
let debug = Debugger("renderbadge");
debug.enable();
// function is used to overcome Edge's non-support of CSS4 hex rgba notation (@nov 2018)
/* eslint-disable no-bitwise*/
function hexToRgbA(hex){
/*eslint no-bitwise: "off"*/
if(/^#([A-Fa-f0-9]{3})$/.test(hex)){
let h= hex.substring(1).split('');
let c= '0x'+[h[0], h[0], h[1], h[1], h[2], h[2]].join('');
return 'rgb('+[(c>>16)&255, (c>>8)&255, c&255].join(',')+')';
}
if(/^#([A-Fa-f0-9]{6})$/.test(hex)){
let h= hex.substring(1).split('');
let c= '0x'+h.join('');
return 'rgb('+[(c>>16)&255, (c>>8)&255, c&255].join(',')+')';
}
if(/^#([A-Fa-f0-9]{8})$/.test(hex)){
let h= hex.substring(1).split('');
let c = '0x' + [h[0],h[1],h[2],h[3],h[4],h[5],].join('');
let a= '0x' + [h[6],h[7],].join('');
return 'rgba('+[(c>>16)&255, (c>>8)&255, c&255].join(',')+','+a/255.0+')';
}
throw Error('Invalid hex code: ' + hex);
}
/* eslint-enable no-bitwise */
let self = {
init: function init() {
debug.info("Setting up badge renderers");
// Put whatever you like here. $ is available
// to you as normal.
$("figure.levelbadge").each(function () {
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
let colors = {
base: props.color,
light: self.shadeBlendConvert(0.6, props.color), // 60% lighter
dark: self.shadeBlendConvert(0.3, props.color), // 30% lighter
lightPoint: self.shadeBlendConvert(0.8, props.color), // 80% lighter
reflection: {
lightest: "#ffffff51",
darkest: "#ffffff20",
},
radialGradient: {
x0: 0.75,
y0: 0.25,
r0: 0.05,
x1: 0.6,
y1: 0.4,
r1: 0.4,
},
levelText: "white",
};
// size and position configuration
let config = {
size: Math.min(props.height, props.width),
borderWidth: 0.05, // factor of image size
reflection: {
angle: -20, // relative to horizontal
offset: 0.125, // relative to radius
},
levelText: {
x: 0.5,
y: 0.9,
size: 0.2,
font: "Open Sans, Arial, helvetica, sans-serif",
},
icon: {
x: 0.5,
y: 0.47,
scale: 0.7, // scale to this fraction of image size
}
};
debug.info(" Config", config);
debug.info(" Colors", colors);
debug.info(" Props", props);
// draw main circle
let baseGradient = ctx.createRadialGradient(
config.size * colors.radialGradient.x0,
config.size * colors.radialGradient.y0,
(config.size ) * colors.radialGradient.r0,
config.size * colors.radialGradient.x1,
config.size * colors.radialGradient.y1,
(config.size ) * colors.radialGradient.r1
);
baseGradient.addColorStop(0, hexToRgbA(colors.lightPoint));
baseGradient.addColorStop(1, hexToRgbA(colors.base));
ctx.beginPath();
ctx.fillStyle = baseGradient;
ctx.arc(0.5 * config.size, 0.5 * config.size, config.size / 2, 0, 2 * Math.PI);
ctx.fill();
// draw main reflection
let rflOffset = Math.asin(config.reflection.offset);
let rflAngleRad = (config.reflection.angle / 360.0) * 2 * Math.PI;
debug.info("rflAngleRad:",rflAngleRad);
let rflGradient = ctx.createLinearGradient(
(0.5 - config.reflection.offset * Math.sin(rflAngleRad))/2 * config.size,
(0.5 + config.reflection.offset * Math.cos(rflAngleRad))/2 * config.size,
Math.sin(rflAngleRad)/2 * config.size,
Math.cos(rflAngleRad)/2 * config.size
);
debug.info("rflGradient",rflGradient);
rflGradient.addColorStop(0, hexToRgbA(colors.reflection.lightest));
rflGradient.addColorStop(1, hexToRgbA(colors.reflection.darkest));
ctx.beginPath();
ctx.fillStyle = rflGradient;
ctx.arc(0.5 * config.size, 0.5 * config.size, config.size / 2,
0 + rflOffset + rflAngleRad,
Math.PI - rflOffset + rflAngleRad);
ctx.fill();
debug.info("Starting with border");
// draw empty border
let strokeWidth = config.size * config.borderWidth;
ctx.beginPath();
ctx.strokeStyle = colors.light;
ctx.lineWidth = strokeWidth;
ctx.arc(0.5 * config.size, 0.5 * config.size, config.size / 2 - strokeWidth / 2, 0, 2 * Math.PI);
ctx.stroke();
// draw current progress border
ctx.beginPath();
ctx.strokeStyle = colors.dark;
ctx.lineWidth = strokeWidth;
ctx.arc(0.5 * config.size, 0.5 * config.size, config.size / 2 - strokeWidth / 2,
0 - Math.PI / 2, // -90 degrees (top)
props.progress * 2 * Math.PI - Math.PI / 2 // fraction of whole circle offset with -90 degrees
);
ctx.stroke();
if (props.level) {
// write level in lower part
ctx.font = "" + config.size * config.levelText.size + "px " + config.levelText.font;
ctx.fillStyle = colors.levelText;
ctx.textAlign = "center";
ctx.fillText("" + props.level, config.size * config.levelText.x, config.size * config.levelText.y);
}
/*
var imageObj = new Image();
imageObj.onload = function () {
ctx.drawImage(this, 15, 15, 120, 120);
};
imageObj.src = "https://dev.miqra.nl/blocks/gradelevel/pix/undefinedskill.svg";
*/
// paint image in center
if (props.image) {
let iconImg = new Image();
iconImg.onload = function () {
let imPos = {
x: 0, // to be determined later
y: 0, // to be determined later
w: config.size * config.icon.scale,
h: config.size * config.icon.scale,
};
// preserve aspect ratio
if (this.width > this.height) {
imPos.h *= this.height / this.width;
} else {
imPos.w *= this.width / this.height;
}
// calculate x and y
imPos.x = (config.size * config.icon.x) - (imPos.w / 2);
imPos.y = (config.size * config.icon.y) - (imPos.h / 2);
ctx.drawImage(this, imPos.x, imPos.y, imPos.w, imPos.h);
};
//debug.info("Image: ",props.image);
iconImg.src = props.image;
}
// complete
},
fetchProperties: function fetchProperties(figure) {
let $figure = $(figure);
let $image = $figure.find("img");
let image = null;
if ($image.length > 0) {
image = $image.attr("src");
}
return {
progress: $figure.attr("data-progress"),
width: $figure.attr("data-width"),
height: $figure.attr("data-height"),
color: "#"+$figure.attr("data-color"),
level: $figure.attr("data-level"),
image: image,
};
},
shadeBlendConvert: function shadeBlendConvert(p, from, to) {
/* eslint-disable no-bitwise, max-len, curly, no-var, no-unused-expressions */
// Code for this function was taken from https://github.com/PimpTrizkit/PJs pSBC.js
if (typeof (p) != "number" || p < -1 || p > 1 || typeof (from) != "string" || (from[0] != 'r' && from[0] != '#') || (to && typeof (to) != "string")) return null; //ErrorCheck
if (!this.sbcRip) this.sbcRip = (d) => {
let l = d.length, RGB = {};
if (l > 9) {
d = d.split(",");
if (d.length < 3 || d.length > 4) return null;//ErrorCheck
RGB[0] = i(d[0].split("(")[1]), RGB[1] = i(d[1]), RGB[2] = i(d[2]), RGB[3] = d[3] ? parseFloat(d[3]) : -1;
} else {
if (l == 8 || l == 6 || l < 4) return null; //ErrorCheck
if (l < 6) d = "#" + d[1] + d[1] + d[2] + d[2] + d[3] + d[3] + (l > 4 ? d[4] + "" + d[4] : ""); //3 or 4 digit
d = i(d.slice(1), 16), RGB[0] = d >> 16 & 255, RGB[1] = d >> 8 & 255, RGB[2] = d & 255, RGB[3] = -1;
if (l == 9 || l == 5) RGB[3] = r((RGB[2] / 255) * 10000) / 10000, RGB[2] = RGB[1], RGB[1] = RGB[0], RGB[0] = d >> 24 & 255;
}
return RGB;
};
var i = parseInt, r = Math.round, h = from.length > 9, h = typeof (to) == "string" ? to.length > 9 ? true : to == "c" ? !h : false : h, b = p < 0, p = b ? p * -1 : p, to = to && to != "c" ? to : b ? "#000000" : "#FFFFFF", f = this.sbcRip(from), t = this.sbcRip(to);
if (!f || !t) return null; //ErrorCheck
if (h) return "rgb" + (f[3] > -1 || t[3] > -1 ? "a(" : "(") + r((t[0] - f[0]) * p + f[0]) + "," + r((t[1] - f[1]) * p + f[1]) + "," + r((t[2] - f[2]) * p + f[2]) + (f[3] < 0 && t[3] < 0 ? ")" : "," + (f[3] > -1 && t[3] > -1 ? r(((t[3] - f[3]) * p + f[3]) * 10000) / 10000 : t[3] < 0 ? f[3] : t[3]) + ")");
else return "#" + (0x100000000 + r((t[0] - f[0]) * p + f[0]) * 0x1000000 + r((t[1] - f[1]) * p + f[1]) * 0x10000 + r((t[2] - f[2]) * p + f[2]) * 0x100 + (f[3] > -1 && t[3] > -1 ? r(((t[3] - f[3]) * p + f[3]) * 255) : t[3] > -1 ? r(t[3] * 255) : f[3] > -1 ? r(f[3] * 255) : 255)).toString(16).slice(1, f[3] > -1 || t[3] > -1 ? undefined : -2);
/* eslint-enable no-bitwise, max-len, curly, no-var, no-unused-expressions */
},
};
return self;
});

View File

@ -1,179 +0,0 @@
/*eslint no-var: "error"*/
/*eslint no-unused-vars: "off" */
/*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 (e) {
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 (e) {
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 (e) {
let $uploader = $("<input type='file' style='display: none;' accept='" + uploadFilter + "'/>");
$uploader.on('change', function (e) {
e.stopPropagation();
e.preventDefault();
let file = e.originalEvent.target.files[0];
let fr = new FileReader();
$(fr).on('load', function (e) {
let dataURI = e.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();
}
});
});
});
});
},
};
return self;
});

View File

@ -1,90 +0,0 @@
<?php
require_once($CFG->libdir.'/gradelib.php');
require_once($CFG->dirroot.'/grade/querylib.php');
require_once($CFG->dirroot.'/blocks/gradelevel/lib.php');
use block_gradelevel;
class block_gradelevel extends block_base {
public $levelset;
public function init() {
global $PAGE;
global $COURSE;
$this->title = get_config('gradelevel', 'blocktitle');
if(empty($this->title))
{
$this->title = get_string('title', 'block_gradelevel');
}
// include javascript and run badge renderer when page loading is complete
$PAGE->requires->js_call_amd('block_gradelevel/renderbadge', 'init');
// find or create the levelset for this course
$this->levelset = block_gradelevel_levelset::find_by_course($COURSE->id);
}
// The PHP tag and the curly bracket for the class definition
// will only be closed after there is another function added in the next section.
public function html_attributes() {
$attributes = parent::html_attributes(); // Get default values
$attributes['class'] .= ' block_'. $this->name(); // Append our class to class attribute
return $attributes;
}
public function get_content() {
global $CFG;
global $USER;
global $COURSE;
if ($this->content !== null) {
return $this->content;
}
$this->content = new stdClass;
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 = round($this->levelset->get_levelset_grade($USER->id),1);
$level_info = $this->levelset->calculate_level($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'>{$pointstotal}</span>/<span class='leveluppoints'>{$level_info->next_at}</span></div>";
}
else
{
$this->content->footer = "<div class='pointinfo complete'>".get_string('levelup_done','block_gradelevel')."</div>";
}
$coursecontext = context_course::instance($COURSE->id);
if(has_capability('block/gradelevel:viewresults', $coursecontext))
{
$this->content->footer .= "\n<div class='teachermode'><a href='{$CFG->wwwroot}/blocks/gradelevel/view-results.php?courseid={$COURSE->id}'>".get_string('teacher_view_results','block_gradelevel')."</a></div>";
}
}
return $this->content;
}
public function hide_header() { return !get_config('gradelevel', 'showtitle'); }
public function has_config() { return true; }
}

91
block_mytreestudyplan.php Normal file
View File

@ -0,0 +1,91 @@
<?php
use local_treestudyplan\studyplan;
class block_mytreestudyplan extends \block_base {
public $levelset;
public function init() {
global $PAGE;
global $CFG;
$this->title = get_string('title', 'block_mytreestudyplan');
$systemcontext = \context_system::instance();
$teachermode = has_capability("local/treestudyplan:viewuserreports",$systemcontext);
// Load CSS files from treestudyplan
try{
$PAGE->requires->css(new \moodle_url($CFG->wwwroot.'/local/treestudyplan/css/bootstrap-vue.min.css'));
$PAGE->requires->css(new \moodle_url($CFG->wwwroot.'/local/treestudyplan/css/devstyles.css'));
// include javascript and run studyplan renderer when page loading is complete
$PAGE->requires->js_call_amd('block_mytreestudyplan/block_mytreestudyplan', 'init',[$teachermode?'teaching':'myreport']);
} catch( Exception $x) {
// On some occasions (Plugin management), the plugin is loaded after HEAD has been printed. In those cases we don't want to show the block anyway,
// so ignore the error that gets inevitably thrown
}
}
public function applicable_formats()
{
// Limit this block to the site index and the dashboard (my) pages
return [
'admin' => false,
'site-index' => true,
'course-view' => false,
'mod' => false,
'my' => true
];
}
public function get_content() {
global $CFG;
global $USER;
global $COURSE;
global $OUTPUT;
if ($this->content !== null) {
return $this->content;
}
$coursecontext = \context_course::instance($COURSE->id);
$systemcontext = \context_system::instance();
$teachermode = has_capability("local/treestudyplan:viewuserreports",$systemcontext);
$this->content = new \stdClass;
$this->content->text = "";
$mystudyplans = studyplan::find_for_user($USER->id);
$data = [
'teachermode' => $teachermode,
];
$this->content->text = $OUTPUT->render_from_template("block_mytreestudyplan/block",$data);
$invite_url =$CFG->wwwroot.'/local/treestudyplan/invitations.php';
$invite_text = get_string('manage_invites','local_treestudyplan');
if($teachermode){
$this->content->footer = "<a class='btn btn-primary' href='{$invite_url}'>".get_string("view_plan","local_treestudyplan")."</a>";
if(has_capability("local/treestudyplan:editstudyplan",$systemcontext)){
$this->content->footer .= "&nbsp; <a class='btn btn-primary' href='{$invite_url}'>".get_string("cfg_plans","local_treestudyplan")."</a>";
}
} else if (count($mystudyplans) > 0) {
$this->content->footer = "<a class='btn btn-primary' href='{$invite_url}' id='manage_invites'><i class='fa fa-share'></i>{$invite_text}</a>";
}
return $this->content;
}
public function hide_header() { return false; }
public function has_config() { return false; }
}

View File

@ -1,34 +0,0 @@
<?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_default_levels");
$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/leveleditor', 'init');
print $OUTPUT->header();
print $OUTPUT->heading(get_string('cfgpage_globallevels', 'block_gradelevel'));
// render page for skill level 0 (global)
print block_gradelevel_skillmgmtservice::render_leveltable(0);
print $OUTPUT->footer();

View File

@ -1,48 +0,0 @@
<?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 class='btn' onclick='window.location=\"{$cfg_skills_url}\";'>".get_string('back','core')."</button>";
print $OUTPUT->footer();

View File

@ -1,35 +0,0 @@
<?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();

View File

@ -1,499 +0,0 @@
<?php
require_once($CFG->libdir.'/gradelib.php');
require_once($CFG->dirroot.'/grade/querylib.php');
//namespace block_gradelevel;
class block_gradelevel_levelset {
const UNDEFINED_BADGE_COLOR="#3F3F3F";
const NULL_BADGE_COLOR = "000000";
const DEFAULT_ICON = "/blocks/gradelevel/pix/undefinedskill.svg";
const GLOBAL_DEFAULTS = array(
0 => "#320000",
250 => "#2ad4ff", // + 250
750 => "#cd7f32", // + 500
1750 => "#92A1A6", // + 1000
2750 => "#f6ae00", // + 2000
);
private $id;
private $data;
private $levels = null;
private $global_levels = null;
/**
* Construct a levelset object for an existing database item
*
*/
private function __construct($id = null, $dataObject = null)
{
global $DB;
$this->id = $id;
if($id != null)
{
if(isset($dataObject) && isset($dataObject->id) && $dataObject->id == $id) // slight sanity check
{
$this->data = $dataObject;
}
else {
// database validity check went south, retrieve again
$this->data = $DB->get_record('block_gradelevel_levelset', array('id' => $this->id));
}
//retrieve levels for this levelset
$this->levels = $DB->get_records('block_gradelevel_levels', array('levelset_id' => $this->id));
usort( $this->levels, function( $a, $b) {
return ( $a->points < $b->points ) ? -1 : 1;
} );
}
// retrieve global levels
$this->global_levels = $DB->get_records('block_gradelevel_levels', array('levelset_id' => 0));
usort( $this->global_levels, function( $a, $b) {
return ( $a->points < $b->points ) ? -1 : 1;
} );
// if no global levels are defined, insert default global levels
if(count($this->global_levels) == 0)
{
foreach(static::GLOBAL_DEFAULTS as $points => $color)
{
// setup default
$row = new stdClass;
$row->levelset_id = 0;
$row->points = $points;
$row->badgecolor = $color;
// insert into db
if(!$DB->insert_record('block_gradelevel_levels',$row)){
print_error('inserterror', 'block_gradelevel');
}
}
// and reload global levels;
$this->global_levels = $DB->get_records('block_gradelevel_levels', array('levelset_id' => 0));
usort( $this->global_levels, function( $a, $b) {
return ( $a->points < $b->points ) ? -1 : 1;
} );
}
}
public function getId() : string
{
return $this->id;
}
public function setName(string $name)
{
$this->data->name = $name;
}
public function getName() : string
{
return $this->data->name;
}
public function setIcon(string $iconname)
{
$this->data->icon = $iconname;
}
public function getIcon() : string
{
$icon = $this->data->icon;
if(empty($icon))
{
$icon = static::DEFAULT_ICON;
}
return $icon;
}
/**
* Find a levelset for a given course
*
* @params int $course_id The id of the course to find a levelset for
* @return levelset The levelset for this course or null if none found;
*/
static public function find_by_course($course_id)
{
global $DB;
try {
// FIXME: Make this more efficient by joining it into one sql statement.
$records = $DB->get_records('block_gradelevel_course_link', array('course_id' => $course_id));
if(count($records) > 0)
{
$levelset = $DB->get_record('block_gradelevel_levelset', array('id' => array_values($records)[0]->levelset_id));
if($levelset)
{
return new static($levelset->id,$levelset);
}
}
}
catch(Exception $x){} // catch error if table does not (yet exist)
return null; // return null if no current levelset linked
}
static public function find_by_id(int $id)
{
global $DB;
$levelset = $DB->get_record('block_gradelevel_levelset', array('id' => $id));
if($levelset)
{
return new static($levelset->id,$levelset);
}
else
{
return null;
}
}
/**
* List attached courses for this levelset
*
* @return array An array with the id's of attached courses
*/
public function list_courses()
{
global $DB;
$list = array();
$links = $DB->get_records('block_gradelevel_course_link', array('levelset_id' => $this->id));
foreach($links as $link)
{
$list[] = $link->course_id;
}
return $list;
}
/**
* Attach a course to this levelset. The course will be detached from any other levelsets.
*
* @params int $course_id The id of the course to attach
*/
public function attach_course($course_id)
{
global $DB;
// check if course attachement is already done
if(!in_array($course_id,$this->list_courses))
{
// no, now find an existing attachment for this course
$rows = $DB->get_records('block_gradelevel_course_link', array('course_id' => $course_id));
if(empty($rows))
{
// create new attachment if existing link was not found
$row = new stdClass;
$row->levelset_id = $this->id;
$row->course_id = $course_id;
// insert new row
if(!$DB->insert_record('block_gradelevel_course_link',$row)){
print_error('inserterror', 'block_gradelevel');
}
}
else
{
// update existing link (automatically detaches course from its previous levelset)
$row = array_values($rows)[0];
$row->course_id = $course_id;
// update existing row
if(!$DB->update_record('block_gradelevel_course_link',$row)){
print_error('updateerror', 'block_gradelevel');
}
}
}
}
/**
* Detache a course from this levelset.
*
* @params int $course_id The id of the course to detach
*/
public function detach_course($course_id)
{
global $DB;
$rows = $DB->get_records('block_gradelevel_course_link', array('course_id' => $course_id, 'levelset_id' => $this->id));
if(!empty($rows))
{
if(!$DB->delete_records('block_gradelevel_course_link', array('id' => array_values($rows)[0]->id)))
{
print_error('deleteerror','block_gradelevel');
}
}
}
/**
* Store changes made to the levelset data parameter containing levelset data
*
*/
public function save_data()
{
global $DB;
if($this->data->id == $this->id) // sanity check so we don't kill everything
{
if(!$DB->update_record('block_gradelevel_levelset',$this->data)){
print_error('updateerror', 'block_gradelevel');
}
}
else
{
print_error('datarowchanged_error', 'block_gradelevel');
}
}
/**
* Retrieve point total for all attached courses for a given user
*
* @param int $user_id The id
* @return int Total points for this user in this levelset
*/
public function get_levelset_grade($user_id)
{
// loop through all attached courses and add up the grade points gathered
$points = 0;
foreach($this->list_courses() as $course_id)
{
$result = grade_get_course_grade($user_id,$course_id);
$points += $result->grade;
}
return $points;
}
/**
* Return the levelup data for a given userid in this levelset
*
* @param int $user_id The id
* @return stdClass A stdClass containing the level data for the specified number of point
*/
public function get_user_leveldata($user_id)
{
$points = $this->get_levelset_grade($user_id);
return $this->calculate_level($points);
}
/**
* Create a new levelset
*
* @params string $name Optional name of the new levelset
* @return levelset The new levelset
*/
static public function create_new($name="New levelset")
{
global $DB;
// create a new levelset
$row = new stdClass;
$row->name = $name;
if(!$id = $DB->insert_record('block_gradelevel_levelset',$row, true)){
print_error('inserterror', 'block_gradelevel');
}
else
{
$rows = $DB->get_records('block_gradelevel_levelset', array('id' => $id));
if(count($rows) > 0)
{
return new static($id,array_values($rows)[0]);
}
}
throw new RuntimeException("Could not create new levelset");
}
/**
* List all levelsets
*
* @return array Array of levelset
*/
static public function list_all()
{
global $DB;
$list = array();
$levelsets = $DB->get_records('block_gradelevel_levelset');
foreach($levelsets as $lset)
{
$list[] = new static($lset->id,$lset);
}
return $list;
}
/**
* Calculate the levelup data, given a specified set of points
*
* @params int points The amount of points to calculate for
* @return stdClass A stdClass containing the level data for the specified number of point
*/
public function calculate_level($points){
$levels = $this->badgelevels();
$level = -1;
$badge_color = static::NULL_BADGE_COLOR;
$current_at = 0;
$next_at = 0;
foreach($levels as $threshold => $badgeColor)
{
if($points >= $threshold){
$level++;
$badge_color = $badgeColor;
$current_at = $threshold;
}
else
{
$next_at = $threshold;
break;
}
}
$levelup_points = $next_at - $current_at;
$points_in_level = $points - $current_at;
if($levelup_points <= 0){ // at max level
$progress = 0;
$points_in_level = 0;
}
else
{
$progress = $points_in_level / $levelup_points;
}
$result = new stdClass;
$result->level = $level;
$result->badge_color = $badge_color;
$result->progress = $progress;
$result->next_at = round($next_at);
$result->levelup_total = round($levelup_points);
$result->points_in_level = round($points_in_level);
return $result;
}
/**
* Simplified list of levels and associated badge colors for this levelset
* Takes data from global levelset if more specialized data is not set
*
* @return array An array of points (keys) and badge color (values), sorted by level
*/
public function badgelevels()
{
$level_info = array();
// If we have levels defined, use those, otherwise use the global levels
if(!empty($this->levels))
{
if(array_values($this->levels)[0]->points > 0)
{
// insert level 0
$level_info[0] = static::NULL_BADGE_COLOR;
}
$i = 0;
foreach($this->levels as $lvl)
{
// Check if color is properly set or needs to be retrieved from global config
if(!empty($lvl->badgecolor)) {
$color = $lvl->badgecolor;
}
else
{
$color = static::UNDEFINED_BADGE_COLOR;
}
$level_info[$lvl->points] = $color;
$i++;
}
}
else
{
if(empty($this->global_levels) || array_values($this->global_levels)[0]->points > 0)
{
// insert level 1 if levels don't start at 0 points,
// or if no global levels are defined. - At least start somewhere...
$level_info[0] = static::NULL_BADGE_COLOR;
}
// use global levels if levelset is not defined.
foreach($this->global_levels as $lvl)
{
// Check if color is properly set
if(!empty($lvl->badgecolor)) {
$color = $lvl->badgecolor;
}
else
{
$color = static::UNDEFINED_BADGE_COLOR;
}
$level_info[$lvl->points] = $color;
}
}
return $level_info;
}
public function render_badge(int $points,int $size=150){
global $CFG;
$info = $this->calculate_level($points);
$image = $this->getIcon();
if(strncmp($image,"data:",5) == 0)
{
$image_url = $CFG->wwwroot."/blocks/gradelevel/view-icon.php?skillid=".$this->id;
}
else
{
$image_url = $image;
}
$html = "<figure class='levelbadge weird'";
$html .= " data-color='{$info->badge_color}'";
$html .= " data-progress='{$info->progress}'";
$html .= " data-level='{$info->level}'";
$html .= " data-width='{$size}'";
$html .= " data-height='{$size}'";
$html .= ">";
if(!empty($image))
{
$html .= "<img style='display:none' src='{$image_url}' />";
}
$html .= "</figure>";
return $html;
}
public function render_demo_badge(int $size=100, $level=null)
{
$levels = $this->badgelevels();
if($level === null || $level > count($levels))
{
$points = array_pop(array_keys($levels));
}
else
{
$points = array_keys($levels)[$level];
}
return $this->render_badge($points, $size);
}
}

View File

@ -1,473 +0,0 @@
<?php
require_once($CFG->libdir.'/gradelib.php');
require_once($CFG->libdir.'/externallib.php');
require_once($CFG->dirroot.'/grade/querylib.php');
//namespace block_gradelevel;
class block_gradelevel_skillmgmtservice extends external_api
{
const DEBUG = false; // enable debug logging
const DEMOBADGE_SIZE = 150; // size of demo badge
private static function log($message)
{
if(self::DEBUG)
{
error_log($message."\n",3,"/tmp/block_gradelevel.log");
}
}
private static function list_courses($skill_id)
{
global $DB;
$list = array();
$links = $DB->get_records('block_gradelevel_course_link', array('levelset_id' => $skill_id));
foreach($links as $link)
{
$list[] = $link->course_id;
}
return $list;
}
// Input parameter config
public static function submit_levels_parameters()
{
return new external_function_parameters(
array(
'skill_id' => new external_value(PARAM_INT, 'id of skill'),
'levels' => new external_multiple_structure(
new external_single_structure(
array(
'id' => new external_value(PARAM_INT, 'id of level'),
'points' => new external_value(PARAM_INT, 'number of points for this level'),
'badgecolor' => new external_value(PARAM_TEXT, 'color of level badge'),
)
)
)
)
);
}
public static function list_levels_parameters()
{
return new external_function_parameters(
array(
'skill_id' => new external_value(PARAM_INT, 'id of skill'),
)
);
}
public static function list_skills_parameters()
{
return new external_function_parameters( array() );
}
public static function get_skill_parameters()
{
return new external_function_parameters(
array(
'id' => new external_value(PARAM_INT, 'id of skill'),
)
);
}
public static function update_skill_parameters()
{
return new external_function_parameters(
array(
'id' => new external_value(PARAM_INT, 'id of skill'),
'name' => new external_value(PARAM_TEXT, 'Name of skill'),
'icon' => new external_value(PARAM_RAW, 'Icon for skill'),
)
);
}
public static function add_skill_parameters()
{
return new external_function_parameters(
array(
'name' => new external_value(PARAM_TEXT, 'Name of skill'),
'icon' => new external_value(PARAM_RAW, 'Icon for skill'),
)
);
}
public static function delete_skill_parameters()
{
return new external_function_parameters(
array(
'id' => new external_value(PARAM_INT, 'Id of skill'),
)
);
}
// Output parameter config
public static function submit_levels_returns()
{
return new external_multiple_structure(
new external_single_structure(
array(
'id' => new external_value(PARAM_INT, 'id of level'),
'points' => new external_value(PARAM_INT, 'number of points for this level'),
'badgecolor' => new external_value(PARAM_TEXT, 'color of level badge'),
)
)
);
}
public static function list_levels_returns()
{
return new external_multiple_structure(
new external_single_structure(
array(
'id' => new external_value(PARAM_INT, 'id of level'),
'points' => new external_value(PARAM_INT, 'number of points for this level'),
'badgecolor' => new external_value(PARAM_TEXT, 'color of level badge'),
)
)
);
}
public static function list_skills_returns()
{
return new external_multiple_structure(
new external_single_structure(
array(
'id' => new external_value(PARAM_INT, 'Id of skill'),
'name' => new external_value(PARAM_TEXT, 'Name of skill'),
'icon' => new external_value(PARAM_RAW, 'Icon for skill'),
'html' => new external_value(PARAM_RAW, 'Demo badge'),
)
)
);
}
public static function get_skill_returns()
{
return new external_single_structure(
array(
'name' => new external_value(PARAM_TEXT, 'Name of skill'),
'icon' => new external_value(PARAM_RAW, 'Icon for skill'),
'html' => new external_value(PARAM_RAW, 'Demo badge'),
)
);
}
public static function update_skill_returns()
{
return new external_single_structure(
array(
'id' => new external_value(PARAM_INT, 'Id of skill'),
'name' => new external_value(PARAM_TEXT, 'Name of skill'),
'icon' => new external_value(PARAM_RAW, 'Icon for skill'),
'html' => new external_value(PARAM_RAW, 'Demo badge'),
)
);
}
public static function add_skill_returns()
{
return new external_single_structure(
array(
'id' => new external_value(PARAM_INT, 'Id of skill'),
'name' => new external_value(PARAM_TEXT, 'Name of skill'),
'icon' => new external_value(PARAM_RAW, 'Icon for skill'),
'html' => new external_value(PARAM_RAW, 'Demo badge'),
)
);
}
public static function delete_skill_returns()
{
return new external_single_structure(
array(
'id' => new external_value(PARAM_INT, 'Id of skill'),
'deleted' => new external_value(PARAM_BOOL, 'Deletion succesful'),
)
);
}
// Actual functions
public static function submit_levels(int $skill_id, array $levels)
{
global $CFG, $DB;
self::log("submit_levels called, skill_id: {$skill_id}, levels: \n".print_r($levels,true));
$systemcontext = context_system::instance();
self::validate_context($systemcontext);
foreach($levels as $lvl_raw)
{
// convert level array to stdObj
$lvl = (object) $lvl_raw;
$lvl->levelset_id = $skill_id;
self::log("Processing level: ".print_r($lvl,true));
if($lvl->points >= 0)
{
if($lvl->id >= 0)
{
// Update record
self::log("updating row {$lvl->id}: {$lvl->points}, {$lvl->badgecolor} @ {$lvl->levelset_id}");
$DB->update_record('block_gradelevel_levels',$lvl);
}
else
{
// unset invalid id before insert
unset($lvl->id);
self::log("inserting new row {$lvl->points}, {$lvl->badgecolor} @ {$lvl->levelset_id}");
// Insert record
$DB->insert_record('block_gradelevel_levels',$lvl);
}
}
else
{
// points is empty: delete record if we have a valid id.
if($lvl->id >= 0)
{
self::log("deleting empty row {$lvl->id}");
$DB->delete_records('block_gradelevel_levels', array('id' => $lvl->id));
}
else
{
self::log("ignoring empty row");
}
}/**/
}
return static::list_levels($skill_id);
}
public static function list_levels(int $skill_id)
{
global $CFG, $DB;
$levels = $DB->get_records('block_gradelevel_levels', array('levelset_id' => $skill_id));
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;
}
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;
}
}
public static function list_skills()
{
global $CFG, $DB;
$skills = $DB->get_records('block_gradelevel_levelset');
// Sort by points
usort( $skills, function( $a, $b) {
return ( $a->name < $b->name) ? -1 : 1;
} );
foreach($skills as $skill )
{
$skill->html = block_gradelevel_levelset::find_by_id($skill->id)->render_demo_badge(static::DEMOBADGE_SIZE);
}
return $skills;
}
public static function get_skill(int $id)
{
global $CFG, $DB;
$skill = $DB->get_record('block_gradelevel_levels', array('id' => $id));
$skill->html = block_gradelevel_levelset::find_by_id($skill->id)->render_demo_badge(static::DEMOBADGE_SIZE);
return $skill;
}
public static function update_skill(int $id, $name, $icon )
{
global $CFG, $DB;
$skill = $DB->get_record('block_gradelevel_levelset', array('id' => $id));
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($name, $icon)
{
global $CFG, $DB;
$skill = new stdClass;
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 = static::single_skill_editor_item(block_gradelevel_levelset::find_by_id($skill->id));
return $skill;
}
public static function delete_skill(int $id)
{
global $CFG, $DB;
$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 = array('id' => $id);
$result['deleted'] = ($DB->delete_records('block_gradelevel_levelset',array('id' => $id)))?true:false;
return $result;
}
// Other public functions
public static function render_leveltable($skill_id)
{
$levels = static::list_levels($skill_id);
$s = "<p>".get_string('levelcfg_description','block_gradelevel')."</p>";
$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)
{
$color = ltrim($lvl->badgecolor,"#"); // trim any leading hashes
$s .= "<tr data-rowid='{$lvl->id}'><td><input data-name='points' type='number' class='uint' value='{$lvl->points}'></td><td><input type='text' data-name='color' class='jscolor' value='{$color}'></td></tr>";
}
$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 .= "<br><p><button class='btn btn-primary' data-action='savechanges'>".get_string('savechanges','core')."</button>";
if($skill_id > 0)
{
$s .= " <button class='btn' data-action='resetlevels'>".get_string('cfg_resetlevels','block_gradelevel')."</button>";
}
$s .= "</p>";
return $s;
}
public static function render_skill_list()
{
global $CFG;
$skills = block_gradelevel_levelset::list_all();
// 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)
{
$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()) == 0){
$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;
}
}

View File

@ -1,17 +1,7 @@
<?php
$capabilities = array(
'block/gradelevel:myaddinstance' => array(
'captype' => 'write',
'contextlevel' => CONTEXT_SYSTEM,
'archetypes' => array(
'user' => CAP_ALLOW
),
'clonepermissionsfrom' => 'moodle/my:manageblocks'
),
'block/gradelevel:addinstance' => array(
'block/mytreestudyplan:addinstance' => array(
'riskbitmask' => RISK_SPAM | RISK_XSS,
'captype' => 'write',
@ -24,26 +14,5 @@
'clonepermissionsfrom' => 'moodle/site:manageblocks'
),
'block/gradelevel:skillmanager' => array(
'riskbitmask' => RISK_CONFIG | RISK_DATALOSS | RISK_XSS,
'captype' => 'write',
'contextlevel' => CONTEXT_SYSTEM,
'archetypes' => array(
'manager' => CAP_ALLOW
),
),
'block/gradelevel:viewresults' => array(
'riskbitmask' => RISK_DATALOSS | RISK_XSS,
'captype' => 'write',
'contextlevel' => CONTEXT_BLOCK,
'archetypes' => array(
'editingteacher' => CAP_ALLOW,
'manager' => CAP_ALLOW
),
),
);

View File

@ -1,44 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<XMLDB PATH="blocks/gradelevel/db" VERSION="20180917" COMMENT="XMLDB file for Moodle blocks/gradelevel"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../../../lib/xmldb/xmldb.xsd"
>
<TABLES>
<TABLE NAME="block_gradelevel_levelset" COMMENT="Level set table">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="name" TYPE="char" LENGTH="128" NOTNULL="false" SEQUENCE="false" COMMENT="Name of this level set"/>
<FIELD NAME="parent_id" TYPE="int" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="Optional parent for this level set (references another level set)"/>
<FIELD NAME="icon" TYPE="text" NOTNULL="false" SEQUENCE="false"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="parent_id_idx" TYPE="foreign" FIELDS="parent_id" REFTABLE="block_gradelevel_levelset" REFFIELDS="id" COMMENT="Parent index for nested levelsets"/>
</KEYS>
</TABLE>
<TABLE NAME="block_gradelevel_levels" COMMENT="Level references">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="levelset_id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="Reference to specific levelset"/>
<FIELD NAME="points" TYPE="int" LENGTH="10" NOTNULL="true" DEFAULT="0" SEQUENCE="false" COMMENT="Number of points needed to reach this level"/>
<FIELD NAME="badgecolor" TYPE="char" LENGTH="10" NOTNULL="false" SEQUENCE="false" COMMENT="Color of the level badge. Leave null to use default color (of the levelset 0 set)"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="levelset_id_idx" TYPE="foreign" FIELDS="levelset_id" REFTABLE="block_gradelevel_levelset" REFFIELDS="id" COMMENT="Index for levelset reference"/>
</KEYS>
</TABLE>
<TABLE NAME="block_gradelevel_course_link" COMMENT="Link courses to level sets">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="course_id" TYPE="int" LENGTH="20" NOTNULL="true" SEQUENCE="false" COMMENT="Id of the course to link"/>
<FIELD NAME="levelset_id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false" COMMENT="ID of the levelset a course links to"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="course_id_idx" TYPE="foreign-unique" FIELDS="course_id" REFTABLE="mdl_course" REFFIELDS="id" COMMENT="Course Id index"/>
<KEY NAME="levelset_id_idx" TYPE="foreign" FIELDS="levelset_id" REFTABLE="block_gradelevel_levelset" REFFIELDS="id" COMMENT="Levelset id reference"/>
</KEYS>
</TABLE>
</TABLES>
</XMLDB>

View File

@ -1,93 +0,0 @@
<?php
$services = array(
"Gradelevel Level Management" => array(
'functions' => array('block_gradelevel_submit_levels', 'block_gradelevel_list_levels'),
'requiredcapability' => 'block/gradelevel:changelevels',
'shortname'=> 'block_gradelevel_levelmgmt',
'restrictedusers' => 0,
'enabled' => 0,
'ajax' => true,
),
);
$functions = array(
'block_gradelevel_submit_levels' => array( //web service function name
'classname' => 'block_gradelevel_skillmgmtservice', //class containing the external function
'methodname' => 'submit_levels', //external function name
'classpath' => 'blocks/gradelevel/skillmgmtservice.php', //file containing the class/external function
'description' => 'Update level settings for a given skill', //human readable description of the web service function
'type' => 'write', //database rights of the web service function (read, write)
'ajax' => true,
'capabilities' => 'block/gradelevel:skillmanager',
'loginrequired' => true,
'services' => array('block_gradelevel_levelmgmt'),
),
'block_gradelevel_list_levels' => array( //web service function name
'classname' => 'block_gradelevel_skillmgmtservice', //class containing the external function
'methodname' => 'list_levels', //external function name
'classpath' => 'blocks/gradelevel/skillmgmtservice.php', //file containing the class/external function
'description' => 'List level settings for a given skill', //human readable description of the web service function
'type' => 'read', //database rights of the web service function (read, write)
'ajax' => true,
'capabilities' => 'block/gradelevel:skillmanager',
'loginrequired' => true,
'services' => array('block_gradelevel_levelmgmt'),
),
'block_gradelevel_list_skills' => array( //web service function name
'classname' => 'block_gradelevel_skillmgmtservice', //class containing the external function
'methodname' => 'list_skills', //external function name
'classpath' => 'blocks/gradelevel/skillmgmtservice.php', //file containing the class/external function
'description' => 'List skills', //human readable description of the web service function
'type' => 'read', //database rights of the web service function (read, write)
'ajax' => true,
'capabilities' => 'block/gradelevel:skillmanager',
'loginrequired' => true,
'services' => array('block_gradelevel_levelmgmt'),
),
'block_gradelevel_get_skill' => array( //web service function name
'classname' => 'block_gradelevel_skillmgmtservice', //class containing the external function
'methodname' => 'get_skill', //external function name
'classpath' => 'blocks/gradelevel/skillmgmtservice.php', //file containing the class/external function
'description' => 'Retrieve skill information', //human readable description of the web service function
'type' => 'read', //database rights of the web service function (read, write)
'ajax' => true,
'capabilities' => 'block/gradelevel:skillmanager',
'loginrequired' => true,
'services' => array('block_gradelevel_levelmgmt'),
),
'block_gradelevel_update_skill' => array( //web service function name
'classname' => 'block_gradelevel_skillmgmtservice', //class containing the external function
'methodname' => 'update_skill', //external function name
'classpath' => 'blocks/gradelevel/skillmgmtservice.php', //file containing the class/external function
'description' => 'Update a skill', //human readable description of the web service function
'type' => 'read', //database rights of the web service function (read, write)
'ajax' => true,
'capabilities' => 'block/gradelevel:skillmanager',
'loginrequired' => true,
'services' => array('block_gradelevel_levelmgmt'),
),
'block_gradelevel_add_skill' => array( //web service function name
'classname' => 'block_gradelevel_skillmgmtservice', //class containing the external function
'methodname' => 'add_skill', //external function name
'classpath' => 'blocks/gradelevel/skillmgmtservice.php', //file containing the class/external function
'description' => 'Add a new skill', //human readable description of the web service function
'type' => 'read', //database rights of the web service function (read, write)
'ajax' => true,
'capabilities' => 'block/gradelevel:skillmanager',
'loginrequired' => true,
'services' => array('block_gradelevel_levelmgmt'),
),
'block_gradelevel_delete_skill' => array( //web service function name
'classname' => 'block_gradelevel_skillmgmtservice', //class containing the external function
'methodname' => 'delete_skill', //external function name
'classpath' => 'blocks/gradelevel/skillmgmtservice.php', //file containing the class/external function
'description' => 'Delete a skill', //human readable description of the web service function
'type' => 'read', //database rights of the web service function (read, write)
'ajax' => true,
'capabilities' => 'block/gradelevel:skillmanager',
'loginrequired' => true,
'services' => array('block_gradelevel_levelmgmt'),
),
);

View File

@ -1,70 +0,0 @@
<?php
function xmldb_block_gradelevel_upgrade($oldversion) {
global $DB;
$dbman = $DB->get_manager();
/// Add a new column newcol to the mdl_myqtype_options
if ($oldversion < 2018091600) {
// Define table block_gradelevel_levelset to be created.
$table = new xmldb_table('block_gradelevel_levelset');
// Adding fields to table block_gradelevel_levelset.
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
$table->add_field('name', XMLDB_TYPE_CHAR, '128', null, null, null, null);
$table->add_field('parent_id', XMLDB_TYPE_INTEGER, '10', null, null, null, null);
$table->add_field('icon', XMLDB_TYPE_TEXT, null, null, null, null, null);
// Adding keys to table block_gradelevel_levelset.
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
$table->add_key('parent_id_idx', XMLDB_KEY_FOREIGN, array('parent_id'), 'block_gradelevel_levelset', array('id'));
// Conditionally launch create table for block_gradelevel_levelset.
if (!$dbman->table_exists($table)) {
$dbman->create_table($table);
}
// Define table block_gradelevel_levels to be created.
$table = new xmldb_table('block_gradelevel_levels');
// Adding fields to table block_gradelevel_levels.
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
$table->add_field('levelset_id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
$table->add_field('points', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0');
$table->add_field('badgecolor', XMLDB_TYPE_CHAR, '10', null, null, null, null);
// Adding keys to table block_gradelevel_levels.
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
$table->add_key('levelset_id_idx', XMLDB_KEY_FOREIGN, array('levelset_id'), 'block_gradelevel_levelset', array('id'));
// Conditionally launch create table for block_gradelevel_levels.
if (!$dbman->table_exists($table)) {
$dbman->create_table($table);
}
// Define table block_gradelevel_course_link to be created.
$table = new xmldb_table('block_gradelevel_course_link');
// Adding fields to table block_gradelevel_course_link.
$table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null);
$table->add_field('course_id', XMLDB_TYPE_INTEGER, '20', null, XMLDB_NOTNULL, null, null);
$table->add_field('levelset_id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, null);
// Adding keys to table block_gradelevel_course_link.
$table->add_key('primary', XMLDB_KEY_PRIMARY, array('id'));
$table->add_key('course_id_idx', XMLDB_KEY_FOREIGN_UNIQUE, array('course_id'), 'mdl_course', array('id'));
$table->add_key('levelset_id_idx', XMLDB_KEY_FOREIGN, array('levelset_id'), 'block_gradelevel_levelset', array('id'));
// Conditionally launch create table for block_gradelevel_course_link.
if (!$dbman->table_exists($table)) {
$dbman->create_table($table);
}
// Gradelevel savepoint reached.
upgrade_block_savepoint(true, 2018091600, 'gradelevel');
}
return true;
}

View File

@ -1,184 +0,0 @@
USER: stdClass Object
(
[id] => 2
[auth] => manual
[confirmed] => 1
[policyagreed] => 0
[deleted] => 0
[suspended] => 0
[mnethostid] => 1
[username] => admin
[idnumber] =>
[firstname] => Admin
[lastname] => User
[email] => pm@miqra.nl
[emailstop] => 0
[icq] =>
[skype] =>
[yahoo] =>
[aim] =>
[msn] =>
[phone1] =>
[phone2] =>
[institution] =>
[department] =>
[address] =>
[city] =>
[country] =>
[lang] => en
[calendartype] => gregorian
[theme] =>
[timezone] => 99
[firstaccess] => 1530717879
[lastaccess] => 1536959033
[lastlogin] => 1530732921
[currentlogin] => 1536953353
[lastip] => 2001:985:a081:1:5dfc:c799:21e1:4fdc
[secret] =>
[picture] => 0
[url] =>
[descriptionformat] => 1
[mailformat] => 1
[maildigest] => 0
[maildisplay] => 1
[autosubscribe] => 1
[trackforums] => 0
[timecreated] => 0
[timemodified] => 1530717931
[trustbitmask] => 0
[imagealt] =>
[lastnamephonetic] =>
[firstnamephonetic] =>
[middlename] =>
[alternatename] =>
[lastcourseaccess] => Array
(
[2] => 1530738819
)
[currentcourseaccess] => Array
(
[2] => 1536959033
)
[groupmember] => Array
(
)
[profile] => Array
(
)
[sesskey] => ejGT6VqIBv
[ajax_updatable_user_prefs] => Array
(
[drawer-open-nav] => alpha
[filepicker_recentrepository] => int
[filepicker_recentlicense] => safedir
[filepicker_recentviewmode] => int
[filemanager_recentviewmode] => int
)
[editing] => 1
[preference] => Array
(
[core_message_migrate_data] => 1
[auth_manual_passwordupdatetime] => 1530717931
[email_bounce_count] => 1
[email_send_count] => 1
[filepicker_recentrepository] => 4
[filepicker_recentlicense] => allrightsreserved
[login_failed_count_since_success] => 6
[ifirst] =>
[ilast] =>
[_lastloaded] => 1536959033
)
[enrol] => Array
(
[enrolled] => Array
(
[2] => 2147483647
)
[tempguest] => Array
(
)
)
[grade_last_report] => Array
(
[2] => grader
)
[gradeediting] => Array
(
[2] => 0
)
[access] => Array
(
[ra] => Array
(
[/1] => Array
(
[7] => 7
)
[/1/2] => Array
(
[8] => 8
)
[/1/40/23] => Array
(
[3] => 3
[5] => 5
)
)
[time] => 1536958657
[rsw] => Array
(
)
)
)
COURSE: stdClass Object
(
[id] => 2
[category] => 2
[sortorder] => 20001
[fullname] => PIC Microcontrollers programmeren
[shortname] => PIC-MCU3
[idnumber] =>
[summary] => Programmeren van PIC18 microcontrollers van microchip.
[summaryformat] => 1
[format] => topics
[showgrades] => 1
[newsitems] => 0
[startdate] => 1526594400
[enddate] => 0
[marker] => 0
[maxbytes] => 0
[legacyfiles] => 0
[showreports] => 0
[visible] => 1
[visibleold] => 1
[groupmode] => 0
[groupmodeforce] => 0
[defaultgroupingid] => 0
[lang] =>
[calendartype] =>
[theme] =>
[timecreated] => 1526555879
[timemodified] => 1536956992
[requested] => 0
[enablecompletion] => 1
[completionnotify] => 0
[cacherev] => 1536956992
)

View File

@ -1,82 +0,0 @@
<?php
require_once($CFG->dirroot.'/blocks/gradelevel/lib.php');
class block_gradelevel_edit_form extends block_edit_form {
protected function specific_definition($mform) {
global $CFG;
// retrieve levelset
$levelset = $this->block->levelset;
// Section header title according to language file.
$mform->addElement('header', 'config_header', get_string('blocksettings', 'block'));
$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)
{
$options[$skill->getId()] = $skill->getName();
}
// A sample string variable with a default value.
$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
$skill = block_gradelevel_levelset::find_by_course($COURSE->id);
if(isset($skill)){
$defaults->attached_skill = $skill->getId();
}
parent::set_data($defaults);
}
public function get_data()
{
$data = parent::get_data();
if(isset($data))
{
$this->save_data($data);
}
return $data;
}
protected function save_data($data)
{
global $COURSE;
// retrieve levelset
if(isset($data->attached_skill))
{
$currentskill = block_gradelevel_levelset::find_by_course($COURSE->id);
if(isset($currentskill))
{
$currentskill->detach_course($COURSE->id);
}
$skill = block_gradelevel_levelset::find_by_id($data->attached_skill);
if(isset($skill)){
$skill->attach_course($COURSE->id);
}
}
}
}

View File

@ -1,54 +0,0 @@
<?php
$string['pluginname'] = 'Grade Levelup';
$string['gradelevel'] = 'GradeLevel';
$string['title'] = 'Progress level';
$string['gradelevel:addinstance'] = 'Add a new Grade Level block';
$string['gradelevel:myaddinstance'] = 'Add a new Grade Level block to the My Moodle page';
$string['blockstring'] = 'Text in the block';
$string['levelup_at'] = 'Progress: ';
$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['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['results_heading'] = "Results for skill ";
$string['results_ungrouped'] = "Other";
$string['descconfig'] = "Configuration for Grade Level block";
$string['labeltitle'] = "Title of gradelevel block";
$string['desctitle'] = "The title of the gradelevel block in the courses";
$string['labelshowtitle'] = "Show title bar in block";
$string['descshowtitle'] = "Whether the block should show a title bar or not";
$string['labelnumlevels'] = "Number of deault levels";
$string['descnumlevels'] = "The number of levels that is set by default for all skills";
$string['levelcfg_description'] = "Levels will be sorted based on points. Make sure to set the points incrementally. Leave points empty to remove level";
$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[''] = "";

View File

@ -0,0 +1,6 @@
<?php
$string['pluginname'] = 'My Treestudyplan';
$string['mytreestudyplan'] = 'MyTreestudyplan';
$string['title'] = 'My Studyplan';
$string['mytreestudyplan:addinstance'] = 'Add my studyplan block';

View File

@ -1,50 +0,0 @@
<?php
$string['pluginname'] = 'Cijferniveaus';
$string['gradelevel'] = 'GradeLevel';
$string['title'] = 'Voortgang Level';
$string['gradelevel:addinstance'] = 'Voeg een GradeLevel block toe';
$string['gradelevel:myaddinstance'] = 'Voeg een GradeLevel block aan mijn moodle toe';
$string['blockstring'] = 'Tekst in het blok';
$string['levelup_at'] = 'Voortgang: ';
$string['levelup_done'] = 'Klaar';
$string['unattached_course'] = 'Koppel deze cursus aan een skill in de eigenschappen van het blok.';
$string['teacher_view_results'] = 'Bekijk resultaten studenten';
$string['edit_pickskill'] = "Koppelen aan skill";
$string['edit_noneskill'] = "Geen";
$string['cfgpage_generic'] = "GradeLevel instellingen";
$string['cfgpage_globallevels'] = "Standaard levels";
$string['cfgpage_skilllevels'] = "Levels aanpassen";
$string['cfgpage_skills'] = "Skills beheren";
$string['cfgpage_editskill'] = "Skill aanpassen";
$string['results_heading'] = "Resultaten voor ";
$string['results_ungrouped'] = "Overig";
$string['descconfig'] = "Instellingen voor GradeLevel blok";
$string['labeltitle'] = "Titel van het gradelevel blok";
$string['desctitle'] = "De titel van het blok in de cursus";
$string['labelshowtitle'] = "Laat titelbalk in het blok zien";
$string['descshowtitle'] = "Geef aan of wel of niet de titel van het blok moet worden getoond";
$string['levelcfg_description'] = "Levels worden na opslaan gesorteerd op punten. Laat aantel punten leeg om een level te verwijderen";
$string['levelcfg_head_points'] = "Punten";
$string['levelcfg_head_color'] = "Badgekleur";
$string['levelcfg_addlevel'] = "Level toevoegen";
$string['tooltip_editicon'] = "Icoon aanpassen";
$string['tooltip_editname'] = "Naam aanpassen";
$string['tooltip_deleteskill'] = "Skill verwijderen";
$string['tooltip_deleteskill_disabled'] = "Skill kan niet worden verwijderd, omdat er cursussen aan gekoppeld zijn.";
$string['defaults_name'] = "Nieuwe skill";
$string['cfg_resetlevels'] = "Reset levels naar standaard";
$string['cfg_addskill'] = "Skill toevoegen";
$string['title_confirmdelete'] = "Bevestig verwijderen";
$string['dialog_confirmdeleteskill'] = "Week je zeker dat je deze skill witl verwijderen?";
//$string[''] = "";

View File

@ -0,0 +1,6 @@
<?php
$string['pluginname'] = 'Mijn Treestudyplan';
$string['mytreestudyplan'] = 'MyTreestudyplan';
$string['title'] = 'Mijn Studieplan';
$string['mytreestudyplan:addinstance'] = 'Voeg mijn studieplan block toe';

View File

@ -1,4 +1 @@
<?php
require_once($CFG->libdir.'/gradelib.php');
require_once($CFG->dirroot.'/grade/querylib.php');

3
package-lock.json generated
View File

@ -1,3 +0,0 @@
{
"lockfileVersion": 1
}

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -1,772 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="25mm"
height="25mm"
viewBox="0 0 25.000001 25"
version="1.1"
id="svg11763"
inkscape:version="0.92.1 r15371"
sodipodi:docname="base.svg">
<defs
id="defs11757">
<linearGradient
id="linearGradient26476"
inkscape:collect="always">
<stop
id="stop26472"
offset="0"
style="stop-color:#f0f0f0;stop-opacity:1" />
<stop
id="stop26474"
offset="1"
style="stop-color:#a6a6a6;stop-opacity:1" />
</linearGradient>
<linearGradient
id="linearGradient7518"
inkscape:collect="always">
<stop
id="stop7514"
offset="0"
style="stop-color:#fbfbfb;stop-opacity:0.31764707" />
<stop
id="stop7516"
offset="1"
style="stop-color:#ffffff;stop-opacity:0.1255814" />
</linearGradient>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient26476"
id="radialGradient12749"
gradientUnits="userSpaceOnUse"
cx="50"
cy="92"
fx="50"
fy="92"
r="15.5" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient26476"
id="radialGradient12765"
gradientUnits="userSpaceOnUse"
cx="50"
cy="92"
fx="50"
fy="92"
r="15.5" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient26476"
id="radialGradient12781"
gradientUnits="userSpaceOnUse"
cx="50"
cy="92"
fx="50"
fy="92"
r="15.5" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient26476"
id="radialGradient12797"
gradientUnits="userSpaceOnUse"
cx="50"
cy="92"
fx="50"
fy="92"
r="15.5" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient26476"
id="radialGradient12813"
gradientUnits="userSpaceOnUse"
cx="50"
cy="92"
fx="50"
fy="92"
r="15.5" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient26476"
id="radialGradient12829"
gradientUnits="userSpaceOnUse"
cx="50"
cy="92"
fx="50"
fy="92"
r="15.5" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient26476"
id="radialGradient12845"
gradientUnits="userSpaceOnUse"
cx="50"
cy="92"
fx="50"
fy="92"
r="15.5" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient26476"
id="radialGradient12861"
gradientUnits="userSpaceOnUse"
cx="50"
cy="92"
fx="50"
fy="92"
r="15.5" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient26476"
id="radialGradient12877"
gradientUnits="userSpaceOnUse"
cx="50"
cy="92"
fx="50"
fy="92"
r="15.5" />
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient26476"
id="radialGradient12893"
gradientUnits="userSpaceOnUse"
cx="50"
cy="92"
fx="50"
fy="92"
r="15.5" />
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8574"
style="fill:#f9f9f9;fill-opacity:1;fill-rule:evenodd;stroke:#f9f9f9;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="marker12913"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path12911"
style="fill:#f9f9f9;fill-opacity:1;fill-rule:evenodd;stroke:#f9f9f9;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="marker12917"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path12915"
style="fill:#f9f9f9;fill-opacity:1;fill-rule:evenodd;stroke:#f9f9f9;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient26476"
id="radialGradient12919"
gradientUnits="userSpaceOnUse"
cx="50"
cy="92"
fx="50"
fy="92"
r="15.5" />
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="marker12937"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path12935"
style="fill:#f9f9f9;fill-opacity:1;fill-rule:evenodd;stroke:#f9f9f9;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<radialGradient
inkscape:collect="always"
xlink:href="#linearGradient26476"
id="radialGradient13236"
gradientUnits="userSpaceOnUse"
cx="50"
cy="92"
fx="50"
fy="92"
r="15.5" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient7518"
id="linearGradient13238"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(-35.116754,0.0704092)"
x1="80"
y1="98"
x2="87.273346"
y2="109.53979" />
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend-5"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8574-9"
style="fill:#f9f9f9;fill-opacity:1;fill-rule:evenodd;stroke:#f9f9f9;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="marker13272"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path13270"
style="fill:#f9f9f9;fill-opacity:1;fill-rule:evenodd;stroke:#f9f9f9;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="marker13276"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path13274"
style="fill:#f9f9f9;fill-opacity:1;fill-rule:evenodd;stroke:#f9f9f9;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="marker13280"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path13278"
style="fill:#f9f9f9;fill-opacity:1;fill-rule:evenodd;stroke:#f9f9f9;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="marker13284"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path13282"
style="fill:#f9f9f9;fill-opacity:1;fill-rule:evenodd;stroke:#f9f9f9;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0"
refX="0"
id="Arrow2Mend-2"
style="overflow:visible"
inkscape:isstock="true">
<path
id="path8574-2"
style="fill:#f9f9f9;fill-opacity:1;fill-rule:evenodd;stroke:#f9f9f9;stroke-width:0.625;stroke-linejoin:round;stroke-opacity:1"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6)"
inkscape:connector-curvature="0" />
</marker>
<linearGradient
id="linearGradient3314">
<stop
offset="0"
style="stop-color:#dcdcdc;stop-opacity:1"
id="stop3316" />
<stop
offset="0.0729612"
style="stop-color:#e8e8e8;stop-opacity:1"
id="stop3322" />
<stop
offset="0.39346588"
style="stop-color:#e2e2e2;stop-opacity:1"
id="stop3324" />
<stop
offset="0.50066584"
style="stop-color:#bcbcbc;stop-opacity:1"
id="stop3326" />
<stop
offset="0.6425212"
style="stop-color:#dedede;stop-opacity:1"
id="stop3330" />
<stop
offset="0.94838297"
style="stop-color:#dddddd;stop-opacity:1"
id="stop3328" />
<stop
offset="1"
style="stop-color:#dcdcdc;stop-opacity:1"
id="stop3318" />
</linearGradient>
<linearGradient
id="linearGradient3298">
<stop
offset="0"
style="stop-color:#919191;stop-opacity:1"
id="stop3300" />
<stop
offset="0.30858582"
style="stop-color:#919191;stop-opacity:1"
id="stop3302" />
<stop
offset="0.51132685"
style="stop-color:#5c5c5c;stop-opacity:1"
id="stop3304" />
<stop
offset="0.69885707"
style="stop-color:#919191;stop-opacity:1"
id="stop3306" />
<stop
offset="1"
style="stop-color:#919191;stop-opacity:1"
id="stop3308" />
</linearGradient>
<linearGradient
id="linearGradient3270">
<stop
offset="0"
style="stop-color:#929295;stop-opacity:1"
id="stop3272" />
<stop
offset="1"
style="stop-color:#b9b9b9;stop-opacity:1"
id="stop3274" />
</linearGradient>
<linearGradient
id="linearGradient3246">
<stop
offset="0"
style="stop-color:#007d12;stop-opacity:1"
id="stop3248" />
<stop
offset="0.46926689"
style="stop-color:#007d12;stop-opacity:1"
id="stop3254" />
<stop
offset="0.51132685"
style="stop-color:#5e7c62;stop-opacity:1"
id="stop3256" />
<stop
offset="0.5669955"
style="stop-color:#007d12;stop-opacity:1"
id="stop3258" />
<stop
offset="1"
style="stop-color:#007d12;stop-opacity:1"
id="stop3250" />
</linearGradient>
<linearGradient
gradientUnits="userSpaceOnUse"
xlink:href="#linearGradient3246"
id="linearGradient3252"
y2="299.70178"
x2="849.7998"
y1="463.29184"
x1="153.0388" />
<linearGradient
gradientUnits="userSpaceOnUse"
xlink:href="#linearGradient3270"
id="linearGradient3276"
y2="418.82431"
x2="241.64479"
y1="425.34058"
x1="171.59496" />
<linearGradient
gradientUnits="userSpaceOnUse"
xlink:href="#linearGradient3270"
id="linearGradient3286"
y2="294.47226"
x2="755.3006"
y1="269.49326"
x1="830.32367" />
<linearGradient
gradientUnits="userSpaceOnUse"
xlink:href="#linearGradient3298"
id="linearGradient3296"
y2="450.36261"
x2="896.48633"
y1="600.70026"
x1="197.66" />
<linearGradient
gradientUnits="userSpaceOnUse"
xlink:href="#linearGradient3314"
id="linearGradient3320"
y2="265.29617"
x2="780.50598"
y1="396.72012"
x1="233.33572" />
<filter
id="filter3587">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="9.2928517"
id="feGaussianBlur3589" />
</filter>
<filter
id="filter3631">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="14.191705"
id="feGaussianBlur3633" />
</filter>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.979899"
inkscape:cx="125.57529"
inkscape:cy="10.242677"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:pagecheckerboard="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1920"
inkscape:window-height="1017"
inkscape:window-x="1672"
inkscape:window-y="-8"
inkscape:window-maximized="1"
showguides="false">
<inkscape:grid
type="xygrid"
id="grid14028"
units="mm"
spacingx="1"
spacingy="1"
dotted="true"
empspacing="5" />
<inkscape:grid
type="xygrid"
id="grid14036" />
</sodipodi:namedview>
<metadata
id="metadata11760">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-96.700309,-96.926329)">
<g
inkscape:transform-center-y="2.0000018"
inkscape:transform-center-x="1.7354122"
id="use5329"
transform="matrix(204.05634,0,0,204.05634,-135784.74,75153.402)">
<rect
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect12450"
width="4"
height="11"
x="273.52917"
y="-149" />
<rect
y="-146"
x="277.52917"
height="5"
width="3"
id="rect12452"
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<path
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 281,-145.00002 5,2e-5 v 0.47083 h 2 V -144 h 5 v 1 h -5 v 0.52917 h -2 V -142 l -5,-2e-5 z"
id="path12454"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccc" />
<g
id="g12460"
transform="translate(0.52916667,-2)">
<path
inkscape:connector-curvature="0"
id="path12456"
d="m 287.99999,-140.47083 v 2 H 290 Z"
style="fill:#ffffff;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
y="-138"
x="288"
height="7"
width="2"
id="rect12458"
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
</g>
</g>
<g
inkscape:transform-center-y="2.0000018"
inkscape:transform-center-x="1.7354122"
id="use5329-5"
transform="matrix(204.05634,0,0,204.05634,-135784.74,75153.402)">
<rect
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="rect12508"
width="4"
height="11"
x="273.52917"
y="-149" />
<rect
y="-146"
x="277.52917"
height="5"
width="3"
id="rect12510"
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<path
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 281,-145.00002 5,2e-5 v 0.47083 h 2 V -144 h 5 v 1 h -5 v 0.52917 h -2 V -142 l -5,-2e-5 z"
id="path12512"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccccc" />
<g
id="g12518"
transform="translate(0.52916667,-2)">
<path
inkscape:connector-curvature="0"
id="path12514"
d="m 287.99999,-140.47083 v 2 H 290 Z"
style="fill:#ffffff;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<rect
y="-138"
x="288"
height="7"
width="2"
id="rect12516"
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
</g>
</g>
<g
id="use26239"
transform="translate(41252296,-26435496)">
<g
transform="matrix(157375.71,0,0,157375.71,-87067038,35086817)"
id="g13228">
<circle
style="opacity:1;fill:url(#radialGradient13236);fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="circle13220"
cx="45"
cy="97"
r="15" />
<path
style="opacity:1;fill:url(#linearGradient13238);fill-opacity:1;stroke:none;stroke-width:0.97674406;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
d="m 58.593623,92.350616 c 2.385905,6.962784 -0.972423,14.538754 -7.252029,17.704604 -6.581851,3.31823 -14.445868,1.16906 -18.535439,-4.95045"
id="path13222"
inkscape:connector-curvature="0"
inkscape:transform-center-x="-1.0852379"
inkscape:transform-center-y="4.9804617"
sodipodi:nodetypes="csc" />
<circle
r="15"
cy="97"
cx="45"
id="circle13224"
style="opacity:1;fill:none;fill-opacity:1;stroke:#ebebeb;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<path
sodipodi:open="true"
d="m 44.897568,82.00035 a 15,15 0 0 1 14.369022,10.36668 15,15 0 0 1 -5.536793,16.83095 15,15 0 0 1 -17.71726,-0.18859"
sodipodi:end="2.2132531"
sodipodi:start="4.7055601"
sodipodi:ry="15"
sodipodi:rx="15"
sodipodi:cy="97"
sodipodi:cx="45"
sodipodi:type="arc"
style="opacity:1;fill:none;fill-opacity:1;stroke:#d3d3d3;stroke-width:2;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
id="path13226" />
</g>
<g
id="g13232">
<g
transform="matrix(3.7795276,0,0,3.7795276,-2219.735,1371.8767)"
id="use13230"
inkscape:transform-center-x="0.99999954"
inkscape:transform-center-y="0.60193146">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:0.26458332"
x="240"
y="-105"
id="text13242"><tspan
sodipodi:role="line"
id="tspan13240"
x="240"
y="-105"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.28888893px;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';fill:#ffffff;stroke:#ffffff;stroke-width:0.26458332">M</tspan></text>
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path13244"
d="m 258,-101 -3,4 h 6 z"
style="fill:#ffffff;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<circle
r="2"
cy="-99"
cx="241"
id="circle13246"
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path13248"
d="m 237,-101.47083 h 24"
style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path13250"
d="m 249,-100 v 7"
style="fill:none;stroke:#f9f9f9;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Mend)" />
<text
id="text13256"
y="-91.737373"
x="250.36359"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332"
xml:space="preserve"><tspan
style="font-size:3.52777767px;fill:#ffffff;stroke-width:0.26458332"
y="-91.737373"
x="250.36359"
id="tspan13254"
sodipodi:role="line">F<tspan
id="tspan13252"
style="font-size:1.41111112px;fill:#ffffff">Z</tspan></tspan></text>
</g>
</g>
</g>
<g
transform="matrix(204.05634,0,0,204.05634,-135917.88,75008.797)"
id="use5478"
inkscape:transform-center-x="0.99999954"
inkscape:transform-center-y="0.60193146">
<text
xml:space="preserve"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:0.26458332"
x="240"
y="-105"
id="text13402"><tspan
sodipodi:role="line"
id="tspan13400"
x="240"
y="-105"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:11.28888893px;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';fill:#ffffff;stroke:#ffffff;stroke-width:0.26458332">M</tspan></text>
<path
sodipodi:nodetypes="cccc"
inkscape:connector-curvature="0"
id="path13404"
d="m 258,-101 -3,4 h 6 z"
style="fill:#ffffff;stroke:none;stroke-width:0.26458332px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<circle
r="2"
cy="-99"
cx="241"
id="circle13406"
style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" />
<path
inkscape:connector-curvature="0"
id="path13408"
d="m 237,-101.47083 h 24"
style="fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
<path
sodipodi:nodetypes="cc"
inkscape:connector-curvature="0"
id="path13410"
d="m 249,-100 v 7"
style="fill:none;stroke:#f9f9f9;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;marker-end:url(#Arrow2Mend)" />
<text
id="text13416"
y="-91.737373"
x="250.36359"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0.26458332"
xml:space="preserve"><tspan
style="font-size:3.52777767px;fill:#ffffff;stroke-width:0.26458332"
y="-91.737373"
x="250.36359"
id="tspan13414"
sodipodi:role="line">F<tspan
id="tspan13412"
style="font-size:1.41111112px;fill:#ffffff">Z</tspan></tspan></text>
</g>
<text
id="text26490"
y="108.77583"
x="98.945969"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10.58333302px;line-height:1.25;font-family:Arial;-inkscape-font-specification:Arial;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:#ffffff;stroke-width:0.26458332"
xml:space="preserve"><tspan
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:12.69999981px;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';fill:#ffffff;stroke:#ffffff;stroke-width:0.26458332"
y="108.77583"
x="98.945969"
id="tspan26488"
sodipodi:role="line">S</tspan></text>
<path
id="path4840"
d="m 116.70664,100.3512 c -0.14496,-0.002 -0.29126,0.006 -0.43659,0.01 -1.17718,0.0362 -2.33828,0.9636 -2.42672,2.18313 -0.29727,1.25439 -0.50828,2.57197 -1.15103,3.70509 -2.1609,2.16336 -4.48161,4.16303 -6.70887,6.25817 -0.90253,0.86304 -1.86084,1.67552 -2.6889,2.61168 -0.6963,1.00578 0.0217,2.73204 1.30443,2.72455 1.01064,-0.0331 1.59865,-1.0163 2.25453,-1.64313 2.44276,-2.6581 4.68431,-5.49976 7.19592,-8.09519 0.66341,-0.54689 1.58373,-0.59881 2.3884,-0.81925 0.54078,-0.13455 1.11301,-0.17869 1.63466,-0.36816 0.9358,-0.59434 1.60138,-1.6614 1.70207,-2.76612 0.0333,-0.26301 -0.26095,-0.18064 -0.26095,-0.18064 l -1.62107,0.74703 -1.23842,-1.02247 -0.20786,-1.15326 c 0,0 0.37664,-0.37309 0.54518,-0.40539 l 1.59106,-0.59363 c -0.0633,-0.65793 -0.8946,-0.98875 -1.44713,-1.1386 -0.14025,-0.0381 -0.28388,-0.0511 -0.42884,-0.0536 z m -1.20876,4.4606 0.72444,1.71223 -0.65567,0.26423 -0.0142,-0.0329 0.17926,-0.0746 -0.0342,-0.082 0.0375,-0.009 0.0862,-0.0193 -0.0386,-0.17219 -0.086,0.0191 -0.068,0.0152 -0.0859,-0.20546 0.0367,-0.009 0.0862,-0.0193 -0.0384,-0.1722 -0.0862,0.0192 -0.0674,0.015 -0.0859,-0.20563 0.0362,-0.008 0.0862,-0.0192 -0.0386,-0.17236 -0.086,0.0193 -0.0667,0.015 -0.0859,-0.20581 0.0353,-0.008 0.0862,-0.0191 -0.0384,-0.17236 -0.0862,0.0193 -0.0661,0.0149 -0.11963,-0.28682 c -0.12696,0.0512 -0.13397,0.0554 -0.19581,0.081 l -0.0148,-0.0347 c 0.22143,-0.0893 0.44287,-0.17845 0.66429,-0.26768 z m -1.15554,0.46556 0.0168,0.0393 c -0.0598,0.0247 -0.0613,0.0265 -0.17426,0.072 l 0.0576,0.13702 -0.0298,0.007 -0.0862,0.0193 0.0386,0.17218 0.086,-0.0193 0.0609,-0.0136 0.0865,0.20563 -0.0302,0.007 -0.0862,0.0193 0.0384,0.1722 0.0862,-0.0193 0.0612,-0.0136 0.0863,0.20546 -0.0305,0.007 -0.0862,0.0193 0.0386,0.17219 0.086,-0.0191 0.0617,-0.0138 0.0863,0.20545 -0.0308,0.007 -0.0862,0.0193 0.0384,0.1722 0.0862,-0.0192 0.0621,-0.0138 0.0978,0.23252 0.18598,-0.0774 0.0117,0.0273 -0.61448,0.24751 -0.7241,-1.71222 c 0.20185,-0.0814 0.40366,-0.16274 0.60552,-0.24406 z m -9.51337,9.71898 a 1.0178768,1.0178768 0 0 1 1.01779,1.01797 1.0178768,1.0178768 0 0 1 -1.01779,1.01779 1.0178768,1.0178768 0 0 1 -1.01779,-1.01779 1.0178768,1.0178768 0 0 1 1.01779,-1.01797 z"
inkscape:connector-curvature="0"
style="fill:#ffffff;stroke-width:0.08825012" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 31 KiB

View File

@ -1,40 +1,2 @@
<?php
$ADMIN->add('blocksettings', new admin_category('block_gradelevel', get_string('cfgpage_generic', 'block_gradelevel')));
$settings->add(new admin_setting_configcheckbox(
'gradelevel/showtitle',
get_string('labelshowtitle', 'block_gradelevel'),
get_string('descshowtitle', 'block_gradelevel'),
true
));
$settings->add(new admin_setting_configtext(
'gradelevel/blocktitle',
get_string('labeltitle', 'block_gradelevel'),
get_string('desctitle', 'block_gradelevel'),
get_string('title', 'block_gradelevel')
));
$ADMIN->add("block_gradelevel", $settings);
// Add the default levels page
$ADMIN->add("block_gradelevel", new admin_externalpage(
'block_gradelevel_default_levels',
get_string('cfgpage_globallevels', 'block_gradelevel'),
$CFG->wwwroot . '/blocks/gradelevel/cfg_globallevels.php'
)
);
// 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;

View File

@ -1,145 +1,10 @@
figure.levelbadge, figure.dummybadge {
text-align: center;
}
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 span.leveluppoints {
font-weight: bold;
}
div.teachermode {
text-align: center;
}
td.block_gradelevel_addlevel {
text-align: right;
}
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;
}
div.block_gradelevel_results ul {
padding-left: 0px;
margin-left: 0px;
}
div .block_gradelevel_results li.result_badge {
position: relative; /* needed to have absolute positions be relative to this li */
list-style: none;
display: inline-block;
width: 190px;
height: 210px;
border-color: #ccc;
border-width: 1px;
border-style: solid;
margin: 5px;
padding: 5px;
padding-top: 10px;
}
div.block_gradelevel_results li.result_badge figcaption {
text-align: center;
height: 3em;
margin-bottom: 0.5rem;
}
div.block_gradelevel_results li.result_badge div.pointinfo {
font-size: 85%;
}
div.block_gradelevel_results li.result_badge figcaption span.namepart {
break-inside: avoid;
display: inline-block;
}
div.block_gradelevel_results figure.levelset_icon {
margin-bottom: 0.5rem;
}
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%);
background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, #aaa), color-stop(.25, transparent)), -webkit-gradient(linear, 0 0, 100% 100%, color-stop(.25, #aaa), color-stop(.25, transparent)), -webkit-gradient(linear, 0 100%, 100% 0, color-stop(.75, transparent), color-stop(.75, #aaa)), -webkit-gradient(linear, 0 0, 100% 100%, color-stop(.75, transparent), color-stop(.75, #aaa));
-moz-background-size: 32px 32px;
background-size: 32px 33px;
-webkit-background-size: 32px 33px; /* override value for shitty webkit */
background-position: 0 0, 16px 0, 16px -16px, 0px 16px;
display: inline-block;
}
/* stylelint-disable length-zero-no-unit, color-hex-case, color-hex-length*/
.path-block-mytreestudyplan [v-cloak] {
visibility: hidden;
}
.path-block-mytreestudyplan .vue-loader {
width: 32px;
margin: auto;
}

51
templates/block.mustache Normal file
View File

@ -0,0 +1,51 @@
{{!
This file is part of Moodle - https://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/>.
}}
{{!
@template plugintype_pluginname/template_name
Template purpose and description.
Classes required for JS:
* none
Data attributes required for JS:
* none
Context variables required for this template:
* none
Example context (json):
{
}
}}
<div id='block_mytreestudyplan' class='path-local-treestudyplan'>
<div class='vue-loader' v-show='false'>
<div class='spinner-border text-primary' role='status'>
<span class='sr-only'>Loading...</span>
</div>
</div>
<div v-cloak>
{{^teachermode}}
<r-report v-model='studyplans'></r-report>
{{/teachermode}}
{{#teachermode}}
<r-report v-model='studyplans' teachermode></r-report>
{{/teachermode}}
</div>
</div>

View File

@ -1,4 +1,8 @@
<?php
$plugin->component = 'block_gradelevel'; // Recommended since 2.0.2 (MDL-26035). Required since 3.0 (MDL-48494)
$plugin->version = 2019100900; // YYYYMMDDHH (year, month, day, iteration)
$plugin->requires = 2018050800; // YYYYMMDDHH (This is the release version for Moodle 3.5)
$plugin->component = 'block_mytreestudyplan'; // Recommended since 2.0.2 (MDL-26035). Required since 3.0 (MDL-48494)
$plugin->version = 2022061600; // YYYYMMDDHH (year, month, day, iteration)
$plugin->requires = 2021051700; // YYYYMMDDHH (This is the release version for Moodle 3.11)
$plugin->dependencies = [
'local_treestudyplan' => 2022061100,
];

View File

@ -1,49 +0,0 @@
<?php
//header("Content-type: image/svg+xml");
//ob_start();
require_once("../../config.php");
global $CFG;
global $DB;
$skillid = required_param('skillid', PARAM_INT);
$skill = $DB->get_record('block_gradelevel_levelset', array('id' => $skillid));
if(is_object($skill))
{
$image = $skill->icon;
if(strncmp($image,"data:",5) == 0)
{
$parts = explode(",",ltrim(substr($image,5)),2);
$typeinfo = explode(";",$parts[0]);
if(count($typeinfo) > 1 && $typeinfo[1] == "base64")
{
$binary = base64_decode($parts[1]);
}
else
{
$binary = $parts[0];
}
$mime = $typeinfo[0];
// set header
header("Content-type: {$mime}");
header("Pragma:");
// Allow cache for 5 seconds
header("Cache-Control: public, max-age=5");
// print data
print $binary;
}
else
{
// redirect to specified url
header("Location: {$image}",true,302);
}
}
else
{
http_response_code(404);
print "Image not found";
}

View File

@ -1,107 +0,0 @@
<?php
require_once("../../config.php");
global $DB;
global $CFG;
const BADGE_SIZE = 100;
// Do sanity and access checks on course
$courseid = required_param('courseid', PARAM_INT);
$COURSE = get_course($courseid);
$coursecontext = context_course::instance($courseid);
$skill = block_gradelevel_levelset::find_by_course($courseid);
require_login($COURSE);
require_capability('block/gradelevel:viewresults', $coursecontext);
$PAGE->set_url('/blocks/gradelevel/view-results.php', array('courseid' => $courseid));
$PAGE->set_pagelayout('standard');
$PAGE->requires->js_call_amd('block_gradelevel/renderbadge', 'init');
print $OUTPUT->header();
print $OUTPUT->heading(get_string('results_heading', 'block_gradelevel') . " " . $skill->getName());
print "<p>".get_string('course', 'core')." " . $COURSE->fullname."</p>";
//retrieve groups
$course_groups = groups_get_all_groups($COURSE->id);
// retrieve users
$remaining_users = get_enrolled_users($coursecontext);
print "<div class='block_gradelevel_results'>";
if(count($course_groups > 0))
{
// loop through all groups first
foreach($course_groups as $grp)
{
// Get members
$members = get_enrolled_users($coursecontext,'mod/assignment:submit',$grp->id);
$count_members = count($members);
// show group name
print $OUTPUT->heading($grp->name." ({$count_members})",4,array('groupname'));
// Sort on last name
usort( $members, function( $a, $b) {
return ( $a->lastname < $b->lastname ) ? -1 : 1;
} );
print "<ul class='skill_results'>";
foreach($members as $usr)
{
$pointstotal = round($skill->get_levelset_grade($usr->id),1);
$level_info = $skill->calculate_level($pointstotal);
print "<li class='result_badge'>";
print $skill->render_badge($pointstotal,BADGE_SIZE);
print "<figcaption><span class='namepart'>{$usr->firstname}</span> <span class='namepart'>{$usr->lastname}</span></figcaption>";
if($level_info->levelup_total > 0)
{
print "<div class='pointinfo'>".get_string('levelup_at','block_gradelevel')." <span class='currentpoints'>{$pointstotal}</span>/<span class='leveluppoints'>{$level_info->next_at}</span></div>";
}
else
{
print "<div class='pointinfo complete'>".get_string('levelup_done','block_gradelevel')."</div>";
}
print "</li>";
unset($remaining_users[$usr->id]);
}
print "</ul>";
}
$count_members = count($remaining_users);
print $OUTPUT->heading(get_string('results_ungrouped','block_gradelevel')." ({$count_members})" ,4,array('groupname'));
}
usort( $remaining_users, function( $a, $b) {
return ( $a->lastname < $b->lastname ) ? -1 : 1;
} );
print "<ul class='skill_results other'>";
foreach($remaining_users as $usr)
{
$pointstotal = round($skill->get_levelset_grade($usr->id),1);
$level_info = $skill->calculate_level($pointstotal);
print "<li class='result_badge'>";
print $skill->render_badge($pointstotal,BADGE_SIZE);
print "<figcaption><span class='namepart'>{$usr->firstname}</span> <span class='namepart'>{$usr->lastname}</span></figcaption>";
if($level_info->levelup_total > 0)
{
print "<div class='pointinfo'>".get_string('levelup_at','block_gradelevel')." <span class='currentpoints'>{$pointstotal}</span>/<span class='leveluppoints'>{$level_info->next_at}</span></div>";
}
else
{
print "<div class='pointinfo complete'>".get_string('levelup_done','block_gradelevel')."</div>";
}
print "</li>";
}
print "</ul>";
print "</div>";
print $OUTPUT->footer();