diff --git a/.eslintrc b/.eslintrc
new file mode 100644
index 0000000..961467d
--- /dev/null
+++ b/.eslintrc
@@ -0,0 +1,214 @@
+{
+ 'plugins': [
+ 'promise',
+ ],
+ 'env': {
+ 'browser': true,
+ 'amd': true
+ },
+ 'globals': {
+ 'M': true,
+ 'Y': true
+ },
+ 'rules': {
+ // See http://eslint.org/docs/rules/ for all rules and explanations of all
+ // rules.
+
+ // === Possible Errors ===
+ 'comma-dangle': 'off',
+ 'no-compare-neg-zero': 'error',
+ 'no-cond-assign': 'error',
+ 'no-console': 'error',
+ 'no-constant-condition': 'error',
+ 'no-control-regex': 'error',
+ 'no-debugger': 'error',
+ 'no-dupe-args': 'error',
+ 'no-dupe-keys': 'error',
+ 'no-duplicate-case': 'error',
+ 'no-empty': 'warn',
+ 'no-empty-character-class': 'error',
+ 'no-ex-assign': 'error',
+ 'no-extra-boolean-cast': 'error',
+ 'no-extra-parens': 'off',
+ 'no-extra-semi': 'error',
+ 'no-func-assign': 'error',
+ 'no-inner-declarations': 'error',
+ 'no-invalid-regexp': 'error',
+ 'no-irregular-whitespace': 'error',
+ 'no-obj-calls': 'error',
+ 'no-prototype-builtins': 'off',
+ 'no-regex-spaces': 'error',
+ 'no-sparse-arrays': 'error',
+ 'no-unexpected-multiline': 'error',
+ 'no-unreachable': 'warn',
+ 'no-unsafe-finally': 'error',
+ 'no-unsafe-negation': 'error',
+ 'use-isnan': 'error',
+ 'valid-jsdoc': ['warn', { 'requireReturn': false, 'requireParamDescription': false, 'requireReturnDescription': false }],
+ 'valid-typeof': 'error',
+
+ // === Best Practices ===
+ // (these mostly match our jshint config)
+ 'array-callback-return': 'warn',
+ 'block-scoped-var': 'warn',
+ 'complexity': 'warn',
+ 'consistent-return': 'warn',
+ 'curly': 'error',
+ 'dot-notation': 'warn',
+ 'no-alert': 'warn',
+ 'no-caller': 'error',
+ 'no-case-declarations': 'error',
+ 'no-div-regex': 'error',
+ 'no-empty-pattern': 'error',
+ 'no-empty-function': 'warn',
+ 'no-eq-null': 'error',
+ 'no-eval': 'error',
+ 'no-extend-native': 'error',
+ 'no-extra-bind': 'warn',
+ 'no-fallthrough': 'error',
+ 'no-floating-decimal': 'warn',
+ 'no-global-assign': 'warn',
+ 'no-implied-eval': 'error',
+ 'no-invalid-this': 'error',
+ 'no-iterator': 'error',
+ 'no-labels': 'error',
+ 'no-loop-func': 'error',
+ 'no-multi-spaces': 'warn',
+ 'no-multi-str': 'error',
+ 'no-new-func': 'error',
+ 'no-new-wrappers': 'error',
+ 'no-octal': 'error',
+ 'no-octal-escape': 'error',
+ 'no-proto': 'error',
+ 'no-redeclare': 'warn',
+ 'no-return-assign': 'error',
+ 'no-script-url': 'error',
+ 'no-self-assign': 'error',
+ 'no-self-compare': 'error',
+ 'no-sequences': 'warn',
+ 'no-throw-literal': 'warn',
+ 'no-unmodified-loop-condition': 'error',
+ 'no-unused-expressions': 'error',
+ 'no-unused-labels': 'error',
+ 'no-useless-call': 'warn',
+ 'no-useless-escape': 'warn',
+ 'no-with': 'error',
+ 'wrap-iife': ['error', 'any'],
+
+ // === Variables ===
+ 'no-delete-var': 'error',
+ 'no-undef': 'error',
+ 'no-undef-init': 'error',
+ 'no-unused-vars': ['error', { 'caughtErrors': 'none' }],
+
+ // === Stylistic Issues ===
+ 'array-bracket-spacing': 'warn',
+ 'block-spacing': 'warn',
+ 'brace-style': ['warn', '1tbs'],
+ 'camelcase': 'warn',
+ 'capitalized-comments': ['warn', 'always', { 'ignoreConsecutiveComments': true }],
+ 'comma-spacing': ['warn', { 'before': false, 'after': true }],
+ 'comma-style': ['warn', 'last'],
+ 'computed-property-spacing': 'error',
+ 'consistent-this': 'off',
+ 'eol-last': 'off',
+ 'func-call-spacing': ['warn', 'never'],
+ 'func-names': 'off',
+ 'func-style': 'off',
+ // indent currently not doing well with our wrapping style, so disabled.
+ 'indent': ['off', 4, { 'SwitchCase': 1 }],
+ 'key-spacing': ['warn', { 'beforeColon': false, 'afterColon': true, 'mode': minimum }],
+ 'keyword-spacing': 'warn',
+ 'linebreak-style': ['error', 'unix'],
+ 'lines-around-comment': 'off',
+ 'max-len': ['error', 132],
+ 'max-lines': 'off',
+ 'max-depth': 'warn',
+ 'max-nested-callbacks': ['warn', 5],
+ 'max-params': 'off',
+ 'max-statements': 'off',
+ 'max-statements-per-line': ['warn', { max: 2 }],
+ 'new-cap': ['warn', { 'properties': false }],
+ 'new-parens': 'warn',
+ 'newline-after-var': 'off',
+ 'newline-before-return': 'off',
+ 'newline-per-chained-call': 'off',
+ 'no-array-constructor': 'off',
+ 'no-bitwise': 'error',
+ 'no-continue': 'off',
+ 'no-inline-comments': 'off',
+ 'no-lonely-if': 'off',
+ 'no-mixed-operators': 'off',
+ 'no-mixed-spaces-and-tabs': 'error',
+ 'no-multiple-empty-lines': 'warn',
+ 'no-negated-condition': 'off',
+ 'no-nested-ternary': 'warn',
+ 'no-new-object': 'off',
+ 'no-plusplus': 'off',
+ 'no-tabs': 'error',
+ 'no-ternary': 'off',
+ 'no-trailing-spaces': 'error',
+ 'no-underscore-dangle': 'off',
+ 'no-unneeded-ternary': 'off',
+ 'no-whitespace-before-property': 'warn',
+ 'object-curly-newline': 'off',
+ 'object-curly-spacing': 'warn',
+ 'object-property-newline': 'off',
+ 'one-var': 'off',
+ 'one-var-declaration-per-line': ['warn', 'initializations'],
+ 'operator-assignment': 'off',
+ 'operator-linebreak': 'off',
+ 'padded-blocks': 'off',
+ 'quote-props': ['warn', 'as-needed', {'unnecessary': false, 'keywords': true, 'numbers': true}],
+ 'quotes': 'off',
+ 'require-jsdoc': 'warn',
+ 'semi': 'error',
+ 'semi-spacing': ['warn', {'before': false, 'after': true}],
+ 'sort-vars': 'off',
+ 'space-before-blocks': 'warn',
+ 'space-before-function-paren': ['warn', 'never'],
+ 'space-in-parens': 'warn',
+ 'space-infix-ops': 'warn',
+ 'space-unary-ops': 'warn',
+ 'spaced-comment': 'warn',
+ 'unicode-bom': 'error',
+ 'wrap-regex': 'off',
+
+ // === Promises ===
+ 'promise/always-return': 'warn',
+ 'promise/no-return-wrap': 'warn',
+ 'promise/param-names': 'warn',
+ 'promise/catch-or-return': ['warn', {terminationMethod: ['catch', 'fail']}],
+ 'promise/no-native': 'warn',
+ 'promise/no-promise-in-callback': 'warn',
+ 'promise/no-callback-in-promise': 'warn',
+ 'promise/avoid-new': 'warn',
+
+ // === Deprecations ===
+ "no-restricted-properties": ['warn', {
+ 'object': 'M',
+ 'property': 'str',
+ 'message': 'Use AMD module "core/str" or M.util.get_string()'
+ }],
+
+ },
+ overrides: [
+ {
+ files: ["**/yui/src/**/*.js"],
+ // Disable some rules which we can't safely define for YUI rollups.
+ rules: {
+ 'no-undef': 'off',
+ 'no-unused-vars': 'off',
+ 'no-unused-expressions': 'off'
+ }
+ },
+ {
+ files: ["**/amd/src/*.js"],
+ // Check AMD with some slightly stricter rules.
+ rules: {
+ 'no-unused-vars': 'error',
+ 'no-implicit-globals': 'error'
+ }
+ }
+ ]
+}
diff --git a/.travis.yml b/.travis.yml
index ec7f53c..7ee6426 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -18,7 +18,6 @@ cache:
php:
# PHP 5.6 gives errors because of the provider.php needs to be PHP7
- - 7.0
- 7.1
env:
diff --git a/amd/build/canvas.min.js b/amd/build/canvas.min.js
index 5f9f71e..f501cdd 100644
--- a/amd/build/canvas.min.js
+++ b/amd/build/canvas.min.js
@@ -1 +1 @@
-define(["jquery","core/notification"],function(a,b){"use strict";var c={id:0,debugjs:!1,hasHorizontalRuler:!0,background:""},d=function(a){var b,d;for(b in c)c.hasOwnProperty(b)&&a.hasOwnProperty(b)&&(d=typeof c[b],"boolean"===d?c[b]=Boolean(a[b]):"number"===d?c[b]=Number(a[b]):"string"===d&&(c[b]=String(a[b])))},e={},f=0,g=0,h=!0,i=function(a){if(a)for(var b in console)"function"==typeof console[b]&&(e[b]=console[b].bind(window.console));else for(var b in console)"function"==typeof console[b]&&(e[b]=function(){})},j=null,k={canvasWidth:800,canvasHeight:500,defaultShaperect:{width:70,height:70,left:200,top:50,angle:0,fill:"#ffb628"},defaultShapecircle:{radius:40,left:200,top:50,fill:"#b3cc2b"},defaultShapetriangle:{top:50,left:200,width:70,height:70,fill:"#0081b4"},defaultShapetextbox:{top:50,left:200,fill:"#0081b4"},loadHistory:function(){a.ajax({type:"POST",url:M.cfg.wwwroot+"/mod/gcanvas/ajax.php",data:{sesskey:M.cfg.sesskey,action:"load_history",data:{id:c.id}},dataType:"json",success:function(b){e.log(b),b.success&&a("#history").html(b.html)},error:function(a){e.error(a.responseText),b.addNotification({message:a.responseText,type:"error"})}})},saveCanvasAjax:function(){fabric.Canvas.supports("toDataURL")?a.ajax({type:"POST",url:M.cfg.wwwroot+"/mod/gcanvas/ajax.php",data:{sesskey:M.cfg.sesskey,action:"save_canvas",data:{id:c.id,status:"final",canvas_data:j.toDataURL({multiplier:1,format:"png"}),json_data:JSON.stringify(j)}},dataType:"json",success:function(a){e.log(a),a.success?(b.addNotification({message:M.util.get_string("javascript:updated","mod_gcanvas"),type:"success"}),k.loadHistory()):b.addNotification({message:a.error,type:"error"})},error:function(a){e.error(a.responseText),b.addNotification({message:a.responseText,type:"error"})}}):b.addNotification({message:"This browser doesn't provide means to serialize canvas to an image",type:"error"})},deleteSelectedCanvasItems:function(){try{var a=j.getActiveObjects();if(a.length){for(var b in a)if(a.hasOwnProperty(b)){var c=a[b];if(void 0!==c.id&&"ruler"===c.id){e.log("Ruler: Not removable!");continue}j.remove(c)}j.discardActiveObject().renderAll()}else e.log("Selection empty")}catch(d){e.error("Nothing selected",d)}},loadDynamicToolbarMappingShapes:function(){a("#toolbar .icon[data-element-type]").on("click",function(){var b,c=a(this).data("element-type");try{j.discardActiveObject()}catch(d){}var f="defaultShape"+c.toLowerCase();e.log("Search for shape: "+f),k.hasOwnProperty(f)?(e.log("Shape found"),b="Textbox"===c?new fabric[c]("DEMO",k[f]):new fabric[c](k[f]),j.add(b),j.setActiveObject(b)):e.error("Shape not found!"),j.renderAll()})},loadColorPicker:function(){a("#colorpicker").spectrum({showPalette:!0,palette:[],showSelectionPalette:!0,selectionPalette:["red","green","blue","orange"],flat:!1,change:function(a){e.log("change color"),k.setColor(a)}}).on("dragstart.spectrum , dragstop.spectrum",function(a,b){e.log("change color - dragstop - dragstart"),k.setColor(b)})},loadEmojiCsv:function(a){e.log("loadEmojiCsv : ",a),fabric.Image.fromURL(a.replace(".png",".svg"),function(a){a.set({height:500,width:500,left:150,top:100,angle:0,centerTransform:!0}).scale(.4).setCoords(),j.add(a),j.setActiveObject(a)})},deleteAttempt:function(d){e.log("Delete",d),b.confirm(M.util.get_string("javascript:confirm_title","mod_gcanvas"),M.util.get_string("javascript:confirm_desc","mod_gcanvas"),M.util.get_string("javascript:yes","mod_gcanvas"),M.util.get_string("javascript:no","mod_gcanvas"),function(){a.ajax({type:"POST",url:M.cfg.wwwroot+"/mod/gcanvas/ajax.php",data:{sesskey:M.cfg.sesskey,action:"delete_attempt",data:{id:c.id,attempt_id:d.data("id")}},dataType:"json",success:function(a){e.log(a),a.success?k.loadHistory():b.addNotification({message:a.error,type:"error"})},error:function(a){e.error(a.responseText),b.addNotification({message:a.responseText,type:"error"})}})})},restoreAttempt:function(b){e.log("Restore",b),a.ajax({type:"POST",url:M.cfg.wwwroot+"/mod/gcanvas/ajax.php",data:{sesskey:M.cfg.sesskey,action:"get_attempt",data:{id:c.id,attempt_id:b.data("id")}},dataType:"json",success:function(a){e.log(a),a.success&&(h=!1,j.loadFromJSON(a.record.json_data,j.renderAll.bind(j)),setTimeout(function(){h=!0},1e3))}})},showFileuploader:function(b){a("#canvas-filepicker-form-"+b).toggle()},setBackgroundImage:function(){""!==c.background&&fabric.Image.fromURL(c.background,function(a){j.setBackgroundImage(a,j.renderAll.bind(j),{scaleX:j.width/a.width,scaleY:j.height/a.height})})},addUserImage:function(){var b={id:c.id},d=a("#canvas-filepicker-form-student_image form").serializeArray();a.each(d,function(a,c){b[c.name]=c.value}),a.ajax({type:"POST",url:M.cfg.wwwroot+"/mod/gcanvas/ajax.php",data:{sesskey:M.cfg.sesskey,action:"upload_images",data:b},dataType:"json",success:function(b){e.log(b),b.success&&k.addImageFromUrl(b.image),a("#canvas-filepicker-form-student_image").hide()}})},addImageFromUrl:function(a){fabric.Image.fromURL(a,function(a){a.set({left:150,top:100,angle:0,centerTransform:!0}).setCoords();var b=j.getWidth()/3;a.width>b&&a.scaleToWidth(b),j.add(a),j.setActiveObject(a)})},selectToolbarImage:function(){var b=a("#image-picker");return b.is(":visible")?void b.hide():(b.show(),void a.ajax({type:"POST",url:M.cfg.wwwroot+"/mod/gcanvas/ajax.php",data:{sesskey:M.cfg.sesskey,action:"get_toolbar_images",data:{id:c.id}},dataType:"json",success:function(c){if(e.log(c),c.success){var d='
';a.each(c.images,function(a,b){d+=''}),d+="
",b.html(d)}}}))},undo:function(){if(0!==f)try{var a=localStorage.getItem("buffer_"+f);j.loadFromJSON(a,j.renderAll.bind(j)),localStorage.removeItem("buffer_"+f),f--}catch(b){e.log(b)}},loadToolbar:function(){this.setBackgroundImage(),this.loadDynamicToolbarMappingShapes(),this.loadColorPicker(),a("#clear").on("click",function(){j.clear(),c.hasHorizontalRuler&&k.addHorizontalRuler(),k.setBackgroundImage()}),a("#arrow i").on("click",function(){k.loadArrowToCanvas()}),a("#trash i").on("click",function(){k.deleteSelectedCanvasItems()}),a("#smiley i").on("click",function(){k.loadEmojiPicker()}),a("#undo").on("click",function(){h=!1,k.undo(),setTimeout(function(){h=!0},500)}),a("#add-image i").on("click",function(){k.showFileuploader("student_image")}),a("#select-a-image i").on("click",function(){k.selectToolbarImage()}),a("#image-picker ").on("click","img",function(){k.addImageFromUrl(a(this).attr("src")),a("#image-picker").hide()}),a("#save-canvas").on("click",function(){k.saveCanvasAjax()}),a("#show-help").on("click",function(){a("#dialog-help").show()}),a("#dialog-help").on("click",function(){a("#dialog-help").hide()}),a("#history").on("click",".delete",function(b){b.preventDefault(),k.deleteAttempt(a(this))}).on("click",".restore",function(b){b.preventDefault(),k.restoreAttempt(a(this))}),a("#emoji-picker").on("click","img",function(){k.loadEmojiCsv(a(this).attr("src")),a("#emoji-picker").hide()}),a("#change_background").on("click",function(){k.showFileuploader("background")}),a("#add_toolbar_images").on("click",function(){k.showFileuploader("toolbar_shape")}),a("#canvas-filepicker-form-student_image").on("click","#id_submitbutton",function(a){a.preventDefault(),k.addUserImage()}),a(".dialog").on("click",".btn-secondary",function(b){b.preventDefault(),e.log("Cancel"),a(".dialog").hide()})},loadEmojiPicker:function(){var b=a("#emoji-picker");return""!==b.html()?(e.log("Toggle emoji"),void b.toggle()):void a.ajax({type:"POST",url:M.cfg.wwwroot+"/mod/gcanvas/ajax.php",data:{sesskey:M.cfg.sesskey,action:"emoji",data:{id:c.id}},dataType:"json",success:function(a){e.log(a),a.success&&b.html(a.html).show()}})},loadArrowToCanvas:function(){fabric.loadSVGFromURL("pix/arrow.svg",function(a,b){var c=fabric.util.groupSVGElements(a,b);j.add(c.scale(.1)).centerObject(c).renderAll(),c.setCoords(),j.setActiveObject(c)})},setColor:function(a){var b=a.toHexString(),c=j.getActiveObjects();if(c){for(var d in c)if(c.hasOwnProperty(d)){var f=c[d];if(f.hasOwnProperty("id")&&"ruler"===f.id)continue;f.set("fill",b)}j.renderAll()}else e.log("No active items")},preventMovingOutOfCanvas:function(){j.on("object:moving",function(a){var b=a.target;b.currentHeight>b.canvas.height||b.currentWidth>b.canvas.width||(b.setCoords(),(b.getBoundingRect().top<0||b.getBoundingRect().left<0)&&(b.top=Math.max(b.top,b.top-b.getBoundingRect().top),b.left=Math.max(b.left,b.left-b.getBoundingRect().left)),(b.getBoundingRect().top+b.getBoundingRect().height>b.canvas.height||b.getBoundingRect().left+b.getBoundingRect().width>b.canvas.width)&&(b.top=Math.min(b.top,b.canvas.height-b.getBoundingRect().height+b.top-b.getBoundingRect().top),b.left=Math.min(b.left,b.canvas.width-b.getBoundingRect().width+b.left-b.getBoundingRect().left)))})},keyboardActions:function(){a(document).keydown(function(a){switch(e.log("keypress",a.which),a.which){case 46:k.deleteSelectedCanvasItems()}})},init:function(){this.__canvas=j=new fabric.Canvas("sketch"),a("body").on("contextmenu","canvas , img",function(){return!1}),j.setHeight(this.canvasHeight),j.setWidth(this.canvasWidth),j.on({"selection:created":this.onchange,"selection:updated":this.onchange,"object:added":this.addToCache,"object:removed":this.addToCache,"object:modified":this.addToCache}),localStorage.clear(),this.preventMovingOutOfCanvas(),this.loadToolbar(),c.hasHorizontalRuler&&this.addHorizontalRuler(),this.loadHistory(),this.keyboardActions()},addToCache:function(){e.log("history"),k.addCanvasToCacheBuffer()},addCanvasToCacheBuffer:function(){h&&(clearTimeout(g),setTimeout(function(){try{f++,localStorage.setItem("buffer_"+f,JSON.stringify(j))}catch(a){e.log(a)}},500))},addHorizontalRuler:function(){var b=new fabric.Rect({width:this.canvasWidth,height:2,id:"ruler",left:0,top:410,angle:0,fill:"#8b58a1"});b.flipY=!1,b.lockMovementX=!0,b.lockScalingX=!0,b.lockScalingY=!0,b.lockUniScaling=!0,b.lockRotation=!0,j.add(b),j.renderAll(),a(document).keydown(function(a){switch(a.which){case 38:b.top=b.top-10,j.renderAll();break;case 40:b.top=b.top+10,j.renderAll();break;default:return}a.preventDefault()})},onchange:function(b){b.target.hasOwnProperty("id")&&"ruler"===b.target.id||a("#colorpicker").spectrum("set",b.target.fill)}};return{initialise:function(b){a.getScript(M.cfg.wwwroot+"/mod/gcanvas/javascript/spectrum.js").done(function(){d(b),i(c.debugjs),a.noConflict(),a(document).ready(function(){e.log("Canvas Module v1.2"),k.init()})}).fail(function(a,b,c){e.log(a),e.log(b),e.log(c)})}}});
\ No newline at end of file
+define(["jquery","core/notification"],function(a,b){"use strict";var c={id:0,debugjs:!1,hasHorizontalRuler:!0,background:""},d=function(a){var b,d;for(b in c)c.hasOwnProperty(b)&&a.hasOwnProperty(b)&&(d=typeof c[b],"boolean"===d?c[b]=Boolean(a[b]):"number"===d?c[b]=Number(a[b]):"string"===d&&(c[b]=String(a[b])))},e={},f=0,g=0,h=!0,i=function(a){if(a)for(var b in console)"function"==typeof console[b]&&(e[b]=console[b].bind(window.console));else for(var c in console)"function"==typeof console[c]&&(e[c]=function(){})},j=null,k={canvasWidth:800,canvasHeight:500,defaultShaperect:{width:70,height:70,left:200,top:50,angle:0,fill:"#ffb628"},defaultShapecircle:{radius:40,left:200,top:50,fill:"#b3cc2b"},defaultShapetriangle:{top:50,left:200,width:70,height:70,fill:"#0081b4"},defaultShapetextbox:{top:50,left:200,fill:"#0081b4"},loadHistory:function(){a.ajax({type:"POST",url:M.cfg.wwwroot+"/mod/gcanvas/ajax.php",data:{sesskey:M.cfg.sesskey,action:"load_history",data:{id:c.id}},dataType:"json",success:function(b){e.log(b),b.success&&a("#history").html(b.html)},error:function(a){e.error(a.responseText),b.addNotification({message:a.responseText,type:"error"})}})},saveCanvasAjax:function(){fabric.Canvas.supports("toDataURL")?a.ajax({type:"POST",url:M.cfg.wwwroot+"/mod/gcanvas/ajax.php",data:{sesskey:M.cfg.sesskey,action:"save_canvas",data:{id:c.id,status:"final",canvas_data:j.toDataURL({multiplier:1,format:"png"}),json_data:JSON.stringify(j)}},dataType:"json",success:function(a){e.log(a),a.success?(b.addNotification({message:M.util.get_string("javascript:updated","mod_gcanvas"),type:"success"}),k.loadHistory()):b.addNotification({message:a.error,type:"error"})},error:function(a){e.error(a.responseText),b.addNotification({message:a.responseText,type:"error"})}}):b.addNotification({message:"This browser doesn't provide means to serialize canvas to an image",type:"error"})},deleteSelectedCanvasItems:function(){try{var a=j.getActiveObjects();if(a.length<=0)return void e.log("Selection empty");for(var b in a)if(a.hasOwnProperty(b)){var c=a[b];if(void 0!==c.id&&"ruler"===c.id){e.log("Ruler: Not removable!");continue}j.remove(c)}j.discardActiveObject().renderAll()}catch(d){e.error("Nothing selected",d)}},loadDynamicToolbarMappingShapes:function(){a("#toolbar .icon[data-element-type]").on("click",function(){var b,c=a(this).data("element-type");try{j.discardActiveObject()}catch(d){}var f="defaultShape"+c.toLowerCase();e.log("Search for shape: "+f),k.hasOwnProperty(f)?(e.log("Shape found"),b="Textbox"===c?new fabric[c]("DEMO",k[f]):new fabric[c](k[f]),j.add(b),j.setActiveObject(b)):e.error("Shape not found!"),j.renderAll()})},loadColorPicker:function(){a("#colorpicker").spectrum({showPalette:!0,palette:[],showSelectionPalette:!0,selectionPalette:["red","green","blue","orange"],flat:!1,change:function(a){e.log("change color"),k.setColor(a)}}).on("dragstart.spectrum , dragstop.spectrum",function(a,b){e.log("change color - dragstop - dragstart"),k.setColor(b)})},loadEmojiCsv:function(a){e.log("loadEmojiCsv : ",a),fabric.Image.fromURL(a.replace(".png",".svg"),function(a){a.set({height:500,width:500,left:150,top:100,angle:0,centerTransform:!0}).scale(.4).setCoords(),j.add(a),j.setActiveObject(a)})},deleteAttempt:function(d){e.log("Delete",d),b.confirm(M.util.get_string("javascript:confirm_title","mod_gcanvas"),M.util.get_string("javascript:confirm_desc","mod_gcanvas"),M.util.get_string("javascript:yes","mod_gcanvas"),M.util.get_string("javascript:no","mod_gcanvas"),function(){a.ajax({type:"POST",url:M.cfg.wwwroot+"/mod/gcanvas/ajax.php",data:{sesskey:M.cfg.sesskey,action:"delete_attempt",data:{id:c.id,attempt_id:d.data("id")}},dataType:"json",success:function(a){e.log(a),a.success?k.loadHistory():b.addNotification({message:a.error,type:"error"})},error:function(a){e.error(a.responseText),b.addNotification({message:a.responseText,type:"error"})}})})},restoreAttempt:function(b){e.log("Restore",b),a.ajax({type:"POST",url:M.cfg.wwwroot+"/mod/gcanvas/ajax.php",data:{sesskey:M.cfg.sesskey,action:"get_attempt",data:{id:c.id,attempt_id:b.data("id")}},dataType:"json",success:function(a){e.log(a),a.success&&(h=!1,j.loadFromJSON(a.record.json_data,j.renderAll.bind(j)),setTimeout(function(){h=!0},1e3))}})},showFileuploader:function(b){a("#canvas-filepicker-form-"+b).toggle()},setBackgroundImage:function(){""!==c.background&&fabric.Image.fromURL(c.background,function(a){j.setBackgroundImage(a,j.renderAll.bind(j),{scaleX:j.width/a.width,scaleY:j.height/a.height})})},addUserImage:function(){var b={id:c.id},d=a("#canvas-filepicker-form-student_image form").serializeArray();a.each(d,function(a,c){b[c.name]=c.value}),a.ajax({type:"POST",url:M.cfg.wwwroot+"/mod/gcanvas/ajax.php",data:{sesskey:M.cfg.sesskey,action:"upload_images",data:b},dataType:"json",success:function(b){e.log(b),b.success&&k.addImageFromUrl(b.image),a("#canvas-filepicker-form-student_image").hide()}})},addImageFromUrl:function(a){fabric.Image.fromURL(a,function(a){a.set({left:150,top:100,angle:0,centerTransform:!0}).setCoords();var b=j.getWidth()/3;a.width>b&&a.scaleToWidth(b),j.add(a),j.setActiveObject(a)})},selectToolbarImage:function(){var b=a("#image-picker");return b.is(":visible")?void b.hide():(b.show(),void a.ajax({type:"POST",url:M.cfg.wwwroot+"/mod/gcanvas/ajax.php",data:{sesskey:M.cfg.sesskey,action:"get_toolbar_images",data:{id:c.id}},dataType:"json",success:function(c){if(e.log(c),c.success){var d='';a.each(c.images,function(a,b){d+=''}),d+="
",b.html(d)}}}))},undo:function(){if(0!==f)try{var a=localStorage.getItem("buffer_"+f);j.loadFromJSON(a,j.renderAll.bind(j)),localStorage.removeItem("buffer_"+f),f--}catch(b){e.log(b)}},loadToolbar:function(){this.setBackgroundImage(),this.loadDynamicToolbarMappingShapes(),this.loadColorPicker(),a("#clear").on("click",function(){j.clear(),c.hasHorizontalRuler&&k.addHorizontalRuler(),k.setBackgroundImage()}),a("#arrow i").on("click",function(){k.loadArrowToCanvas()}),a("#trash i").on("click",function(){k.deleteSelectedCanvasItems()}),a("#smiley i").on("click",function(){k.loadEmojiPicker()}),a("#undo").on("click",function(){h=!1,k.undo(),setTimeout(function(){h=!0},500)}),a("#add-image i").on("click",function(){k.showFileuploader("student_image")}),a("#select-a-image i").on("click",function(){k.selectToolbarImage()}),a("#image-picker ").on("click","img",function(){k.addImageFromUrl(a(this).attr("src")),a("#image-picker").hide()}),a("#save-canvas").on("click",function(){k.saveCanvasAjax()}),a("#show-help").on("click",function(){a("#dialog-help").show()}),a("#dialog-help").on("click",function(){a("#dialog-help").hide()}),a("#history").on("click",".delete",function(b){b.preventDefault(),k.deleteAttempt(a(this))}).on("click",".restore",function(b){b.preventDefault(),k.restoreAttempt(a(this))}),a("#emoji-picker").on("click","img",function(){k.loadEmojiCsv(a(this).attr("src")),a("#emoji-picker").hide()}),a("#change_background").on("click",function(){k.showFileuploader("background")}),a("#add_toolbar_images").on("click",function(){k.showFileuploader("toolbar_shape")}),a("#canvas-filepicker-form-student_image").on("click","#id_submitbutton",function(a){a.preventDefault(),k.addUserImage()}),a(".dialog").on("click",".btn-secondary",function(b){b.preventDefault(),e.log("Cancel"),a(".dialog").hide()})},loadEmojiPicker:function(){var b=a("#emoji-picker");return""!==b.html()?(e.log("Toggle emoji"),void b.toggle()):void a.ajax({type:"POST",url:M.cfg.wwwroot+"/mod/gcanvas/ajax.php",data:{sesskey:M.cfg.sesskey,action:"emoji",data:{id:c.id}},dataType:"json",success:function(a){e.log(a),a.success&&b.html(a.html).show()}})},loadArrowToCanvas:function(){fabric.loadSVGFromURL("pix/arrow.svg",function(a,b){var c=fabric.util.groupSVGElements(a,b);j.add(c.scale(.1)).centerObject(c).renderAll(),c.setCoords(),j.setActiveObject(c)})},setColor:function(a){var b=a.toHexString(),c=j.getActiveObjects();if(c){for(var d in c)if(c.hasOwnProperty(d)){var f=c[d];if(f.hasOwnProperty("id")&&"ruler"===f.id)continue;f.set("fill",b)}j.renderAll()}else e.log("No active items")},preventMovingOutOfCanvas:function(){j.on("object:moving",function(a){var b=a.target;b.currentHeight>b.canvas.height||b.currentWidth>b.canvas.width||(b.setCoords(),(b.getBoundingRect().top<0||b.getBoundingRect().left<0)&&(b.top=Math.max(b.top,b.top-b.getBoundingRect().top),b.left=Math.max(b.left,b.left-b.getBoundingRect().left)),(b.getBoundingRect().top+b.getBoundingRect().height>b.canvas.height||b.getBoundingRect().left+b.getBoundingRect().width>b.canvas.width)&&(b.top=Math.min(b.top,b.canvas.height-b.getBoundingRect().height+b.top-b.getBoundingRect().top),b.left=Math.min(b.left,b.canvas.width-b.getBoundingRect().width+b.left-b.getBoundingRect().left)))})},keyboardActions:function(){a(document).keydown(function(a){switch(e.log("keypress",a.which),a.which){case 46:k.deleteSelectedCanvasItems()}})},init:function(){this.__canvas=j=new fabric.Canvas("sketch"),a("body").on("contextmenu","canvas , img",function(){return!1}),j.setHeight(this.canvasHeight),j.setWidth(this.canvasWidth),j.on({"selection:created":this.onchange,"selection:updated":this.onchange,"object:added":this.addToCache,"object:removed":this.addToCache,"object:modified":this.addToCache}),localStorage.clear(),this.preventMovingOutOfCanvas(),this.loadToolbar(),c.hasHorizontalRuler&&this.addHorizontalRuler(),this.loadHistory(),this.keyboardActions()},addToCache:function(){e.log("history"),k.addCanvasToCacheBuffer()},addCanvasToCacheBuffer:function(){h&&(clearTimeout(g),setTimeout(function(){try{f++,localStorage.setItem("buffer_"+f,JSON.stringify(j))}catch(a){e.log(a)}},500))},addHorizontalRuler:function(){var b=new fabric.Rect({width:this.canvasWidth,height:2,id:"ruler",left:0,top:410,angle:0,fill:"#8b58a1"});b.flipY=!1,b.lockMovementX=!0,b.lockScalingX=!0,b.lockScalingY=!0,b.lockUniScaling=!0,b.lockRotation=!0,j.add(b),j.renderAll(),a(document).keydown(function(a){switch(a.which){case 38:b.top=b.top-10,j.renderAll();break;case 40:b.top=b.top+10,j.renderAll();break;default:return}a.preventDefault()})},onchange:function(b){b.target.hasOwnProperty("id")&&"ruler"===b.target.id||a("#colorpicker").spectrum("set",b.target.fill)}};return{initialise:function(b){a.getScript(M.cfg.wwwroot+"/mod/gcanvas/javascript/spectrum.js").done(function(){d(b),i(c.debugjs),a.noConflict(),a(document).ready(function(){e.log("Canvas Module v1.2"),k.init()})}).fail(function(a,b,c){e.log(a),e.log(b),e.log(c)})}}});
\ No newline at end of file
diff --git a/amd/src/canvas.js b/amd/src/canvas.js
index 1af823e..532c49c 100644
--- a/amd/src/canvas.js
+++ b/amd/src/canvas.js
@@ -102,9 +102,9 @@ define(['jquery', 'core/notification'], function($, notification) {
}
} else {
// Fake wrapper.
- for (var m in console) {
- if (typeof console[m] == 'function') {
- debug[m] = function() {
+ for (var i in console) {
+ if (typeof console[i] == 'function') {
+ debug[i] = function() {
// Don't do anything.
};
}
@@ -277,26 +277,26 @@ define(['jquery', 'core/notification'], function($, notification) {
deleteSelectedCanvasItems: function() {
try {
var activeobjects = canvas.getActiveObjects();
- if (activeobjects.length) {
-
- for (var i in activeobjects) {
- if (activeobjects.hasOwnProperty(i)) {
- var element = activeobjects[i];
+ if (activeobjects.length <= 0) {
+ debug.log('Selection empty');
+ return;
+ }
- if (element.id !== undefined && element.id === 'ruler') {
- debug.log('Ruler: Not removable!');
- continue;
- }
+ for (var i in activeobjects) {
+ if (activeobjects.hasOwnProperty(i)) {
+ var element = activeobjects[i];
- canvas.remove(element);
+ if (element.id !== undefined && element.id === 'ruler') {
+ debug.log('Ruler: Not removable!');
+ continue;
}
- }
- canvas.discardActiveObject().renderAll();
- } else {
- debug.log('Selection empty');
+ canvas.remove(element);
+ }
}
+ canvas.discardActiveObject().renderAll();
+
} catch (e) {
debug.error('Nothing selected', e);
}
@@ -499,7 +499,8 @@ define(['jquery', 'core/notification'], function($, notification) {
* Add user image.
*/
addUserImage: function() {
- var formdata = {'id': opts.id}, inputs = $('#canvas-filepicker-form-student_image form').serializeArray();
+ var formdata = {'id': opts.id},
+ inputs = $('#canvas-filepicker-form-student_image form').serializeArray();
$.each(inputs, function(i, input) {
formdata[input.name] = input.value;
@@ -854,9 +855,6 @@ define(['jquery', 'core/notification'], function($, notification) {
return false;
});
- // fabric.Object.prototype.transparentCorners = false;
- // fabric.Object.prototype.originX = fabric.Object.prototype.originY = 'center';
-
// Dimensions.
canvas.setHeight(this.canvasHeight);
canvas.setWidth(this.canvasWidth);
diff --git a/version.php b/version.php
index 3aa0c81..90c03d0 100644
--- a/version.php
+++ b/version.php
@@ -25,7 +25,7 @@
defined('MOODLE_INTERNAL') || die();
$plugin->component = 'mod_gcanvas';
-$plugin->release = '1.0.6';
-$plugin->version = 2019051300;
+$plugin->release = '3.5.7';
+$plugin->version = 2019061000;
$plugin->requires = 2018051700;
$plugin->maturity = MATURITY_ALPHA;
\ No newline at end of file