diff --git a/.gitignore b/.gitignore index 4dc06e0..7c6e0dc 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /.vs - +/node_modules +/amd/build diff --git a/LICENSE b/LICENSE index 8917076..3072204 100644 --- a/LICENSE +++ b/LICENSE @@ -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. \ No newline at end of file +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. diff --git a/amd/build/debugger.min.js b/amd/build/debugger.min.js deleted file mode 100644 index d1f292d..0000000 --- a/amd/build/debugger.min.js +++ /dev/null @@ -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}}}}); \ No newline at end of file diff --git a/amd/build/handlers.min.js b/amd/build/handlers.min.js deleted file mode 100644 index 99967d1..0000000 --- a/amd/build/handlers.min.js +++ /dev/null @@ -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)}}}); \ No newline at end of file diff --git a/amd/build/jquery.animate-shadow.min.js b/amd/build/jquery.animate-shadow.min.js deleted file mode 100644 index 690a724..0000000 --- a/amd/build/jquery.animate-shadow.min.js +++ /dev/null @@ -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++)t0&&(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;na[r]&&-t[r]+e[r]+l[r]/2>a[r]/2&&e[r]+l[r]-d[r]>=0?e[r]+l[r]-d[r]:e[r],-t[o]+e[o]+l[o]+d[o]-c+c*s>a[o]?-t[o]+e[o]+l[o]/2>a[o]/2&&e[o]+l[o]-c-c*s>=0?e[o]+l[o]-c-c*s:e[o]+l[o]-c+c*s:e[o]+l[o]-c+c*s>=0?e[o]+l[o]-c+c*s:e[o]+l[o]-c-c*s];else var h=[e[r],e[o]+l[o]-c+c*s];var p=h[r],u=h[o],m=n.fixed?"fixed":"absolute",v=(h[0]+d[0]>e[0]||h[0]2)switch(e.mode.charAt(2).toLowerCase()){case"s":return"s";case"v":return"v"}return null},onDocumentMouseDown:function(e){e||(e=window.event);var t=e.target||e.srcElement;t._jscLinkedInstance?t._jscLinkedInstance.showOnClick&&t._jscLinkedInstance.show():t._jscControlName?i.onControlPointerStart(e,t,t._jscControlName,"mouse"):i.picker&&i.picker.owner&&i.picker.owner.hide()},onDocumentTouchStart:function(e){e||(e=window.event);var t=e.target||e.srcElement;t._jscLinkedInstance?t._jscLinkedInstance.showOnClick&&t._jscLinkedInstance.show():t._jscControlName?i.onControlPointerStart(e,t,t._jscControlName,"touch"):i.picker&&i.picker.owner&&i.picker.owner.hide()},onWindowResize:function(e){i.redrawPosition()},onParentScroll:function(e){i.picker&&i.picker.owner&&i.picker.owner.hide()},_pointerMoveEvent:{mouse:"mousemove",touch:"touchmove"},_pointerEndEvent:{mouse:"mouseup",touch:"touchend"},_pointerOrigin:null,_capturedTarget:null,onControlPointerStart:function(e,t,n,r){var o=t._jscInstance;i.preventDefault(e),i.captureTarget(t);var s=function(o,s){i.attachGroupEvent("drag",o,i._pointerMoveEvent[r],i.onDocumentPointerMove(e,t,n,r,s)),i.attachGroupEvent("drag",o,i._pointerEndEvent[r],i.onDocumentPointerEnd(e,t,n,r))};if(s(document,[0,0]),window.parent&&window.frameElement){var l=window.frameElement.getBoundingClientRect(),a=[-l.left,-l.top];s(window.parent.window.document,a)}var d=i.getAbsPointerPos(e),c=i.getRelPointerPos(e);switch(i._pointerOrigin={x:d.x-c.x,y:d.y-c.y},n){case"pad":switch(i.getSliderComponent(o)){case"s":0===o.hsv[1]&&o.fromHSV(null,100,null);break;case"v":0===o.hsv[2]&&o.fromHSV(null,null,100)}i.setPad(o,e,0,0);break;case"sld":i.setSld(o,e,0)}i.dispatchFineChange(o)},onDocumentPointerMove:function(e,t,n,r,o){return function(e){var r=t._jscInstance;switch(n){case"pad":e||(e=window.event),i.setPad(r,e,o[0],o[1]),i.dispatchFineChange(r);break;case"sld":e||(e=window.event),i.setSld(r,e,o[1]),i.dispatchFineChange(r)}}},onDocumentPointerEnd:function(e,t,n,r){return function(e){var n=t._jscInstance;i.detachGroupEvents("drag"),i.releaseTarget(),i.dispatchChange(n)}},dispatchChange:function(e){e.valueElement&&i.isElementType(e.valueElement,"input")&&i.fireEvent(e.valueElement,"change")},dispatchFineChange:function(e){e.onFineChange&&("string"==typeof e.onFineChange?new Function(e.onFineChange):e.onFineChange).call(e)},setPad:function(e,t,n,r){var o=i.getAbsPointerPos(t),s=n+o.x-i._pointerOrigin.x-e.padding-e.insetWidth,l=r+o.y-i._pointerOrigin.y-e.padding-e.insetWidth,a=s*(360/(e.width-1)),d=100-l*(100/(e.height-1));switch(i.getPadYComponent(e)){case"s":e.fromHSV(a,d,null,i.leaveSld);break;case"v":e.fromHSV(a,null,d,i.leaveSld)}},setSld:function(e,t,n){var r=100-(n+i.getAbsPointerPos(t).y-i._pointerOrigin.y-e.padding-e.insetWidth)*(100/(e.height-1));switch(i.getSliderComponent(e)){case"s":e.fromHSV(null,r,null,i.leavePad);break;case"v":e.fromHSV(null,null,r,i.leavePad)}},_vmlNS:"jsc_vml_",_vmlCSS:"jsc_vml_css_",_vmlReady:!1,initVML:function(){if(!i._vmlReady){var e=document;if(e.namespaces[i._vmlNS]||e.namespaces.add(i._vmlNS,"urn:schemas-microsoft-com:vml"),!e.styleSheets[i._vmlCSS]){var t=["shape","shapetype","group","background","path","formulas","handles","fill","stroke","shadow","textbox","textpath","imagedata","line","polyline","curve","rect","roundrect","oval","arc","image"],n=e.createStyleSheet();n.owningElement.id=i._vmlCSS;for(var r=0;r=3&&(r=s[0].match(l))&&(o=s[1].match(l))&&(i=s[2].match(l))){var a=parseFloat((r[1]||"0")+(r[2]||"")),d=parseFloat((o[1]||"0")+(o[2]||"")),c=parseFloat((i[1]||"0")+(i[2]||""));return this.fromRGB(a,d,c,t),!0}}return!1},this.toString=function(){return(256|Math.round(this.rgb[0])).toString(16).substr(1)+(256|Math.round(this.rgb[1])).toString(16).substr(1)+(256|Math.round(this.rgb[2])).toString(16).substr(1)},this.toHEXString=function(){return"#"+this.toString().toUpperCase()},this.toRGBString=function(){return"rgb("+Math.round(this.rgb[0])+","+Math.round(this.rgb[1])+","+Math.round(this.rgb[2])+")"},this.isLight=function(){return.213*this.rgb[0]+.715*this.rgb[1]+.072*this.rgb[2]>127.5},this._processParentElementsInDOM=function(){if(!this._linkedElementsProcessed){this._linkedElementsProcessed=!0;var e=this.targetElement;do{var t=i.getStyle(e);t&&"fixed"===t.position.toLowerCase()&&(this.fixed=!0),e!==this.targetElement&&(e._jscEventsAttached||(i.attachEvent(e,"scroll",i.onParentScroll),e._jscEventsAttached=!0))}while((e=e.parentNode)&&!i.isElementType(e,"body"))}},"string"==typeof e){var d=e,c=document.getElementById(d);c?this.targetElement=c:i.warn("Could not find target element with ID '"+d+"'")}else e?this.targetElement=e:i.warn("Invalid target element: '"+e+"'");if(this.targetElement._jscLinkedInstance)i.warn("Cannot link jscolor twice to the same element. Skipping.");else{this.targetElement._jscLinkedInstance=this,this.valueElement=i.fetchElement(this.valueElement),this.styleElement=i.fetchElement(this.styleElement);var h=this,p=this.container?i.fetchElement(this.container):document.getElementsByTagName("body")[0],u=3;if(i.isElementType(this.targetElement,"button"))if(this.targetElement.onclick){var m=this.targetElement.onclick;this.targetElement.onclick=function(e){return m.call(this,e),!1}}else this.targetElement.onclick=function(){return!1};if(this.valueElement&&i.isElementType(this.valueElement,"input")){var v=function(){h.fromString(h.valueElement.value,i.leaveValue),i.dispatchFineChange(h)};i.attachEvent(this.valueElement,"keyup",v),i.attachEvent(this.valueElement,"input",v),i.attachEvent(this.valueElement,"blur",function(){h.importColor()}),this.valueElement.setAttribute("autocomplete","off")}this.styleElement&&(this.styleElement._jscOrigStyle={backgroundImage:this.styleElement.style.backgroundImage,backgroundColor:this.styleElement.style.backgroundColor,color:this.styleElement.style.color}),this.value?this.fromString(this.value)||this.exportColor():this.importColor()}}}).jscolor.lookupClass="jscolor",i.jscolor.installByClassName=function(e){var t=document.getElementsByTagName("input"),n=document.getElementsByTagName("button");i.tryInstallOnElements(t,e),i.tryInstallOnElements(n,e)},i.register(),i.jscolor;var e,t,n,r,o,i}); \ No newline at end of file diff --git a/amd/build/leveleditor.min.js b/amd/build/leveleditor.min.js deleted file mode 100644 index 20383b5..0000000 --- a/amd/build/leveleditor.min.js +++ /dev/null @@ -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("");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}); \ No newline at end of file diff --git a/amd/build/renderbadge.min.js b/amd/build/renderbadge.min.js deleted file mode 100644 index a1c4232..0000000 --- a/amd/build/renderbadge.min.js +++ /dev/null @@ -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("");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}); \ No newline at end of file diff --git a/amd/build/skilleditor.min.js b/amd/build/skilleditor.min.js deleted file mode 100644 index 054e300..0000000 --- a/amd/build/skilleditor.min.js +++ /dev/null @@ -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("").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(""+t.name+""))})}"27"==o&&(r.info("Cancelled editing"),n.replaceWith(e(""+t+"")))}).on("focusout",function(i){r.info("Cancelled editing"),n.replaceWith(e(""+t+""))}),n.focus()}else f.find("figurecaption input[type=text]")}),f.find("a[data-action='editicon']").on("click",function(t){let l=e("");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("")),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}); \ No newline at end of file diff --git a/amd/src/block_mytreestudyplan.js b/amd/src/block_mytreestudyplan.js new file mode 100644 index 0000000..e4077d5 --- /dev/null +++ b/amd/src/block_mytreestudyplan.js @@ -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: { + + }, + }); + +} + + diff --git a/amd/src/debugger.js b/amd/src/debugger.js deleted file mode 100644 index bf06efa..0000000 --- a/amd/src/debugger.js +++ /dev/null @@ -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; - } - }; - - }); -}); \ No newline at end of file diff --git a/amd/src/handlers.js b/amd/src/handlers.js deleted file mode 100644 index 103d2d3..0000000 --- a/amd/src/handlers.js +++ /dev/null @@ -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; -}); \ No newline at end of file diff --git a/amd/src/jquery.animate-shadow.js b/amd/src/jquery.animate-shadow.js deleted file mode 100644 index 02274bb..0000000 --- a/amd/src/jquery.animate-shadow.js +++ /dev/null @@ -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 - * @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; - } - }); - -}); \ No newline at end of file diff --git a/amd/src/jscolor.js b/amd/src/jscolor.js deleted file mode 100644 index 80ed655..0000000 --- a/amd/src/jscolor.js +++ /dev/null @@ -1,1867 +0,0 @@ -/*eslint no-unused-vars: "off" */ -/*eslint max-len: "off" */ -/*eslint no-bitwise: "off" */ -/*eslint no-cond-assign: "off" */ -/*eslint no-new-func: "off" */ -/*eslint no-caller: "off" */ -/** - * jscolor - JavaScript Color Picker - * - * @link http://jscolor.com - * @license For open source use: GPLv3 - * For commercial use: JSColor Commercial License - * @author Jan Odvarko - * @version 2.0.5 - * - * See usage examples at http://jscolor.com/examples/ - */ - - -"use strict"; - -define([], function () { - - //if (!window.jscolor) { window.jscolor = (function () { - return (function () { - - //console.info("Initializing JSColor"); - - var jsc = { - - - register: function () { - jsc.attachDOMReadyEvent(jsc.init); - jsc.attachEvent(document, 'mousedown', jsc.onDocumentMouseDown); - jsc.attachEvent(document, 'touchstart', jsc.onDocumentTouchStart); - jsc.attachEvent(window, 'resize', jsc.onWindowResize); - }, - - - init: function () { - if (jsc.jscolor.lookupClass) { - jsc.jscolor.installByClassName(jsc.jscolor.lookupClass); - } - }, - - - tryInstallOnElements: function (elms, className) { - var matchClass = new RegExp('(^|\\s)(' + className + ')(\\s*(\\{[^}]*\\})|\\s|$)', 'i'); - - for (var i = 0; i < elms.length; i += 1) { - if (elms[i].type !== undefined && elms[i].type.toLowerCase() == 'color') { - if (jsc.isColorAttrSupported) { - // skip inputs of type 'color' if supported by the browser - continue; - } - } - var m; - if (!elms[i].jscolor && elms[i].className && (m = elms[i].className.match(matchClass))) { - var targetElm = elms[i]; - var optsStr = null; - - var dataOptions = jsc.getDataAttr(targetElm, 'jscolor'); - if (dataOptions !== null) { - optsStr = dataOptions; - } else if (m[4]) { - optsStr = m[4]; - } - - var opts = {}; - if (optsStr) { - try { - opts = (new Function('return (' + optsStr + ')'))(); - } catch (eParseError) { - jsc.warn('Error parsing jscolor options: ' + eParseError + ':\n' + optsStr); - } - } - targetElm.jscolor = new jsc.jscolor(targetElm, opts); - } - } - }, - - - isColorAttrSupported: (function () { - var elm = document.createElement('input'); - if (elm.setAttribute) { - elm.setAttribute('type', 'color'); - if (elm.type.toLowerCase() == 'color') { - return true; - } - } - return false; - })(), - - - isCanvasSupported: (function () { - var elm = document.createElement('canvas'); - return !!(elm.getContext && elm.getContext('2d')); - })(), - - - fetchElement: function (mixed) { - return typeof mixed === 'string' ? document.getElementById(mixed) : mixed; - }, - - - isElementType: function (elm, type) { - return elm.nodeName.toLowerCase() === type.toLowerCase(); - }, - - - getDataAttr: function (el, name) { - var attrName = 'data-' + name; - var attrValue = el.getAttribute(attrName); - if (attrValue !== null) { - return attrValue; - } - return null; - }, - - - attachEvent: function (el, evnt, func) { - if (el.addEventListener) { - el.addEventListener(evnt, func, false); - } else if (el.attachEvent) { - el.attachEvent('on' + evnt, func); - } - }, - - - detachEvent: function (el, evnt, func) { - if (el.removeEventListener) { - el.removeEventListener(evnt, func, false); - } else if (el.detachEvent) { - el.detachEvent('on' + evnt, func); - } - }, - - - _attachedGroupEvents: {}, - - - attachGroupEvent: function (groupName, el, evnt, func) { - if (!jsc._attachedGroupEvents.hasOwnProperty(groupName)) { - jsc._attachedGroupEvents[groupName] = []; - } - jsc._attachedGroupEvents[groupName].push([el, evnt, func]); - jsc.attachEvent(el, evnt, func); - }, - - - detachGroupEvents: function (groupName) { - if (jsc._attachedGroupEvents.hasOwnProperty(groupName)) { - for (var i = 0; i < jsc._attachedGroupEvents[groupName].length; i += 1) { - var evt = jsc._attachedGroupEvents[groupName][i]; - jsc.detachEvent(evt[0], evt[1], evt[2]); - } - delete jsc._attachedGroupEvents[groupName]; - } - }, - - - attachDOMReadyEvent: function (func) { - var fired = false; - var fireOnce = function () { - if (!fired) { - fired = true; - func(); - } - }; - - if (document.readyState === 'complete') { - setTimeout(fireOnce, 1); // async - return; - } - - if (document.addEventListener) { - document.addEventListener('DOMContentLoaded', fireOnce, false); - - // Fallback - window.addEventListener('load', fireOnce, false); - - } else if (document.attachEvent) { - // IE - document.attachEvent('onreadystatechange', function () { - if (document.readyState === 'complete') { - document.detachEvent('onreadystatechange', arguments.callee); - fireOnce(); - } - }); - - // Fallback - window.attachEvent('onload', fireOnce); - - // IE7/8 - if (document.documentElement.doScroll && window == window.top) { - var tryScroll = function () { - if (!document.body) { return; } - try { - document.documentElement.doScroll('left'); - fireOnce(); - } catch (e) { - setTimeout(tryScroll, 1); - } - }; - tryScroll(); - } - } - }, - - - warn: function (msg) { - if (window.console && window.console.warn) { - window.console.warn(msg); - } - }, - - - preventDefault: function (e) { - if (e.preventDefault) { e.preventDefault(); } - e.returnValue = false; - }, - - - captureTarget: function (target) { - // IE - if (target.setCapture) { - jsc._capturedTarget = target; - jsc._capturedTarget.setCapture(); - } - }, - - - releaseTarget: function () { - // IE - if (jsc._capturedTarget) { - jsc._capturedTarget.releaseCapture(); - jsc._capturedTarget = null; - } - }, - - - fireEvent: function (el, evnt) { - if (!el) { - return; - } - if (document.createEvent) { - var ev = document.createEvent('HTMLEvents'); - ev.initEvent(evnt, true, true); - el.dispatchEvent(ev); - } else if (document.createEventObject) { - var ev = document.createEventObject(); - el.fireEvent('on' + evnt, ev); - } else if (el['on' + evnt]) { // alternatively use the traditional event model - el['on' + evnt](); - } - }, - - - classNameToList: function (className) { - return className.replace(/^\s+|\s+$/g, '').split(/\s+/); - }, - - - // The className parameter (str) can only contain a single class name - hasClass: function (elm, className) { - if (!className) { - return false; - } - return -1 != (' ' + elm.className.replace(/\s+/g, ' ') + ' ').indexOf(' ' + className + ' '); - }, - - - // The className parameter (str) can contain multiple class names separated by whitespace - setClass: function (elm, className) { - var classList = jsc.classNameToList(className); - for (var i = 0; i < classList.length; i += 1) { - if (!jsc.hasClass(elm, classList[i])) { - elm.className += (elm.className ? ' ' : '') + classList[i]; - } - } - }, - - - // The className parameter (str) can contain multiple class names separated by whitespace - unsetClass: function (elm, className) { - var classList = jsc.classNameToList(className); - for (var i = 0; i < classList.length; i += 1) { - var repl = new RegExp( - '^\\s*' + classList[i] + '\\s*|' + - '\\s*' + classList[i] + '\\s*$|' + - '\\s+' + classList[i] + '(\\s+)', - 'g' - ); - elm.className = elm.className.replace(repl, '$1'); - } - }, - - - getStyle: function (elm) { - return window.getComputedStyle ? window.getComputedStyle(elm) : elm.currentStyle; - }, - - - setStyle: (function () { - var helper = document.createElement('div'); - var getSupportedProp = function (names) { - for (var i = 0; i < names.length; i += 1) { - if (names[i] in helper.style) { - return names[i]; - } - } - }; - var props = { - borderRadius: getSupportedProp(['borderRadius', 'MozBorderRadius', 'webkitBorderRadius']), - boxShadow: getSupportedProp(['boxShadow', 'MozBoxShadow', 'webkitBoxShadow']) - }; - return function (elm, prop, value) { - switch (prop.toLowerCase()) { - case 'opacity': - var alphaOpacity = Math.round(parseFloat(value) * 100); - elm.style.opacity = value; - elm.style.filter = 'alpha(opacity=' + alphaOpacity + ')'; - break; - default: - elm.style[props[prop]] = value; - break; - } - }; - })(), - - - setBorderRadius: function (elm, value) { - jsc.setStyle(elm, 'borderRadius', value || '0'); - }, - - - setBoxShadow: function (elm, value) { - jsc.setStyle(elm, 'boxShadow', value || 'none'); - }, - - - getElementPos: function (e, relativeToViewport) { - var x = 0, y = 0; - var rect = e.getBoundingClientRect(); - x = rect.left; - y = rect.top; - if (!relativeToViewport) { - var viewPos = jsc.getViewPos(); - x += viewPos[0]; - y += viewPos[1]; - } - return [x, y]; - }, - - - getElementSize: function (e) { - return [e.offsetWidth, e.offsetHeight]; - }, - - - // get pointer's X/Y coordinates relative to viewport - getAbsPointerPos: function (e) { - if (!e) { e = window.event; } - var x = 0, y = 0; - if (typeof e.changedTouches !== 'undefined' && e.changedTouches.length) { - // touch devices - x = e.changedTouches[0].clientX; - y = e.changedTouches[0].clientY; - } else if (typeof e.clientX === 'number') { - x = e.clientX; - y = e.clientY; - } - return { x: x, y: y }; - }, - - - // get pointer's X/Y coordinates relative to target element - getRelPointerPos: function (e) { - if (!e) { e = window.event; } - var target = e.target || e.srcElement; - var targetRect = target.getBoundingClientRect(); - - var x = 0, y = 0; - - var clientX = 0, clientY = 0; - if (typeof e.changedTouches !== 'undefined' && e.changedTouches.length) { - // touch devices - clientX = e.changedTouches[0].clientX; - clientY = e.changedTouches[0].clientY; - } else if (typeof e.clientX === 'number') { - clientX = e.clientX; - clientY = e.clientY; - } - - x = clientX - targetRect.left; - y = clientY - targetRect.top; - return { x: x, y: y }; - }, - - - getViewPos: function () { - var doc = document.documentElement; - return [ - (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0), - (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0) - ]; - }, - - - getViewSize: function () { - var doc = document.documentElement; - return [ - (window.innerWidth || doc.clientWidth), - (window.innerHeight || doc.clientHeight), - ]; - }, - - - redrawPosition: function () { - - if (jsc.picker && jsc.picker.owner) { - var thisObj = jsc.picker.owner; - - var tp, vp; - - if (thisObj.fixed) { - // Fixed elements are positioned relative to viewport, - // therefore we can ignore the scroll offset - tp = jsc.getElementPos(thisObj.targetElement, true); // target pos - vp = [0, 0]; // view pos - } else { - tp = jsc.getElementPos(thisObj.targetElement); // target pos - vp = jsc.getViewPos(); // view pos - } - - var ts = jsc.getElementSize(thisObj.targetElement); // target size - var vs = jsc.getViewSize(); // view size - var ps = jsc.getPickerOuterDims(thisObj); // picker size - var a, b, c; - switch (thisObj.position.toLowerCase()) { - case 'left': a = 1; b = 0; c = -1; break; - case 'right': a = 1; b = 0; c = 1; break; - case 'top': a = 0; b = 1; c = -1; break; - default: a = 0; b = 1; c = 1; break; - } - var l = (ts[b] + ps[b]) / 2; - - // compute picker position - if (!thisObj.smartPosition) { - var pp = [ - tp[a], - tp[b] + ts[b] - l + l * c - ]; - } else { - var pp = [ - -vp[a] + tp[a] + ps[a] > vs[a] ? - (-vp[a] + tp[a] + ts[a] / 2 > vs[a] / 2 && tp[a] + ts[a] - ps[a] >= 0 ? tp[a] + ts[a] - ps[a] : tp[a]) : - tp[a], - -vp[b] + tp[b] + ts[b] + ps[b] - l + l * c > vs[b] ? - (-vp[b] + tp[b] + ts[b] / 2 > vs[b] / 2 && tp[b] + ts[b] - l - l * c >= 0 ? tp[b] + ts[b] - l - l * c : tp[b] + ts[b] - l + l * c) : - (tp[b] + ts[b] - l + l * c >= 0 ? tp[b] + ts[b] - l + l * c : tp[b] + ts[b] - l - l * c) - ]; - } - - var x = pp[a]; - var y = pp[b]; - var positionValue = thisObj.fixed ? 'fixed' : 'absolute'; - var contractShadow = - (pp[0] + ps[0] > tp[0] || pp[0] < tp[0] + ts[0]) && - (pp[1] + ps[1] < tp[1] + ts[1]); - - jsc._drawPosition(thisObj, x, y, positionValue, contractShadow); - } - }, - - - _drawPosition: function (thisObj, x, y, positionValue, contractShadow) { - var vShadow = contractShadow ? 0 : thisObj.shadowBlur; // px - - jsc.picker.wrap.style.position = positionValue; - jsc.picker.wrap.style.left = x + 'px'; - jsc.picker.wrap.style.top = y + 'px'; - - jsc.setBoxShadow( - jsc.picker.boxS, - thisObj.shadow ? - new jsc.BoxShadow(0, vShadow, thisObj.shadowBlur, 0, thisObj.shadowColor) : - null); - }, - - - getPickerDims: function (thisObj) { - var displaySlider = !!jsc.getSliderComponent(thisObj); - var dims = [ - 2 * thisObj.insetWidth + 2 * thisObj.padding + thisObj.width + - (displaySlider ? 2 * thisObj.insetWidth + jsc.getPadToSliderPadding(thisObj) + thisObj.sliderSize : 0), - 2 * thisObj.insetWidth + 2 * thisObj.padding + thisObj.height + - (thisObj.closable ? 2 * thisObj.insetWidth + thisObj.padding + thisObj.buttonHeight : 0) - ]; - return dims; - }, - - - getPickerOuterDims: function (thisObj) { - var dims = jsc.getPickerDims(thisObj); - return [ - dims[0] + 2 * thisObj.borderWidth, - dims[1] + 2 * thisObj.borderWidth - ]; - }, - - - getPadToSliderPadding: function (thisObj) { - return Math.max(thisObj.padding, 1.5 * (2 * thisObj.pointerBorderWidth + thisObj.pointerThickness)); - }, - - - getPadYComponent: function (thisObj) { - switch (thisObj.mode.charAt(1).toLowerCase()) { - case 'v': return 'v'; break; - } - return 's'; - }, - - - getSliderComponent: function (thisObj) { - if (thisObj.mode.length > 2) { - switch (thisObj.mode.charAt(2).toLowerCase()) { - case 's': return 's'; break; - case 'v': return 'v'; break; - } - } - return null; - }, - - - onDocumentMouseDown: function (e) { - if (!e) { e = window.event; } - var target = e.target || e.srcElement; - - if (target._jscLinkedInstance) { - if (target._jscLinkedInstance.showOnClick) { - target._jscLinkedInstance.show(); - } - } else if (target._jscControlName) { - jsc.onControlPointerStart(e, target, target._jscControlName, 'mouse'); - } else { - // Mouse is outside the picker controls -> hide the color picker! - if (jsc.picker && jsc.picker.owner) { - jsc.picker.owner.hide(); - } - } - }, - - - onDocumentTouchStart: function (e) { - if (!e) { e = window.event; } - var target = e.target || e.srcElement; - - if (target._jscLinkedInstance) { - if (target._jscLinkedInstance.showOnClick) { - target._jscLinkedInstance.show(); - } - } else if (target._jscControlName) { - jsc.onControlPointerStart(e, target, target._jscControlName, 'touch'); - } else { - if (jsc.picker && jsc.picker.owner) { - jsc.picker.owner.hide(); - } - } - }, - - - onWindowResize: function (e) { - jsc.redrawPosition(); - }, - - - onParentScroll: function (e) { - // hide the picker when one of the parent elements is scrolled - if (jsc.picker && jsc.picker.owner) { - jsc.picker.owner.hide(); - } - }, - - - _pointerMoveEvent: { - mouse: 'mousemove', - touch: 'touchmove' - }, - _pointerEndEvent: { - mouse: 'mouseup', - touch: 'touchend' - }, - - - _pointerOrigin: null, - _capturedTarget: null, - - - onControlPointerStart: function (e, target, controlName, pointerType) { - var thisObj = target._jscInstance; - - jsc.preventDefault(e); - jsc.captureTarget(target); - - var registerDragEvents = function (doc, offset) { - jsc.attachGroupEvent('drag', doc, jsc._pointerMoveEvent[pointerType], - jsc.onDocumentPointerMove(e, target, controlName, pointerType, offset)); - jsc.attachGroupEvent('drag', doc, jsc._pointerEndEvent[pointerType], - jsc.onDocumentPointerEnd(e, target, controlName, pointerType)); - }; - - registerDragEvents(document, [0, 0]); - - if (window.parent && window.frameElement) { - var rect = window.frameElement.getBoundingClientRect(); - var ofs = [-rect.left, -rect.top]; - registerDragEvents(window.parent.window.document, ofs); - } - - var abs = jsc.getAbsPointerPos(e); - var rel = jsc.getRelPointerPos(e); - jsc._pointerOrigin = { - x: abs.x - rel.x, - y: abs.y - rel.y - }; - - switch (controlName) { - case 'pad': - // if the slider is at the bottom, move it up - switch (jsc.getSliderComponent(thisObj)) { - case 's': if (thisObj.hsv[1] === 0) { thisObj.fromHSV(null, 100, null); } break; - case 'v': if (thisObj.hsv[2] === 0) { thisObj.fromHSV(null, null, 100); } break; - } - jsc.setPad(thisObj, e, 0, 0); - break; - - case 'sld': - jsc.setSld(thisObj, e, 0); - break; - } - - jsc.dispatchFineChange(thisObj); - }, - - - onDocumentPointerMove: function (e, target, controlName, pointerType, offset) { - return function (e) { - var thisObj = target._jscInstance; - switch (controlName) { - case 'pad': - if (!e) { e = window.event; } - jsc.setPad(thisObj, e, offset[0], offset[1]); - jsc.dispatchFineChange(thisObj); - break; - - case 'sld': - if (!e) { e = window.event; } - jsc.setSld(thisObj, e, offset[1]); - jsc.dispatchFineChange(thisObj); - break; - } - }; - }, - - - onDocumentPointerEnd: function (e, target, controlName, pointerType) { - return function (e) { - var thisObj = target._jscInstance; - jsc.detachGroupEvents('drag'); - jsc.releaseTarget(); - // Always dispatch changes after detaching outstanding mouse handlers, - // in case some user interaction will occur in user's onchange callback - // that would intrude with current mouse events - jsc.dispatchChange(thisObj); - }; - }, - - - dispatchChange: function (thisObj) { - if (thisObj.valueElement) { - if (jsc.isElementType(thisObj.valueElement, 'input')) { - jsc.fireEvent(thisObj.valueElement, 'change'); - } - } - }, - - - dispatchFineChange: function (thisObj) { - if (thisObj.onFineChange) { - var callback; - if (typeof thisObj.onFineChange === 'string') { - callback = new Function(thisObj.onFineChange); - } else { - callback = thisObj.onFineChange; - } - callback.call(thisObj); - } - }, - - - setPad: function (thisObj, e, ofsX, ofsY) { - var pointerAbs = jsc.getAbsPointerPos(e); - var x = ofsX + pointerAbs.x - jsc._pointerOrigin.x - thisObj.padding - thisObj.insetWidth; - var y = ofsY + pointerAbs.y - jsc._pointerOrigin.y - thisObj.padding - thisObj.insetWidth; - - var xVal = x * (360 / (thisObj.width - 1)); - var yVal = 100 - (y * (100 / (thisObj.height - 1))); - - switch (jsc.getPadYComponent(thisObj)) { - case 's': thisObj.fromHSV(xVal, yVal, null, jsc.leaveSld); break; - case 'v': thisObj.fromHSV(xVal, null, yVal, jsc.leaveSld); break; - } - }, - - - setSld: function (thisObj, e, ofsY) { - var pointerAbs = jsc.getAbsPointerPos(e); - var y = ofsY + pointerAbs.y - jsc._pointerOrigin.y - thisObj.padding - thisObj.insetWidth; - - var yVal = 100 - (y * (100 / (thisObj.height - 1))); - - switch (jsc.getSliderComponent(thisObj)) { - case 's': thisObj.fromHSV(null, yVal, null, jsc.leavePad); break; - case 'v': thisObj.fromHSV(null, null, yVal, jsc.leavePad); break; - } - }, - - - _vmlNS: 'jsc_vml_', - _vmlCSS: 'jsc_vml_css_', - _vmlReady: false, - - - initVML: function () { - if (!jsc._vmlReady) { - // init VML namespace - var doc = document; - if (!doc.namespaces[jsc._vmlNS]) { - doc.namespaces.add(jsc._vmlNS, 'urn:schemas-microsoft-com:vml'); - } - if (!doc.styleSheets[jsc._vmlCSS]) { - var tags = ['shape', 'shapetype', 'group', 'background', 'path', 'formulas', 'handles', 'fill', 'stroke', 'shadow', 'textbox', 'textpath', 'imagedata', 'line', 'polyline', 'curve', 'rect', 'roundrect', 'oval', 'arc', 'image']; - var ss = doc.createStyleSheet(); - ss.owningElement.id = jsc._vmlCSS; - for (var i = 0; i < tags.length; i += 1) { - ss.addRule(jsc._vmlNS + '\\:' + tags[i], 'behavior:url(#default#VML);'); - } - } - jsc._vmlReady = true; - } - }, - - - createPalette: function () { - - var paletteObj = { - elm: null, - draw: null - }; - - if (jsc.isCanvasSupported) { - // Canvas implementation for modern browsers - - var canvas = document.createElement('canvas'); - var ctx = canvas.getContext('2d'); - - var drawFunc = function (width, height, type) { - canvas.width = width; - canvas.height = height; - - ctx.clearRect(0, 0, canvas.width, canvas.height); - - var hGrad = ctx.createLinearGradient(0, 0, canvas.width, 0); - hGrad.addColorStop(0 / 6, '#F00'); - hGrad.addColorStop(1 / 6, '#FF0'); - hGrad.addColorStop(2 / 6, '#0F0'); - hGrad.addColorStop(3 / 6, '#0FF'); - hGrad.addColorStop(4 / 6, '#00F'); - hGrad.addColorStop(5 / 6, '#F0F'); - hGrad.addColorStop(6 / 6, '#F00'); - - ctx.fillStyle = hGrad; - ctx.fillRect(0, 0, canvas.width, canvas.height); - - var vGrad = ctx.createLinearGradient(0, 0, 0, canvas.height); - switch (type.toLowerCase()) { - case 's': - vGrad.addColorStop(0, 'rgba(255,255,255,0)'); - vGrad.addColorStop(1, 'rgba(255,255,255,1)'); - break; - case 'v': - vGrad.addColorStop(0, 'rgba(0,0,0,0)'); - vGrad.addColorStop(1, 'rgba(0,0,0,1)'); - break; - } - ctx.fillStyle = vGrad; - ctx.fillRect(0, 0, canvas.width, canvas.height); - }; - - paletteObj.elm = canvas; - paletteObj.draw = drawFunc; - - } else { - // VML fallback for IE 7 and 8 - - jsc.initVML(); - - var vmlContainer = document.createElement('div'); - vmlContainer.style.position = 'relative'; - vmlContainer.style.overflow = 'hidden'; - - var hGrad = document.createElement(jsc._vmlNS + ':fill'); - hGrad.type = 'gradient'; - hGrad.method = 'linear'; - hGrad.angle = '90'; - hGrad.colors = '16.67% #F0F, 33.33% #00F, 50% #0FF, 66.67% #0F0, 83.33% #FF0'; - - var hRect = document.createElement(jsc._vmlNS + ':rect'); - hRect.style.position = 'absolute'; - hRect.style.left = -1 + 'px'; - hRect.style.top = -1 + 'px'; - hRect.stroked = false; - hRect.appendChild(hGrad); - vmlContainer.appendChild(hRect); - - var vGrad = document.createElement(jsc._vmlNS + ':fill'); - vGrad.type = 'gradient'; - vGrad.method = 'linear'; - vGrad.angle = '180'; - vGrad.opacity = '0'; - - var vRect = document.createElement(jsc._vmlNS + ':rect'); - vRect.style.position = 'absolute'; - vRect.style.left = -1 + 'px'; - vRect.style.top = -1 + 'px'; - vRect.stroked = false; - vRect.appendChild(vGrad); - vmlContainer.appendChild(vRect); - - var drawFunc = function (width, height, type) { - vmlContainer.style.width = width + 'px'; - vmlContainer.style.height = height + 'px'; - - hRect.style.width = - vRect.style.width = - (width + 1) + 'px'; - hRect.style.height = - vRect.style.height = - (height + 1) + 'px'; - - // Colors must be specified during every redraw, otherwise IE won't display - // a full gradient during a subsequential redraw - hGrad.color = '#F00'; - hGrad.color2 = '#F00'; - - switch (type.toLowerCase()) { - case 's': - vGrad.color = vGrad.color2 = '#FFF'; - break; - case 'v': - vGrad.color = vGrad.color2 = '#000'; - break; - } - }; - - paletteObj.elm = vmlContainer; - paletteObj.draw = drawFunc; - } - - return paletteObj; - }, - - - createSliderGradient: function () { - - var sliderObj = { - elm: null, - draw: null - }; - - if (jsc.isCanvasSupported) { - // Canvas implementation for modern browsers - - var canvas = document.createElement('canvas'); - var ctx = canvas.getContext('2d'); - - var drawFunc = function (width, height, color1, color2) { - canvas.width = width; - canvas.height = height; - - ctx.clearRect(0, 0, canvas.width, canvas.height); - - var grad = ctx.createLinearGradient(0, 0, 0, canvas.height); - grad.addColorStop(0, color1); - grad.addColorStop(1, color2); - - ctx.fillStyle = grad; - ctx.fillRect(0, 0, canvas.width, canvas.height); - }; - - sliderObj.elm = canvas; - sliderObj.draw = drawFunc; - - } else { - // VML fallback for IE 7 and 8 - - jsc.initVML(); - - var vmlContainer = document.createElement('div'); - vmlContainer.style.position = 'relative'; - vmlContainer.style.overflow = 'hidden'; - - var grad = document.createElement(jsc._vmlNS + ':fill'); - grad.type = 'gradient'; - grad.method = 'linear'; - grad.angle = '180'; - - var rect = document.createElement(jsc._vmlNS + ':rect'); - rect.style.position = 'absolute'; - rect.style.left = -1 + 'px'; - rect.style.top = -1 + 'px'; - rect.stroked = false; - rect.appendChild(grad); - vmlContainer.appendChild(rect); - - var drawFunc = function (width, height, color1, color2) { - vmlContainer.style.width = width + 'px'; - vmlContainer.style.height = height + 'px'; - - rect.style.width = (width + 1) + 'px'; - rect.style.height = (height + 1) + 'px'; - - grad.color = color1; - grad.color2 = color2; - }; - - sliderObj.elm = vmlContainer; - sliderObj.draw = drawFunc; - } - - return sliderObj; - }, - - - leaveValue: 1 << 0, - leaveStyle: 1 << 1, - leavePad: 1 << 2, - leaveSld: 1 << 3, - - - BoxShadow: (function () { - var BoxShadow = function (hShadow, vShadow, blur, spread, color, inset) { - this.hShadow = hShadow; - this.vShadow = vShadow; - this.blur = blur; - this.spread = spread; - this.color = color; - this.inset = !!inset; - }; - - BoxShadow.prototype.toString = function () { - var vals = [ - Math.round(this.hShadow) + 'px', - Math.round(this.vShadow) + 'px', - Math.round(this.blur) + 'px', - Math.round(this.spread) + 'px', - this.color - ]; - if (this.inset) { - vals.push('inset'); - } - return vals.join(' '); - }; - - return BoxShadow; - })(), - - - // - // Usage: - // var myColor = new jscolor( [, ]) - // - - jscolor: function (targetElement, options) { - - // General options - // - this.value = null; // initial HEX color. To change it later, use methods fromString(), fromHSV() and fromRGB() - this.valueElement = targetElement; // element that will be used to display and input the color code - this.styleElement = targetElement; // element that will preview the picked color using CSS backgroundColor - this.required = true; // whether the associated text can be left empty - this.refine = true; // whether to refine the entered color code (e.g. uppercase it and remove whitespace) - this.hash = false; // whether to prefix the HEX color code with # symbol - this.uppercase = true; // whether to show the color code in upper case - this.onFineChange = null; // called instantly every time the color changes (value can be either a function or a string with javascript code) - this.activeClass = 'jscolor-active'; // class to be set to the target element when a picker window is open on it - this.overwriteImportant = false; // whether to overwrite colors of styleElement using !important - this.minS = 0; // min allowed saturation (0 - 100) - this.maxS = 100; // max allowed saturation (0 - 100) - this.minV = 0; // min allowed value (brightness) (0 - 100) - this.maxV = 100; // max allowed value (brightness) (0 - 100) - - // Accessing the picked color - // - this.hsv = [0, 0, 100]; // read-only [0-360, 0-100, 0-100] - this.rgb = [255, 255, 255]; // read-only [0-255, 0-255, 0-255] - - // Color Picker options - // - this.width = 181; // width of color palette (in px) - this.height = 101; // height of color palette (in px) - this.showOnClick = true; // whether to display the color picker when user clicks on its target element - this.mode = 'HSV'; // HSV | HVS | HS | HV - layout of the color picker controls - this.position = 'bottom'; // left | right | top | bottom - position relative to the target element - this.smartPosition = true; // automatically change picker position when there is not enough space for it - this.sliderSize = 16; // px - this.crossSize = 8; // px - this.closable = false; // whether to display the Close button - this.closeText = 'Close'; - this.buttonColor = '#000000'; // CSS color - this.buttonHeight = 18; // px - this.padding = 12; // px - this.backgroundColor = '#FFFFFF'; // CSS color - this.borderWidth = 1; // px - this.borderColor = '#BBBBBB'; // CSS color - this.borderRadius = 8; // px - this.insetWidth = 1; // px - this.insetColor = '#BBBBBB'; // CSS color - this.shadow = true; // whether to display shadow - this.shadowBlur = 15; // px - this.shadowColor = 'rgba(0,0,0,0.2)'; // CSS color - this.pointerColor = '#4C4C4C'; // px - this.pointerBorderColor = '#FFFFFF'; // px - this.pointerBorderWidth = 1; // px - this.pointerThickness = 2; // px - this.zIndex = 1000; - this.container = null; // where to append the color picker (BODY element by default) - - - for (var opt in options) { - if (options.hasOwnProperty(opt)) { - this[opt] = options[opt]; - } - } - - - this.hide = function () { - if (isPickerOwner()) { - detachPicker(); - } - }; - - - this.show = function () { - drawPicker(); - }; - - - this.redraw = function () { - if (isPickerOwner()) { - drawPicker(); - } - }; - - - this.importColor = function () { - if (!this.valueElement) { - this.exportColor(); - } else { - if (jsc.isElementType(this.valueElement, 'input')) { - if (!this.refine) { - if (!this.fromString(this.valueElement.value, jsc.leaveValue)) { - if (this.styleElement) { - this.styleElement.style.backgroundImage = this.styleElement._jscOrigStyle.backgroundImage; - this.styleElement.style.backgroundColor = this.styleElement._jscOrigStyle.backgroundColor; - this.styleElement.style.color = this.styleElement._jscOrigStyle.color; - } - this.exportColor(jsc.leaveValue | jsc.leaveStyle); - } - } else if (!this.required && /^\s*$/.test(this.valueElement.value)) { - this.valueElement.value = ''; - if (this.styleElement) { - this.styleElement.style.backgroundImage = this.styleElement._jscOrigStyle.backgroundImage; - this.styleElement.style.backgroundColor = this.styleElement._jscOrigStyle.backgroundColor; - this.styleElement.style.color = this.styleElement._jscOrigStyle.color; - } - this.exportColor(jsc.leaveValue | jsc.leaveStyle); - - } else if (this.fromString(this.valueElement.value)) { - // managed to import color successfully from the value -> OK, don't do anything - } else { - this.exportColor(); - } - } else { - // not an input element -> doesn't have any value - this.exportColor(); - } - } - }; - - - this.exportColor = function (flags) { - if (!(flags & jsc.leaveValue) && this.valueElement) { - var value = this.toString(); - if (this.uppercase) { value = value.toUpperCase(); } - if (this.hash) { value = '#' + value; } - - if (jsc.isElementType(this.valueElement, 'input')) { - this.valueElement.value = value; - } else { - this.valueElement.innerHTML = value; - } - } - if (!(flags & jsc.leaveStyle)) { - if (this.styleElement) { - var bgColor = '#' + this.toString(); - var fgColor = this.isLight() ? '#000' : '#FFF'; - - this.styleElement.style.backgroundImage = 'none'; - this.styleElement.style.backgroundColor = bgColor; - this.styleElement.style.color = fgColor; - - if (this.overwriteImportant) { - this.styleElement.setAttribute('style', - 'background: ' + bgColor + ' !important; ' + - 'color: ' + fgColor + ' !important;' - ); - } - } - } - if (!(flags & jsc.leavePad) && isPickerOwner()) { - redrawPad(); - } - if (!(flags & jsc.leaveSld) && isPickerOwner()) { - redrawSld(); - } - }; - - - // h: 0-360 - // s: 0-100 - // v: 0-100 - // - this.fromHSV = function (h, s, v, flags) { // null = don't change - if (h !== null) { - if (isNaN(h)) { return false; } - h = Math.max(0, Math.min(360, h)); - } - if (s !== null) { - if (isNaN(s)) { return false; } - s = Math.max(0, Math.min(100, this.maxS, s), this.minS); - } - if (v !== null) { - if (isNaN(v)) { return false; } - v = Math.max(0, Math.min(100, this.maxV, v), this.minV); - } - - this.rgb = HSV_RGB( - h === null ? this.hsv[0] : (this.hsv[0] = h), - s === null ? this.hsv[1] : (this.hsv[1] = s), - v === null ? this.hsv[2] : (this.hsv[2] = v) - ); - - this.exportColor(flags); - }; - - - // r: 0-255 - // g: 0-255 - // b: 0-255 - // - this.fromRGB = function (r, g, b, flags) { // null = don't change - if (r !== null) { - if (isNaN(r)) { return false; } - r = Math.max(0, Math.min(255, r)); - } - if (g !== null) { - if (isNaN(g)) { return false; } - g = Math.max(0, Math.min(255, g)); - } - if (b !== null) { - if (isNaN(b)) { return false; } - b = Math.max(0, Math.min(255, b)); - } - - var hsv = RGB_HSV( - r === null ? this.rgb[0] : r, - g === null ? this.rgb[1] : g, - b === null ? this.rgb[2] : b - ); - if (hsv[0] !== null) { - this.hsv[0] = Math.max(0, Math.min(360, hsv[0])); - } - if (hsv[2] !== 0) { - this.hsv[1] = hsv[1] === null ? null : Math.max(0, this.minS, Math.min(100, this.maxS, hsv[1])); - } - this.hsv[2] = hsv[2] === null ? null : Math.max(0, this.minV, Math.min(100, this.maxV, hsv[2])); - - // update RGB according to final HSV, as some values might be trimmed - var rgb = HSV_RGB(this.hsv[0], this.hsv[1], this.hsv[2]); - this.rgb[0] = rgb[0]; - this.rgb[1] = rgb[1]; - this.rgb[2] = rgb[2]; - - this.exportColor(flags); - }; - - - this.fromString = function (str, flags) { - var m; - if (m = str.match(/^\W*([0-9A-F]{3}([0-9A-F]{3})?)\W*$/i)) { - // HEX notation - // - - if (m[1].length === 6) { - // 6-char notation - this.fromRGB( - parseInt(m[1].substr(0, 2), 16), - parseInt(m[1].substr(2, 2), 16), - parseInt(m[1].substr(4, 2), 16), - flags - ); - } else { - // 3-char notation - this.fromRGB( - parseInt(m[1].charAt(0) + m[1].charAt(0), 16), - parseInt(m[1].charAt(1) + m[1].charAt(1), 16), - parseInt(m[1].charAt(2) + m[1].charAt(2), 16), - flags - ); - } - return true; - - } else if (m = str.match(/^\W*rgba?\(([^)]*)\)\W*$/i)) { - var params = m[1].split(','); - var re = /^\s*(\d*)(\.\d+)?\s*$/; - var mR, mG, mB; - if ( - params.length >= 3 && - (mR = params[0].match(re)) && - (mG = params[1].match(re)) && - (mB = params[2].match(re)) - ) { - var r = parseFloat((mR[1] || '0') + (mR[2] || '')); - var g = parseFloat((mG[1] || '0') + (mG[2] || '')); - var b = parseFloat((mB[1] || '0') + (mB[2] || '')); - this.fromRGB(r, g, b, flags); - return true; - } - } - return false; - }; - - - this.toString = function () { - return ( - (0x100 | Math.round(this.rgb[0])).toString(16).substr(1) + - (0x100 | Math.round(this.rgb[1])).toString(16).substr(1) + - (0x100 | Math.round(this.rgb[2])).toString(16).substr(1) - ); - }; - - - this.toHEXString = function () { - return '#' + this.toString().toUpperCase(); - }; - - - this.toRGBString = function () { - return ('rgb(' + - Math.round(this.rgb[0]) + ',' + - Math.round(this.rgb[1]) + ',' + - Math.round(this.rgb[2]) + ')' - ); - }; - - - this.isLight = function () { - return ( - 0.213 * this.rgb[0] + - 0.715 * this.rgb[1] + - 0.072 * this.rgb[2] > - 255 / 2 - ); - }; - - - this._processParentElementsInDOM = function () { - if (this._linkedElementsProcessed) { return; } - this._linkedElementsProcessed = true; - - var elm = this.targetElement; - do { - // If the target element or one of its parent nodes has fixed position, - // then use fixed positioning instead - // - // Note: In Firefox, getComputedStyle returns null in a hidden iframe, - // that's why we need to check if the returned style object is non-empty - var currStyle = jsc.getStyle(elm); - if (currStyle && currStyle.position.toLowerCase() === 'fixed') { - this.fixed = true; - } - - if (elm !== this.targetElement) { - // Ensure to attach onParentScroll only once to each parent element - // (multiple targetElements can share the same parent nodes) - // - // Note: It's not just offsetParents that can be scrollable, - // that's why we loop through all parent nodes - if (!elm._jscEventsAttached) { - jsc.attachEvent(elm, 'scroll', jsc.onParentScroll); - elm._jscEventsAttached = true; - } - } - } while ((elm = elm.parentNode) && !jsc.isElementType(elm, 'body')); - }; - - - // r: 0-255 - // g: 0-255 - // b: 0-255 - // - // returns: [ 0-360, 0-100, 0-100 ] - // - function RGB_HSV(r, g, b) { - r /= 255; - g /= 255; - b /= 255; - var n = Math.min(Math.min(r, g), b); - var v = Math.max(Math.max(r, g), b); - var m = v - n; - if (m === 0) { return [null, 0, 100 * v]; } - var h = r === n ? 3 + (b - g) / m : (g === n ? 5 + (r - b) / m : 1 + (g - r) / m); - return [ - 60 * (h === 6 ? 0 : h), - 100 * (m / v), - 100 * v - ]; - } - - - // h: 0-360 - // s: 0-100 - // v: 0-100 - // - // returns: [ 0-255, 0-255, 0-255 ] - // - function HSV_RGB(h, s, v) { - var u = 255 * (v / 100); - - if (h === null) { - return [u, u, u]; - } - - h /= 60; - s /= 100; - - var i = Math.floor(h); - var f = i % 2 ? h - i : 1 - (h - i); - var m = u * (1 - s); - var n = u * (1 - s * f); - switch (i) { - case 6: - case 0: return [u, n, m]; - case 1: return [n, u, m]; - case 2: return [m, u, n]; - case 3: return [m, n, u]; - case 4: return [n, m, u]; - case 5: return [u, m, n]; - } - } - - - function detachPicker() { - jsc.unsetClass(THIS.targetElement, THIS.activeClass); - jsc.picker.wrap.parentNode.removeChild(jsc.picker.wrap); - delete jsc.picker.owner; - } - - - function drawPicker() { - - // At this point, when drawing the picker, we know what the parent elements are - // and we can do all related DOM operations, such as registering events on them - // or checking their positioning - THIS._processParentElementsInDOM(); - - if (!jsc.picker) { - jsc.picker = { - owner: null, - wrap: document.createElement('div'), - box: document.createElement('div'), - boxS: document.createElement('div'), // shadow area - boxB: document.createElement('div'), // border - pad: document.createElement('div'), - padB: document.createElement('div'), // border - padM: document.createElement('div'), // mouse/touch area - padPal: jsc.createPalette(), - cross: document.createElement('div'), - crossBY: document.createElement('div'), // border Y - crossBX: document.createElement('div'), // border X - crossLY: document.createElement('div'), // line Y - crossLX: document.createElement('div'), // line X - sld: document.createElement('div'), - sldB: document.createElement('div'), // border - sldM: document.createElement('div'), // mouse/touch area - sldGrad: jsc.createSliderGradient(), - sldPtrS: document.createElement('div'), // slider pointer spacer - sldPtrIB: document.createElement('div'), // slider pointer inner border - sldPtrMB: document.createElement('div'), // slider pointer middle border - sldPtrOB: document.createElement('div'), // slider pointer outer border - btn: document.createElement('div'), - btnT: document.createElement('span') // text - }; - - jsc.picker.pad.appendChild(jsc.picker.padPal.elm); - jsc.picker.padB.appendChild(jsc.picker.pad); - jsc.picker.cross.appendChild(jsc.picker.crossBY); - jsc.picker.cross.appendChild(jsc.picker.crossBX); - jsc.picker.cross.appendChild(jsc.picker.crossLY); - jsc.picker.cross.appendChild(jsc.picker.crossLX); - jsc.picker.padB.appendChild(jsc.picker.cross); - jsc.picker.box.appendChild(jsc.picker.padB); - jsc.picker.box.appendChild(jsc.picker.padM); - - jsc.picker.sld.appendChild(jsc.picker.sldGrad.elm); - jsc.picker.sldB.appendChild(jsc.picker.sld); - jsc.picker.sldB.appendChild(jsc.picker.sldPtrOB); - jsc.picker.sldPtrOB.appendChild(jsc.picker.sldPtrMB); - jsc.picker.sldPtrMB.appendChild(jsc.picker.sldPtrIB); - jsc.picker.sldPtrIB.appendChild(jsc.picker.sldPtrS); - jsc.picker.box.appendChild(jsc.picker.sldB); - jsc.picker.box.appendChild(jsc.picker.sldM); - - jsc.picker.btn.appendChild(jsc.picker.btnT); - jsc.picker.box.appendChild(jsc.picker.btn); - - jsc.picker.boxB.appendChild(jsc.picker.box); - jsc.picker.wrap.appendChild(jsc.picker.boxS); - jsc.picker.wrap.appendChild(jsc.picker.boxB); - } - - var p = jsc.picker; - - var displaySlider = !!jsc.getSliderComponent(THIS); - var dims = jsc.getPickerDims(THIS); - var crossOuterSize = (2 * THIS.pointerBorderWidth + THIS.pointerThickness + 2 * THIS.crossSize); - var padToSliderPadding = jsc.getPadToSliderPadding(THIS); - var borderRadius = Math.min( - THIS.borderRadius, - Math.round(THIS.padding * Math.PI)); // px - var padCursor = 'crosshair'; - - // wrap - p.wrap.style.clear = 'both'; - p.wrap.style.width = (dims[0] + 2 * THIS.borderWidth) + 'px'; - p.wrap.style.height = (dims[1] + 2 * THIS.borderWidth) + 'px'; - p.wrap.style.zIndex = THIS.zIndex; - - // picker - p.box.style.width = dims[0] + 'px'; - p.box.style.height = dims[1] + 'px'; - - p.boxS.style.position = 'absolute'; - p.boxS.style.left = '0'; - p.boxS.style.top = '0'; - p.boxS.style.width = '100%'; - p.boxS.style.height = '100%'; - jsc.setBorderRadius(p.boxS, borderRadius + 'px'); - - // picker border - p.boxB.style.position = 'relative'; - p.boxB.style.border = THIS.borderWidth + 'px solid'; - p.boxB.style.borderColor = THIS.borderColor; - p.boxB.style.background = THIS.backgroundColor; - jsc.setBorderRadius(p.boxB, borderRadius + 'px'); - - // IE hack: - // If the element is transparent, IE will trigger the event on the elements under it, - // e.g. on Canvas or on elements with border - p.padM.style.background = - p.sldM.style.background = - '#FFF'; - jsc.setStyle(p.padM, 'opacity', '0'); - jsc.setStyle(p.sldM, 'opacity', '0'); - - // pad - p.pad.style.position = 'relative'; - p.pad.style.width = THIS.width + 'px'; - p.pad.style.height = THIS.height + 'px'; - - // pad palettes (HSV and HVS) - p.padPal.draw(THIS.width, THIS.height, jsc.getPadYComponent(THIS)); - - // pad border - p.padB.style.position = 'absolute'; - p.padB.style.left = THIS.padding + 'px'; - p.padB.style.top = THIS.padding + 'px'; - p.padB.style.border = THIS.insetWidth + 'px solid'; - p.padB.style.borderColor = THIS.insetColor; - - // pad mouse area - p.padM._jscInstance = THIS; - p.padM._jscControlName = 'pad'; - p.padM.style.position = 'absolute'; - p.padM.style.left = '0'; - p.padM.style.top = '0'; - p.padM.style.width = (THIS.padding + 2 * THIS.insetWidth + THIS.width + padToSliderPadding / 2) + 'px'; - p.padM.style.height = dims[1] + 'px'; - p.padM.style.cursor = padCursor; - - // pad cross - p.cross.style.position = 'absolute'; - p.cross.style.left = - p.cross.style.top = - '0'; - p.cross.style.width = - p.cross.style.height = - crossOuterSize + 'px'; - - // pad cross border Y and X - p.crossBY.style.position = - p.crossBX.style.position = - 'absolute'; - p.crossBY.style.background = - p.crossBX.style.background = - THIS.pointerBorderColor; - p.crossBY.style.width = - p.crossBX.style.height = - (2 * THIS.pointerBorderWidth + THIS.pointerThickness) + 'px'; - p.crossBY.style.height = - p.crossBX.style.width = - crossOuterSize + 'px'; - p.crossBY.style.left = - p.crossBX.style.top = - (Math.floor(crossOuterSize / 2) - Math.floor(THIS.pointerThickness / 2) - THIS.pointerBorderWidth) + 'px'; - p.crossBY.style.top = - p.crossBX.style.left = - '0'; - - // pad cross line Y and X - p.crossLY.style.position = - p.crossLX.style.position = - 'absolute'; - p.crossLY.style.background = - p.crossLX.style.background = - THIS.pointerColor; - p.crossLY.style.height = - p.crossLX.style.width = - (crossOuterSize - 2 * THIS.pointerBorderWidth) + 'px'; - p.crossLY.style.width = - p.crossLX.style.height = - THIS.pointerThickness + 'px'; - p.crossLY.style.left = - p.crossLX.style.top = - (Math.floor(crossOuterSize / 2) - Math.floor(THIS.pointerThickness / 2)) + 'px'; - p.crossLY.style.top = - p.crossLX.style.left = - THIS.pointerBorderWidth + 'px'; - - // slider - p.sld.style.overflow = 'hidden'; - p.sld.style.width = THIS.sliderSize + 'px'; - p.sld.style.height = THIS.height + 'px'; - - // slider gradient - p.sldGrad.draw(THIS.sliderSize, THIS.height, '#000', '#000'); - - // slider border - p.sldB.style.display = displaySlider ? 'block' : 'none'; - p.sldB.style.position = 'absolute'; - p.sldB.style.right = THIS.padding + 'px'; - p.sldB.style.top = THIS.padding + 'px'; - p.sldB.style.border = THIS.insetWidth + 'px solid'; - p.sldB.style.borderColor = THIS.insetColor; - - // slider mouse area - p.sldM._jscInstance = THIS; - p.sldM._jscControlName = 'sld'; - p.sldM.style.display = displaySlider ? 'block' : 'none'; - p.sldM.style.position = 'absolute'; - p.sldM.style.right = '0'; - p.sldM.style.top = '0'; - p.sldM.style.width = (THIS.sliderSize + padToSliderPadding / 2 + THIS.padding + 2 * THIS.insetWidth) + 'px'; - p.sldM.style.height = dims[1] + 'px'; - p.sldM.style.cursor = 'default'; - - // slider pointer inner and outer border - p.sldPtrIB.style.border = - p.sldPtrOB.style.border = - THIS.pointerBorderWidth + 'px solid ' + THIS.pointerBorderColor; - - // slider pointer outer border - p.sldPtrOB.style.position = 'absolute'; - p.sldPtrOB.style.left = -(2 * THIS.pointerBorderWidth + THIS.pointerThickness) + 'px'; - p.sldPtrOB.style.top = '0'; - - // slider pointer middle border - p.sldPtrMB.style.border = THIS.pointerThickness + 'px solid ' + THIS.pointerColor; - - // slider pointer spacer - p.sldPtrS.style.width = THIS.sliderSize + 'px'; - p.sldPtrS.style.height = sliderPtrSpace + 'px'; - - // the Close button - function setBtnBorder() { - var insetColors = THIS.insetColor.split(/\s+/); - var outsetColor = insetColors.length < 2 ? insetColors[0] : insetColors[1] + ' ' + insetColors[0] + ' ' + insetColors[0] + ' ' + insetColors[1]; - p.btn.style.borderColor = outsetColor; - } - p.btn.style.display = THIS.closable ? 'block' : 'none'; - p.btn.style.position = 'absolute'; - p.btn.style.left = THIS.padding + 'px'; - p.btn.style.bottom = THIS.padding + 'px'; - p.btn.style.padding = '0 15px'; - p.btn.style.height = THIS.buttonHeight + 'px'; - p.btn.style.border = THIS.insetWidth + 'px solid'; - setBtnBorder(); - p.btn.style.color = THIS.buttonColor; - p.btn.style.font = '12px sans-serif'; - p.btn.style.textAlign = 'center'; - try { - p.btn.style.cursor = 'pointer'; - } catch (eOldIE) { - p.btn.style.cursor = 'hand'; - } - p.btn.onmousedown = function () { - THIS.hide(); - }; - p.btnT.style.lineHeight = THIS.buttonHeight + 'px'; - p.btnT.innerHTML = ''; - p.btnT.appendChild(document.createTextNode(THIS.closeText)); - - // place pointers - redrawPad(); - redrawSld(); - - // If we are changing the owner without first closing the picker, - // make sure to first deal with the old owner - if (jsc.picker.owner && jsc.picker.owner !== THIS) { - jsc.unsetClass(jsc.picker.owner.targetElement, THIS.activeClass); - } - - // Set the new picker owner - jsc.picker.owner = THIS; - - // The redrawPosition() method needs picker.owner to be set, that's why we call it here, - // after setting the owner - if (jsc.isElementType(container, 'body')) { - jsc.redrawPosition(); - } else { - jsc._drawPosition(THIS, 0, 0, 'relative', false); - } - - if (p.wrap.parentNode != container) { - container.appendChild(p.wrap); - } - - jsc.setClass(THIS.targetElement, THIS.activeClass); - } - - - function redrawPad() { - // redraw the pad pointer - switch (jsc.getPadYComponent(THIS)) { - case 's': var yComponent = 1; break; - case 'v': var yComponent = 2; break; - } - var x = Math.round((THIS.hsv[0] / 360) * (THIS.width - 1)); - var y = Math.round((1 - THIS.hsv[yComponent] / 100) * (THIS.height - 1)); - var crossOuterSize = (2 * THIS.pointerBorderWidth + THIS.pointerThickness + 2 * THIS.crossSize); - var ofs = -Math.floor(crossOuterSize / 2); - jsc.picker.cross.style.left = (x + ofs) + 'px'; - jsc.picker.cross.style.top = (y + ofs) + 'px'; - - // redraw the slider - switch (jsc.getSliderComponent(THIS)) { - case 's': - var rgb1 = HSV_RGB(THIS.hsv[0], 100, THIS.hsv[2]); - var rgb2 = HSV_RGB(THIS.hsv[0], 0, THIS.hsv[2]); - var color1 = 'rgb(' + - Math.round(rgb1[0]) + ',' + - Math.round(rgb1[1]) + ',' + - Math.round(rgb1[2]) + ')'; - var color2 = 'rgb(' + - Math.round(rgb2[0]) + ',' + - Math.round(rgb2[1]) + ',' + - Math.round(rgb2[2]) + ')'; - jsc.picker.sldGrad.draw(THIS.sliderSize, THIS.height, color1, color2); - break; - case 'v': - var rgb = HSV_RGB(THIS.hsv[0], THIS.hsv[1], 100); - var color1 = 'rgb(' + - Math.round(rgb[0]) + ',' + - Math.round(rgb[1]) + ',' + - Math.round(rgb[2]) + ')'; - var color2 = '#000'; - jsc.picker.sldGrad.draw(THIS.sliderSize, THIS.height, color1, color2); - break; - } - } - - - function redrawSld() { - var sldComponent = jsc.getSliderComponent(THIS); - if (sldComponent) { - // redraw the slider pointer - switch (sldComponent) { - case 's': var yComponent = 1; break; - case 'v': var yComponent = 2; break; - } - var y = Math.round((1 - THIS.hsv[yComponent] / 100) * (THIS.height - 1)); - jsc.picker.sldPtrOB.style.top = (y - (2 * THIS.pointerBorderWidth + THIS.pointerThickness) - Math.floor(sliderPtrSpace / 2)) + 'px'; - } - } - - - function isPickerOwner() { - return jsc.picker && jsc.picker.owner === THIS; - } - - - function blurValue() { - THIS.importColor(); - } - - - // Find the target element - if (typeof targetElement === 'string') { - var id = targetElement; - var elm = document.getElementById(id); - if (elm) { - this.targetElement = elm; - } else { - jsc.warn('Could not find target element with ID \'' + id + '\''); - } - } else if (targetElement) { - this.targetElement = targetElement; - } else { - jsc.warn('Invalid target element: \'' + targetElement + '\''); - } - - if (this.targetElement._jscLinkedInstance) { - jsc.warn('Cannot link jscolor twice to the same element. Skipping.'); - return; - } - this.targetElement._jscLinkedInstance = this; - - // Find the value element - this.valueElement = jsc.fetchElement(this.valueElement); - // Find the style element - this.styleElement = jsc.fetchElement(this.styleElement); - - var THIS = this; - var container = - this.container ? - jsc.fetchElement(this.container) : - document.getElementsByTagName('body')[0]; - var sliderPtrSpace = 3; // px - - // For BUTTON elements it's important to stop them from sending the form when clicked - // (e.g. in Safari) - if (jsc.isElementType(this.targetElement, 'button')) { - if (this.targetElement.onclick) { - var origCallback = this.targetElement.onclick; - this.targetElement.onclick = function (evt) { - origCallback.call(this, evt); - return false; - }; - } else { - this.targetElement.onclick = function () { return false; }; - } - } - - /* - var elm = this.targetElement; - do { - // If the target element or one of its offsetParents has fixed position, - // then use fixed positioning instead - // - // Note: In Firefox, getComputedStyle returns null in a hidden iframe, - // that's why we need to check if the returned style object is non-empty - var currStyle = jsc.getStyle(elm); - if (currStyle && currStyle.position.toLowerCase() === 'fixed') { - this.fixed = true; - } - - if (elm !== this.targetElement) { - // attach onParentScroll so that we can recompute the picker position - // when one of the offsetParents is scrolled - if (!elm._jscEventsAttached) { - jsc.attachEvent(elm, 'scroll', jsc.onParentScroll); - elm._jscEventsAttached = true; - } - } - } while ((elm = elm.offsetParent) && !jsc.isElementType(elm, 'body')); - */ - - // valueElement - if (this.valueElement) { - if (jsc.isElementType(this.valueElement, 'input')) { - var updateField = function () { - THIS.fromString(THIS.valueElement.value, jsc.leaveValue); - jsc.dispatchFineChange(THIS); - }; - jsc.attachEvent(this.valueElement, 'keyup', updateField); - jsc.attachEvent(this.valueElement, 'input', updateField); - jsc.attachEvent(this.valueElement, 'blur', blurValue); - this.valueElement.setAttribute('autocomplete', 'off'); - } - } - - // styleElement - if (this.styleElement) { - this.styleElement._jscOrigStyle = { - backgroundImage: this.styleElement.style.backgroundImage, - backgroundColor: this.styleElement.style.backgroundColor, - color: this.styleElement.style.color - }; - } - - if (this.value) { - // Try to set the color from the .value option and if unsuccessful, - // export the current color - if (!this.fromString(this.value)) { - this.exportColor(); - } - } else { - this.importColor(); - } - } - - }; - - - //================================ - // Public properties and methods - //================================ - - - // By default, search for all elements with class="jscolor" and install a color picker on them. - // - // You can change what class name will be looked for by setting the property jscolor.lookupClass - // anywhere in your HTML document. To completely disable the automatic lookup, set it to null. - // - jsc.jscolor.lookupClass = 'jscolor'; - - - jsc.jscolor.installByClassName = function (className) { - var inputElms = document.getElementsByTagName('input'); - var buttonElms = document.getElementsByTagName('button'); - - jsc.tryInstallOnElements(inputElms, className); - jsc.tryInstallOnElements(buttonElms, className); - }; - - - jsc.register(); - - - return jsc.jscolor; - - - })(); -}); diff --git a/amd/src/leveleditor.js b/amd/src/leveleditor.js deleted file mode 100644 index f6dac1f..0000000 --- a/amd/src/leveleditor.js +++ /dev/null @@ -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 = $("" - + "" - + ""); - - // 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; -}); \ No newline at end of file diff --git a/amd/src/renderbadge.js b/amd/src/renderbadge.js deleted file mode 100644 index 0f30388..0000000 --- a/amd/src/renderbadge.js +++ /dev/null @@ -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', 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; -}); \ No newline at end of file diff --git a/amd/src/skilleditor.js b/amd/src/skilleditor.js deleted file mode 100644 index ec7cff6..0000000 --- a/amd/src/skilleditor.js +++ /dev/null @@ -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 = $("").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($("" + data.name + "")); - }); - - } - if (keycode == '27') { - debug.info("Cancelled editing"); - $input.replaceWith($("" + name + "")); - } - }).on("focusout", function input_cancel(e) { - debug.info("Cancelled editing"); - $input.replaceWith($("" + name + "")); - }); - $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 = $(""); - - $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($("")); - - $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; -}); \ No newline at end of file diff --git a/block_gradelevel.php b/block_gradelevel.php deleted file mode 100644 index e4bff3c..0000000 --- a/block_gradelevel.php +++ /dev/null @@ -1,90 +0,0 @@ -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 = "
"; - $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 = "
".get_string('levelup_at','block_gradelevel')." {$pointstotal}/{$level_info->next_at}
"; - } - else - { - $this->content->footer = "
".get_string('levelup_done','block_gradelevel')."
"; - } - - $coursecontext = context_course::instance($COURSE->id); - - if(has_capability('block/gradelevel:viewresults', $coursecontext)) - { - $this->content->footer .= "\n"; - } - } - return $this->content; - } - - - public function hide_header() { return !get_config('gradelevel', 'showtitle'); } - - public function has_config() { return true; } - - - - - -} \ No newline at end of file diff --git a/block_mytreestudyplan.php b/block_mytreestudyplan.php new file mode 100644 index 0000000..7e63f0b --- /dev/null +++ b/block_mytreestudyplan.php @@ -0,0 +1,91 @@ +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 = "".get_string("view_plan","local_treestudyplan").""; + if(has_capability("local/treestudyplan:editstudyplan",$systemcontext)){ + $this->content->footer .= "  ".get_string("cfg_plans","local_treestudyplan").""; + } + } else if (count($mystudyplans) > 0) { + $this->content->footer = "{$invite_text}"; + } + + return $this->content; + } + + + public function hide_header() { return false; } + + public function has_config() { return false; } + + + + + +} \ No newline at end of file diff --git a/cfg_globallevels.php b/cfg_globallevels.php deleted file mode 100644 index 391ff25..0000000 --- a/cfg_globallevels.php +++ /dev/null @@ -1,34 +0,0 @@ -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(); diff --git a/cfg_skilllevels.php b/cfg_skilllevels.php deleted file mode 100644 index df6302b..0000000 --- a/cfg_skilllevels.php +++ /dev/null @@ -1,48 +0,0 @@ -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 ""; -print $OUTPUT->footer(); diff --git a/cfg_skills.php b/cfg_skills.php deleted file mode 100644 index 52798cf..0000000 --- a/cfg_skills.php +++ /dev/null @@ -1,35 +0,0 @@ -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(); diff --git a/classes/levelset.php b/classes/levelset.php deleted file mode 100644 index fa383d7..0000000 --- a/classes/levelset.php +++ /dev/null @@ -1,499 +0,0 @@ -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 = "
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); - - } - -} \ No newline at end of file diff --git a/classes/skillmgmtservice.php b/classes/skillmgmtservice.php deleted file mode 100644 index e07b529..0000000 --- a/classes/skillmgmtservice.php +++ /dev/null @@ -1,473 +0,0 @@ -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 = "

".get_string('levelcfg_description','block_gradelevel')."

"; - $s .= ""; - $s .= ""; - $s .= ""; - foreach($levels as $lvl) - { - $color = ltrim($lvl->badgecolor,"#"); // trim any leading hashes - $s .= ""; - - } - $s .= ""; - $s .= ""; - $s .= "
".get_string('levelcfg_head_points','block_gradelevel')."".get_string('levelcfg_head_color','block_gradelevel')."
".get_string("levelcfg_addlevel",'block_gradelevel')."
"; - $s .= "

"; - if($skill_id > 0) - { - $s .= " "; - } - $s .= "

"; - - 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 = "
    "; - foreach($skills as $skill) - { - $s .= static::single_skill_editor_item($skill); - } - - $s .= "
"; - $s .= "".get_string('cfg_addskill','block_gradelevel').""; - $s .= "
"; - - return $s; - } - - public static function render_skill_editor(int $skill_id) - { - $skill = block_gradelevel_levelset::find_by_id($skill_id); - - $s = "
    "; - $s .= static::single_skill_editor_item($skill,true); - $s .= "
"; - - return $s; - } - - private static function single_skill_editor_item($skill,$single=false) - { - global $OUTPUT; - - $skill_id = $skill->getId(); - $s = "
  • "; - if(!$single){ - $s .= ""; - } - $s .= $skill->render_demo_badge(static::DEMOBADGE_SIZE).""; - - if(!$single){ - $s .= ""; - if(count($skill->list_courses()) == 0){ - $s .= ""; - } - } - - $s .= ""; - $s .= "
    ".$skill->getName().""; - $s .= ""; - $s .= "
  • "; - return $s; - } - -} \ No newline at end of file diff --git a/db/access.php b/db/access.php index 4b61ef2..0ad179a 100644 --- a/db/access.php +++ b/db/access.php @@ -1,17 +1,7 @@ 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 - ), - - ), ); \ No newline at end of file diff --git a/db/install.xml b/db/install.xml deleted file mode 100644 index 4164451..0000000 --- a/db/install.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - -
    - - - - - - - - - - - -
    - - - - - - - - - - - -
    -
    -
    \ No newline at end of file diff --git a/db/services.php b/db/services.php deleted file mode 100644 index ecf3fb4..0000000 --- a/db/services.php +++ /dev/null @@ -1,93 +0,0 @@ - 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'), - ), - -); diff --git a/db/upgrade.php b/db/upgrade.php deleted file mode 100644 index e5069f2..0000000 --- a/db/upgrade.php +++ /dev/null @@ -1,70 +0,0 @@ -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; -} \ No newline at end of file diff --git a/doc_USER_GRADE.txt b/doc_USER_GRADE.txt deleted file mode 100644 index a6b6084..0000000 --- a/doc_USER_GRADE.txt +++ /dev/null @@ -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 -) diff --git a/edit_form.php b/edit_form.php deleted file mode 100644 index 9391192..0000000 --- a/edit_form.php +++ /dev/null @@ -1,82 +0,0 @@ -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); - } - } - } - -} \ No newline at end of file diff --git a/lang/en/block_gradelevel.php b/lang/en/block_gradelevel.php deleted file mode 100644 index fef09e4..0000000 --- a/lang/en/block_gradelevel.php +++ /dev/null @@ -1,54 +0,0 @@ -libdir.'/gradelib.php'); -require_once($CFG->dirroot.'/grade/querylib.php'); - diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 5a05955..0000000 --- a/package-lock.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "lockfileVersion": 1 -} diff --git a/pix/brokenbadge.svg b/pix/brokenbadge.svg deleted file mode 100644 index 9040798..0000000 --- a/pix/brokenbadge.svg +++ /dev/null @@ -1,2601 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Engels - Nederlands - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Engels - Nederlands - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pix/undefinedskill.png b/pix/undefinedskill.png deleted file mode 100644 index b23c864..0000000 Binary files a/pix/undefinedskill.png and /dev/null differ diff --git a/pix/undefinedskill.svg b/pix/undefinedskill.svg deleted file mode 100644 index 01dd950..0000000 --- a/pix/undefinedskill.svg +++ /dev/null @@ -1,772 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - M - - - - - FZ - - - - - M - - - - - FZ - - S - - - diff --git a/settings.php b/settings.php index d4f01a2..ab4fa67 100644 --- a/settings.php +++ b/settings.php @@ -1,40 +1,2 @@ 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; \ No newline at end of file diff --git a/styles.css b/styles.css index 490c2df..eedbe8c 100644 --- a/styles.css +++ b/styles.css @@ -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; -} \ No newline at end of file +/* 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; +} diff --git a/templates/block.mustache b/templates/block.mustache new file mode 100644 index 0000000..99442e3 --- /dev/null +++ b/templates/block.mustache @@ -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 . +}} +{{! + @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): + { + } +}} + +
    +
    +
    + Loading... +
    +
    +
    + {{^teachermode}} + + {{/teachermode}} + {{#teachermode}} + + {{/teachermode}} + +
    +
    \ No newline at end of file diff --git a/version.php b/version.php index 5ea2e88..5f1e3a5 100644 --- a/version.php +++ b/version.php @@ -1,4 +1,8 @@ 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) \ No newline at end of file +$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, +]; \ No newline at end of file diff --git a/view-icon.php b/view-icon.php deleted file mode 100644 index 24cf0a2..0000000 --- a/view-icon.php +++ /dev/null @@ -1,49 +0,0 @@ -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"; -} diff --git a/view-results.php b/view-results.php deleted file mode 100644 index 8b1a04e..0000000 --- a/view-results.php +++ /dev/null @@ -1,107 +0,0 @@ -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 "

    ".get_string('course', 'core')." " . $COURSE->fullname."

    "; - -//retrieve groups -$course_groups = groups_get_all_groups($COURSE->id); -// retrieve users -$remaining_users = get_enrolled_users($coursecontext); - -print "
    "; -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 "
      "; - foreach($members as $usr) - { - $pointstotal = round($skill->get_levelset_grade($usr->id),1); - $level_info = $skill->calculate_level($pointstotal); - - print "
    • "; - print $skill->render_badge($pointstotal,BADGE_SIZE); - print "
      {$usr->firstname} {$usr->lastname}
      "; - - if($level_info->levelup_total > 0) - { - print "
      ".get_string('levelup_at','block_gradelevel')." {$pointstotal}/{$level_info->next_at}
      "; - } - else - { - print "
      ".get_string('levelup_done','block_gradelevel')."
      "; - } - - print "
    • "; - unset($remaining_users[$usr->id]); - } - print "
    "; - } - - $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 "
      "; -foreach($remaining_users as $usr) -{ - $pointstotal = round($skill->get_levelset_grade($usr->id),1); - $level_info = $skill->calculate_level($pointstotal); - print "
    • "; - print $skill->render_badge($pointstotal,BADGE_SIZE); - print "
      {$usr->firstname} {$usr->lastname}
      "; - if($level_info->levelup_total > 0) - { - print "
      ".get_string('levelup_at','block_gradelevel')." {$pointstotal}/{$level_info->next_at}
      "; - } - else - { - print "
      ".get_string('levelup_done','block_gradelevel')."
      "; - } - print "
    • "; - -} -print "
    "; - -print "
    "; - -print $OUTPUT->footer();