YUI.add('moodle-assignfeedback_editpdf-editor', function (Y, NAME) { // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . /* eslint-disable no-unused-vars */ /** * A list of globals used by this module. * * @module moodle-assignfeedback_editpdf-editor */ var AJAXBASE = M.cfg.wwwroot + '/mod/assign/feedback/editpdf/ajax.php', AJAXBASEPROGRESS = M.cfg.wwwroot + '/mod/assign/feedback/editpdf/ajax_progress.php', CSS = { DIALOGUE: 'assignfeedback_editpdf_widget' }, SELECTOR = { PREVIOUSBUTTON: '.navigate-previous-button', NEXTBUTTON: ' .navigate-next-button', SEARCHCOMMENTSBUTTON: '.searchcommentsbutton', SEARCHFILTER: '.assignfeedback_editpdf_commentsearch input', SEARCHCOMMENTSLIST: '.assignfeedback_editpdf_commentsearch ul', PAGESELECT: '.navigate-page-select', LOADINGICON: '.loading', PROGRESSBARCONTAINER: '.progress-info.progress-striped', DRAWINGREGION: '.drawingregion', DRAWINGCANVAS: '.drawingcanvas', SAVE: '.savebutton', COMMENTCOLOURBUTTON: '.commentcolourbutton', COMMENTMENU: '.commentdrawable a', ANNOTATIONCOLOURBUTTON: '.annotationcolourbutton', DELETEANNOTATIONBUTTON: '.deleteannotationbutton', UNSAVEDCHANGESDIV: '.assignfeedback_editpdf_unsavedchanges', UNSAVEDCHANGESINPUT: 'input[name="assignfeedback_editpdf_haschanges"]', STAMPSBUTTON: '.currentstampbutton', DIALOGUE: '.' + CSS.DIALOGUE }, SELECTEDBORDERCOLOUR = 'rgba(200, 200, 255, 0.9)', SELECTEDFILLCOLOUR = 'rgba(200, 200, 255, 0.5)', COMMENTTEXTCOLOUR = 'rgb(51, 51, 51)', COMMENTCOLOUR = { 'white': 'rgb(255,255,255)', 'yellow': 'rgb(255,236,174)', 'red': 'rgb(249,181,179)', 'green': 'rgb(214,234,178)', 'blue': 'rgb(203,217,237)', 'clear': 'rgba(255,255,255, 0)' }, ANNOTATIONCOLOUR = { 'white': 'rgb(255,255,255)', 'yellow': 'rgb(255,207,53)', 'red': 'rgb(239,69,64)', 'green': 'rgb(152,202,62)', 'blue': 'rgb(125,159,211)', 'black': 'rgb(51,51,51)' }, CLICKTIMEOUT = 300, TOOLSELECTOR = { 'comment': '.commentbutton', 'pen': '.penbutton', 'line': '.linebutton', 'rectangle': '.rectanglebutton', 'oval': '.ovalbutton', 'stamp': '.stampbutton', 'select': '.selectbutton', 'drag': '.dragbutton', 'highlight': '.highlightbutton' }, STROKEWEIGHT = 4; // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . /** * Provides an in browser PDF editor. * * @module moodle-assignfeedback_editpdf-editor */ /** * Class representing a 2d point. * * @namespace M.assignfeedback_editpdf * @param Number x * @param Number y * @class point */ var POINT = function(x, y) { /** * X coordinate. * @property x * @type int * @public */ this.x = parseInt(x, 10); /** * Y coordinate. * @property y * @type int * @public */ this.y = parseInt(y, 10); /** * Clip this point to the rect * @method clip * @param M.assignfeedback_editpdf.point * @public */ this.clip = function(bounds) { if (this.x < bounds.x) { this.x = bounds.x; } if (this.x > (bounds.x + bounds.width)) { this.x = bounds.x + bounds.width; } if (this.y < bounds.y) { this.y = bounds.y; } if (this.y > (bounds.y + bounds.height)) { this.y = bounds.y + bounds.height; } // For chaining. return this; }; }; M.assignfeedback_editpdf = M.assignfeedback_editpdf || {}; M.assignfeedback_editpdf.point = POINT; // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . /** * Provides an in browser PDF editor. * * @module moodle-assignfeedback_editpdf-editor */ /** * Class representing a 2d rect. * * @namespace M.assignfeedback_editpdf * @param int x * @param int y * @param int width * @param int height * @class rect */ var RECT = function(x, y, width, height) { /** * X coordinate. * @property x * @type int * @public */ this.x = x; /** * Y coordinate. * @property y * @type int * @public */ this.y = y; /** * Width * @property width * @type int * @public */ this.width = width; /** * Height * @property height * @type int * @public */ this.height = height; /** * Set this rect to represent the smallest possible rectangle containing this list of points. * @method bounds * @param M.assignfeedback_editpdf.point[] * @public */ this.bound = function(points) { var minx = 0, maxx = 0, miny = 0, maxy = 0, i = 0, point; for (i = 0; i < points.length; i++) { point = points[i]; if (point.x < minx || i === 0) { minx = point.x; } if (point.x > maxx || i === 0) { maxx = point.x; } if (point.y < miny || i === 0) { miny = point.y; } if (point.y > maxy || i === 0) { maxy = point.y; } } this.x = minx; this.y = miny; this.width = maxx - minx; this.height = maxy - miny; // Allow chaining. return this; }; /** * Checks if rect has min width. * @method has_min_width * @return bool true if width is more than 5px. * @public */ this.has_min_width = function() { return (this.width >= 5); }; /** * Checks if rect has min height. * @method has_min_height * @return bool true if height is more than 5px. * @public */ this.has_min_height = function() { return (this.height >= 5); }; /** * Set min. width of annotation bound. * @method set_min_width * @public */ this.set_min_width = function() { this.width = 5; }; /** * Set min. height of annotation bound. * @method set_min_height * @public */ this.set_min_height = function() { this.height = 5; }; }; M.assignfeedback_editpdf = M.assignfeedback_editpdf || {}; M.assignfeedback_editpdf.rect = RECT; // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . /** * Provides an in browser PDF editor. * * @module moodle-assignfeedback_editpdf-editor */ /** * EDIT * * @namespace M.assignfeedback_editpdf * @class edit */ var EDIT = function() { /** * Starting point for the edit. * @property start * @type M.assignfeedback_editpdf.point|false * @public */ this.start = false; /** * Finishing point for the edit. * @property end * @type M.assignfeedback_editpdf.point|false * @public */ this.end = false; /** * Starting time for the edit. * @property starttime * @type int * @public */ this.starttime = 0; /** * Starting point for the currently selected annotation. * @property annotationstart * @type M.assignfeedback_editpdf.point|false * @public */ this.annotationstart = false; /** * The currently selected tool * @property tool * @type String * @public */ this.tool = "drag"; /** * The currently comment colour * @property commentcolour * @type String * @public */ this.commentcolour = 'yellow'; /** * The currently annotation colour * @property annotationcolour * @type String * @public */ this.annotationcolour = 'red'; /** * The current stamp image. * @property stamp * @type String * @public */ this.stamp = ''; /** * List of points the the current drawing path. * @property path * @type M.assignfeedback_editpdf.point[] * @public */ this.path = []; }; M.assignfeedback_editpdf = M.assignfeedback_editpdf || {}; M.assignfeedback_editpdf.edit = EDIT; // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . /* global SELECTOR */ /** * Provides an in browser PDF editor. * * @module moodle-assignfeedback_editpdf-editor */ /** * Class representing a drawable thing which contains both Y.Nodes, and Y.Shapes. * * @namespace M.assignfeedback_editpdf * @param M.assignfeedback_editpdf.editor editor * @class drawable */ var DRAWABLE = function(editor) { /** * Reference to M.assignfeedback_editpdf.editor. * @property editor * @type M.assignfeedback_editpdf.editor * @public */ this.editor = editor; /** * Array of Y.Shape * @property shapes * @type Y.Shape[] * @public */ this.shapes = []; /** * Array of Y.Node * @property nodes * @type Y.Node[] * @public */ this.nodes = []; /** * Delete the shapes from the drawable. * @protected * @method erase_drawable */ this.erase = function() { if (this.shapes) { while (this.shapes.length > 0) { this.editor.graphic.removeShape(this.shapes.pop()); } } if (this.nodes) { while (this.nodes.length > 0) { this.nodes.pop().remove(); } } }; /** * Update the positions of all absolutely positioned nodes, when the drawing canvas is scrolled * @public * @method scroll_update * @param scrollx int * @param scrolly int */ this.scroll_update = function(scrollx, scrolly) { var i, x, y; for (i = 0; i < this.nodes.length; i++) { x = this.nodes[i].getData('x'); y = this.nodes[i].getData('y'); if (x !== undefined && y !== undefined) { this.nodes[i].setX(parseInt(x, 10) - scrollx); this.nodes[i].setY(parseInt(y, 10) - scrolly); } } }; /** * Store the initial position of the node, so it can be updated when the drawing canvas is scrolled * @public * @method store_position * @param container * @param x * @param y */ this.store_position = function(container, x, y) { var drawingregion, scrollx, scrolly; drawingregion = this.editor.get_dialogue_element(SELECTOR.DRAWINGREGION); scrollx = parseInt(drawingregion.get('scrollLeft'), 10); scrolly = parseInt(drawingregion.get('scrollTop'), 10); container.setData('x', x + scrollx); container.setData('y', y + scrolly); }; }; M.assignfeedback_editpdf = M.assignfeedback_editpdf || {}; M.assignfeedback_editpdf.drawable = DRAWABLE; // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . /* global STROKEWEIGHT, SELECTOR, SELECTEDBORDERCOLOUR, SELECTEDFILLCOLOUR */ /** * Provides an in browser PDF editor. * * @module moodle-assignfeedback_editpdf-editor */ /** * Class representing a highlight. * * @namespace M.assignfeedback_editpdf * @class annotation * @constructor */ var ANNOTATION = function(config) { ANNOTATION.superclass.constructor.apply(this, [config]); }; ANNOTATION.NAME = "annotation"; ANNOTATION.ATTRS = {}; Y.extend(ANNOTATION, Y.Base, { /** * Reference to M.assignfeedback_editpdf.editor. * @property editor * @type M.assignfeedback_editpdf.editor * @public */ editor: null, /** * Grade id * @property gradeid * @type Int * @public */ gradeid: 0, /** * Comment page number * @property pageno * @type Int * @public */ pageno: 0, /** * X position * @property x * @type Int * @public */ x: 0, /** * Y position * @property y * @type Int * @public */ y: 0, /** * Ending x position * @property endx * @type Int * @public */ endx: 0, /** * Ending y position * @property endy * @type Int * @public */ endy: 0, /** * Path * @property path * @type String - list of points like x1,y1:x2,y2 * @public */ path: '', /** * Tool. * @property type * @type String * @public */ type: 'rect', /** * Annotation colour. * @property colour * @type String * @public */ colour: 'red', /** * Reference to M.assignfeedback_editpdf.drawable * @property drawable * @type M.assignfeedback_editpdf.drawable * @public */ drawable: false, /** * Initialise the annotation. * * @method initializer * @return void */ initializer: function(config) { this.editor = config.editor || null; this.gradeid = parseInt(config.gradeid, 10) || 0; this.pageno = parseInt(config.pageno, 10) || 0; this.x = parseInt(config.x, 10) || 0; this.y = parseInt(config.y, 10) || 0; this.endx = parseInt(config.endx, 10) || 0; this.endy = parseInt(config.endy, 10) || 0; this.path = config.path || ''; this.type = config.type || 'rect'; this.colour = config.colour || 'red'; this.drawable = false; }, /** * Clean a comment record, returning an oject with only fields that are valid. * @public * @method clean * @return {} */ clean: function() { return { gradeid: this.gradeid, x: parseInt(this.x, 10), y: parseInt(this.y, 10), endx: parseInt(this.endx, 10), endy: parseInt(this.endy, 10), type: this.type, path: this.path, pageno: this.pageno, colour: this.colour }; }, /** * Draw a selection around this annotation if it is selected. * @public * @method draw_highlight * @return M.assignfeedback_editpdf.drawable */ draw_highlight: function() { var bounds, drawingregion = this.editor.get_dialogue_element(SELECTOR.DRAWINGREGION), offsetcanvas = this.editor.get_dialogue_element(SELECTOR.DRAWINGCANVAS).getXY(), shape; if (this.editor.currentannotation === this) { // Draw a highlight around the annotation. bounds = new M.assignfeedback_editpdf.rect(); bounds.bound([new M.assignfeedback_editpdf.point(this.x, this.y), new M.assignfeedback_editpdf.point(this.endx, this.endy)]); shape = this.editor.graphic.addShape({ type: Y.Rect, width: bounds.width, height: bounds.height, stroke: { weight: STROKEWEIGHT, color: SELECTEDBORDERCOLOUR }, fill: { color: SELECTEDFILLCOLOUR }, x: bounds.x, y: bounds.y }); this.drawable.shapes.push(shape); // Add a delete X to the annotation. var deleteicon = Y.Node.create(''), deletelink = Y.Node.create(''); deleteicon.setAttrs({ 'alt': M.util.get_string('deleteannotation', 'assignfeedback_editpdf') }); deleteicon.setStyles({ 'backgroundColor': 'white' }); deletelink.addClass('deleteannotationbutton'); deletelink.append(deleteicon); drawingregion.append(deletelink); deletelink.setData('annotation', this); deletelink.setStyle('zIndex', '200'); deletelink.on('click', this.remove, this); deletelink.on('key', this.remove, 'space,enter', this); deletelink.setX(offsetcanvas[0] + bounds.x + bounds.width - 18); deletelink.setY(offsetcanvas[1] + bounds.y + 6); this.drawable.nodes.push(deletelink); } return this.drawable; }, /** * Draw an annotation * @public * @method draw * @return M.assignfeedback_editpdf.drawable|false */ draw: function() { // Should be overridden by the subclass. this.draw_highlight(); return this.drawable; }, /** * Delete an annotation * @protected * @method remove * @param event */ remove: function(e) { var annotations, i; e.preventDefault(); annotations = this.editor.pages[this.editor.currentpage].annotations; for (i = 0; i < annotations.length; i++) { if (annotations[i] === this) { annotations.splice(i, 1); if (this.drawable) { this.drawable.erase(); } this.editor.currentannotation = false; this.editor.save_current_page(); return; } } }, /** * Move an annotation to a new location. * @public * @param int newx * @param int newy * @method move_annotation */ move: function(newx, newy) { var diffx = newx - this.x, diffy = newy - this.y, newpath, oldpath, xy, x, y; this.x += diffx; this.y += diffy; this.endx += diffx; this.endy += diffy; if (this.path) { newpath = []; oldpath = this.path.split(':'); Y.each(oldpath, function(position) { xy = position.split(','); x = parseInt(xy[0], 10); y = parseInt(xy[1], 10); newpath.push((x + diffx) + ',' + (y + diffy)); }); this.path = newpath.join(':'); } if (this.drawable) { this.drawable.erase(); } this.editor.drawables.push(this.draw()); }, /** * Draw the in progress edit. * * @public * @method draw_current_edit * @param M.assignfeedback_editpdf.edit edit */ draw_current_edit: function(edit) { var noop = edit && false; // Override me please. return noop; }, /** * Promote the current edit to a real annotation. * * @public * @method init_from_edit * @param M.assignfeedback_editpdf.edit edit * @return bool if width/height is more than min. required. */ init_from_edit: function(edit) { var bounds = new M.assignfeedback_editpdf.rect(); bounds.bound([edit.start, edit.end]); this.gradeid = this.editor.get('gradeid'); this.pageno = this.editor.currentpage; this.x = bounds.x; this.y = bounds.y; this.endx = bounds.x + bounds.width; this.endy = bounds.y + bounds.height; this.colour = edit.annotationcolour; this.path = ''; return (bounds.has_min_width() && bounds.has_min_height()); } }); M.assignfeedback_editpdf = M.assignfeedback_editpdf || {}; M.assignfeedback_editpdf.annotation = ANNOTATION; // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . /* global STROKEWEIGHT, ANNOTATIONCOLOUR */ /** * Provides an in browser PDF editor. * * @module moodle-assignfeedback_editpdf-editor */ /** * Class representing a line. * * @namespace M.assignfeedback_editpdf * @class annotationline * @extends M.assignfeedback_editpdf.annotation */ var ANNOTATIONLINE = function(config) { ANNOTATIONLINE.superclass.constructor.apply(this, [config]); }; ANNOTATIONLINE.NAME = "annotationline"; ANNOTATIONLINE.ATTRS = {}; Y.extend(ANNOTATIONLINE, M.assignfeedback_editpdf.annotation, { /** * Draw a line annotation * @protected * @method draw * @return M.assignfeedback_editpdf.drawable */ draw: function() { var drawable, shape; drawable = new M.assignfeedback_editpdf.drawable(this.editor); shape = this.editor.graphic.addShape({ type: Y.Path, fill: false, stroke: { weight: STROKEWEIGHT, color: ANNOTATIONCOLOUR[this.colour] } }); shape.moveTo(this.x, this.y); shape.lineTo(this.endx, this.endy); shape.end(); drawable.shapes.push(shape); this.drawable = drawable; return ANNOTATIONLINE.superclass.draw.apply(this); }, /** * Draw the in progress edit. * * @public * @method draw_current_edit * @param M.assignfeedback_editpdf.edit edit */ draw_current_edit: function(edit) { var drawable = new M.assignfeedback_editpdf.drawable(this.editor), shape; shape = this.editor.graphic.addShape({ type: Y.Path, fill: false, stroke: { weight: STROKEWEIGHT, color: ANNOTATIONCOLOUR[edit.annotationcolour] } }); shape.moveTo(edit.start.x, edit.start.y); shape.lineTo(edit.end.x, edit.end.y); shape.end(); drawable.shapes.push(shape); return drawable; }, /** * Promote the current edit to a real annotation. * * @public * @method init_from_edit * @param M.assignfeedback_editpdf.edit edit * @return bool true if line bound is more than min width/height, else false. */ init_from_edit: function(edit) { this.gradeid = this.editor.get('gradeid'); this.pageno = this.editor.currentpage; this.x = edit.start.x; this.y = edit.start.y; this.endx = edit.end.x; this.endy = edit.end.y; this.colour = edit.annotationcolour; this.path = ''; return !(((this.endx - this.x) === 0) && ((this.endy - this.y) === 0)); } }); M.assignfeedback_editpdf = M.assignfeedback_editpdf || {}; M.assignfeedback_editpdf.annotationline = ANNOTATIONLINE; // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . /* global STROKEWEIGHT, ANNOTATIONCOLOUR */ /** * Provides an in browser PDF editor. * * @module moodle-assignfeedback_editpdf-editor */ /** * Class representing a rectangle. * * @namespace M.assignfeedback_editpdf * @class annotationrectangle * @extends M.assignfeedback_editpdf.annotation */ var ANNOTATIONRECTANGLE = function(config) { ANNOTATIONRECTANGLE.superclass.constructor.apply(this, [config]); }; ANNOTATIONRECTANGLE.NAME = "annotationrectangle"; ANNOTATIONRECTANGLE.ATTRS = {}; Y.extend(ANNOTATIONRECTANGLE, M.assignfeedback_editpdf.annotation, { /** * Draw a rectangle annotation * @protected * @method draw * @return M.assignfeedback_editpdf.drawable */ draw: function() { var drawable, bounds, shape; drawable = new M.assignfeedback_editpdf.drawable(this.editor); bounds = new M.assignfeedback_editpdf.rect(); bounds.bound([new M.assignfeedback_editpdf.point(this.x, this.y), new M.assignfeedback_editpdf.point(this.endx, this.endy)]); shape = this.editor.graphic.addShape({ type: Y.Rect, width: bounds.width, height: bounds.height, stroke: { weight: STROKEWEIGHT, color: ANNOTATIONCOLOUR[this.colour] }, x: bounds.x, y: bounds.y }); drawable.shapes.push(shape); this.drawable = drawable; return ANNOTATIONRECTANGLE.superclass.draw.apply(this); }, /** * Draw the in progress edit. * * @public * @method draw_current_edit * @param M.assignfeedback_editpdf.edit edit */ draw_current_edit: function(edit) { var drawable = new M.assignfeedback_editpdf.drawable(this.editor), shape, bounds; bounds = new M.assignfeedback_editpdf.rect(); bounds.bound([new M.assignfeedback_editpdf.point(edit.start.x, edit.start.y), new M.assignfeedback_editpdf.point(edit.end.x, edit.end.y)]); // Set min. width and height of rectangle. if (!bounds.has_min_width()) { bounds.set_min_width(); } if (!bounds.has_min_height()) { bounds.set_min_height(); } shape = this.editor.graphic.addShape({ type: Y.Rect, width: bounds.width, height: bounds.height, stroke: { weight: STROKEWEIGHT, color: ANNOTATIONCOLOUR[edit.annotationcolour] }, x: bounds.x, y: bounds.y }); drawable.shapes.push(shape); return drawable; } }); M.assignfeedback_editpdf = M.assignfeedback_editpdf || {}; M.assignfeedback_editpdf.annotationrectangle = ANNOTATIONRECTANGLE; // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . /* global STROKEWEIGHT, ANNOTATIONCOLOUR */ /** * Provides an in browser PDF editor. * * @module moodle-assignfeedback_editpdf-editor */ /** * Class representing a oval. * * @namespace M.assignfeedback_editpdf * @class annotationoval * @extends M.assignfeedback_editpdf.annotation */ var ANNOTATIONOVAL = function(config) { ANNOTATIONOVAL.superclass.constructor.apply(this, [config]); }; ANNOTATIONOVAL.NAME = "annotationoval"; ANNOTATIONOVAL.ATTRS = {}; Y.extend(ANNOTATIONOVAL, M.assignfeedback_editpdf.annotation, { /** * Draw a oval annotation * @protected * @method draw * @return M.assignfeedback_editpdf.drawable */ draw: function() { var drawable, bounds, shape; drawable = new M.assignfeedback_editpdf.drawable(this.editor); bounds = new M.assignfeedback_editpdf.rect(); bounds.bound([new M.assignfeedback_editpdf.point(this.x, this.y), new M.assignfeedback_editpdf.point(this.endx, this.endy)]); shape = this.editor.graphic.addShape({ type: Y.Ellipse, width: bounds.width, height: bounds.height, stroke: { weight: STROKEWEIGHT, color: ANNOTATIONCOLOUR[this.colour] }, x: bounds.x, y: bounds.y }); drawable.shapes.push(shape); this.drawable = drawable; return ANNOTATIONOVAL.superclass.draw.apply(this); }, /** * Draw the in progress edit. * * @public * @method draw_current_edit * @param M.assignfeedback_editpdf.edit edit */ draw_current_edit: function(edit) { var drawable = new M.assignfeedback_editpdf.drawable(this.editor), shape, bounds; bounds = new M.assignfeedback_editpdf.rect(); bounds.bound([new M.assignfeedback_editpdf.point(edit.start.x, edit.start.y), new M.assignfeedback_editpdf.point(edit.end.x, edit.end.y)]); // Set min. width and height of oval. if (!bounds.has_min_width()) { bounds.set_min_width(); } if (!bounds.has_min_height()) { bounds.set_min_height(); } shape = this.editor.graphic.addShape({ type: Y.Ellipse, width: bounds.width, height: bounds.height, stroke: { weight: STROKEWEIGHT, color: ANNOTATIONCOLOUR[edit.annotationcolour] }, x: bounds.x, y: bounds.y }); drawable.shapes.push(shape); return drawable; } }); M.assignfeedback_editpdf = M.assignfeedback_editpdf || {}; M.assignfeedback_editpdf.annotationoval = ANNOTATIONOVAL; // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . /* global STROKEWEIGHT, ANNOTATIONCOLOUR */ /** * Provides an in browser PDF editor. * * @module moodle-assignfeedback_editpdf-editor */ /** * Class representing a pen. * * @namespace M.assignfeedback_editpdf * @class annotationpen * @extends M.assignfeedback_editpdf.annotation */ var ANNOTATIONPEN = function(config) { ANNOTATIONPEN.superclass.constructor.apply(this, [config]); }; ANNOTATIONPEN.NAME = "annotationpen"; ANNOTATIONPEN.ATTRS = {}; Y.extend(ANNOTATIONPEN, M.assignfeedback_editpdf.annotation, { /** * Draw a pen annotation * @protected * @method draw * @return M.assignfeedback_editpdf.drawable */ draw: function() { var drawable, shape, first, positions, xy; drawable = new M.assignfeedback_editpdf.drawable(this.editor); shape = this.editor.graphic.addShape({ type: Y.Path, fill: false, stroke: { weight: STROKEWEIGHT, color: ANNOTATIONCOLOUR[this.colour] } }); first = true; // Recreate the pen path array. positions = this.path.split(':'); // Redraw all the lines. Y.each(positions, function(position) { xy = position.split(','); if (first) { shape.moveTo(xy[0], xy[1]); first = false; } else { shape.lineTo(xy[0], xy[1]); } }, this); shape.end(); drawable.shapes.push(shape); this.drawable = drawable; return ANNOTATIONPEN.superclass.draw.apply(this); }, /** * Draw the in progress edit. * * @public * @method draw_current_edit * @param M.assignfeedback_editpdf.edit edit */ draw_current_edit: function(edit) { var drawable = new M.assignfeedback_editpdf.drawable(this.editor), shape, first; shape = this.editor.graphic.addShape({ type: Y.Path, fill: false, stroke: { weight: STROKEWEIGHT, color: ANNOTATIONCOLOUR[edit.annotationcolour] } }); first = true; // Recreate the pen path array. // Redraw all the lines. Y.each(edit.path, function(position) { if (first) { shape.moveTo(position.x, position.y); first = false; } else { shape.lineTo(position.x, position.y); } }, this); shape.end(); drawable.shapes.push(shape); return drawable; }, /** * Promote the current edit to a real annotation. * * @public * @method init_from_edit * @param M.assignfeedback_editpdf.edit edit * @return bool true if pen bound is more than min width/height, else false. */ init_from_edit: function(edit) { var bounds = new M.assignfeedback_editpdf.rect(), pathlist = [], i = 0; // This will get the boundaries of all points in the path. bounds.bound(edit.path); for (i = 0; i < edit.path.length; i++) { pathlist.push(parseInt(edit.path[i].x, 10) + ',' + parseInt(edit.path[i].y, 10)); } this.gradeid = this.editor.get('gradeid'); this.pageno = this.editor.currentpage; this.x = bounds.x; this.y = bounds.y; this.endx = bounds.x + bounds.width; this.endy = bounds.y + bounds.height; this.colour = edit.annotationcolour; this.path = pathlist.join(':'); return (bounds.has_min_width() || bounds.has_min_height()); } }); M.assignfeedback_editpdf = M.assignfeedback_editpdf || {}; M.assignfeedback_editpdf.annotationpen = ANNOTATIONPEN; // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . /* global ANNOTATIONCOLOUR */ /** * Provides an in browser PDF editor. * * @module moodle-assignfeedback_editpdf-editor */ /** * Class representing a highlight. * * @namespace M.assignfeedback_editpdf * @class annotationhighlight * @extends M.assignfeedback_editpdf.annotation * @module moodle-assignfeedback_editpdf-editor */ var ANNOTATIONHIGHLIGHT = function(config) { ANNOTATIONHIGHLIGHT.superclass.constructor.apply(this, [config]); }; ANNOTATIONHIGHLIGHT.NAME = "annotationhighlight"; ANNOTATIONHIGHLIGHT.ATTRS = {}; Y.extend(ANNOTATIONHIGHLIGHT, M.assignfeedback_editpdf.annotation, { /** * Draw a highlight annotation * @protected * @method draw * @return M.assignfeedback_editpdf.drawable */ draw: function() { var drawable, shape, bounds, highlightcolour; drawable = new M.assignfeedback_editpdf.drawable(this.editor); bounds = new M.assignfeedback_editpdf.rect(); bounds.bound([new M.assignfeedback_editpdf.point(this.x, this.y), new M.assignfeedback_editpdf.point(this.endx, this.endy)]); highlightcolour = ANNOTATIONCOLOUR[this.colour]; // Add an alpha channel to the rgb colour. highlightcolour = highlightcolour.replace('rgb', 'rgba'); highlightcolour = highlightcolour.replace(')', ',0.5)'); shape = this.editor.graphic.addShape({ type: Y.Rect, width: bounds.width, height: bounds.height, stroke: false, fill: { color: highlightcolour }, x: bounds.x, y: bounds.y }); drawable.shapes.push(shape); this.drawable = drawable; return ANNOTATIONHIGHLIGHT.superclass.draw.apply(this); }, /** * Draw the in progress edit. * * @public * @method draw_current_edit * @param M.assignfeedback_editpdf.edit edit */ draw_current_edit: function(edit) { var drawable = new M.assignfeedback_editpdf.drawable(this.editor), shape, bounds, highlightcolour; bounds = new M.assignfeedback_editpdf.rect(); bounds.bound([new M.assignfeedback_editpdf.point(edit.start.x, edit.start.y), new M.assignfeedback_editpdf.point(edit.end.x, edit.end.y)]); // Set min. width of highlight. if (!bounds.has_min_width()) { bounds.set_min_width(); } highlightcolour = ANNOTATIONCOLOUR[edit.annotationcolour]; // Add an alpha channel to the rgb colour. highlightcolour = highlightcolour.replace('rgb', 'rgba'); highlightcolour = highlightcolour.replace(')', ',0.5)'); // We will draw a box with the current background colour. shape = this.editor.graphic.addShape({ type: Y.Rect, width: bounds.width, height: 16, stroke: false, fill: { color: highlightcolour }, x: bounds.x, y: edit.start.y }); drawable.shapes.push(shape); return drawable; }, /** * Promote the current edit to a real annotation. * * @public * @method init_from_edit * @param M.assignfeedback_editpdf.edit edit * @return bool true if highlight bound is more than min width/height, else false. */ init_from_edit: function(edit) { var bounds = new M.assignfeedback_editpdf.rect(); bounds.bound([edit.start, edit.end]); this.gradeid = this.editor.get('gradeid'); this.pageno = this.editor.currentpage; this.x = bounds.x; this.y = edit.start.y; this.endx = bounds.x + bounds.width; this.endy = edit.start.y + 16; this.colour = edit.annotationcolour; this.page = ''; return (bounds.has_min_width()); } }); M.assignfeedback_editpdf = M.assignfeedback_editpdf || {}; M.assignfeedback_editpdf.annotationhighlight = ANNOTATIONHIGHLIGHT; // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see . /* global SELECTOR */ /** * Provides an in browser PDF editor. * * @module moodle-assignfeedback_editpdf-editor */ /** * Class representing a stamp. * * @namespace M.assignfeedback_editpdf * @class annotationstamp * @extends M.assignfeedback_editpdf.annotation */ var ANNOTATIONSTAMP = function(config) { ANNOTATIONSTAMP.superclass.constructor.apply(this, [config]); }; ANNOTATIONSTAMP.NAME = "annotationstamp"; ANNOTATIONSTAMP.ATTRS = {}; Y.extend(ANNOTATIONSTAMP, M.assignfeedback_editpdf.annotation, { /** * Draw a stamp annotation * @protected * @method draw * @return M.assignfeedback_editpdf.drawable */ draw: function() { var drawable = new M.assignfeedback_editpdf.drawable(this.editor), drawingregion = this.editor.get_dialogue_element(SELECTOR.DRAWINGREGION), node, position; position = this.editor.get_window_coordinates(new M.assignfeedback_editpdf.point(this.x, this.y)); node = Y.Node.create('
'); node.setStyles({ 'position': 'absolute', 'display': 'inline-block', 'backgroundImage': 'url(' + this.editor.get_stamp_image_url(this.path) + ')', 'width': (this.endx - this.x), 'height': (this.endy - this.y), 'backgroundSize': '100% 100%', 'zIndex': 50 }); drawingregion.append(node); node.setX(position.x); node.setY(position.y); drawable.store_position(node, position.x, position.y); // Bind events only when editing. if (!this.editor.get('readonly')) { // Pass through the event handlers on the div. node.on('gesturemovestart', this.editor.edit_start, null, this.editor); node.on('gesturemove', this.editor.edit_move, null, this.editor); node.on('gesturemoveend', this.editor.edit_end, null, this.editor); } drawable.nodes.push(node); this.drawable = drawable; return ANNOTATIONSTAMP.superclass.draw.apply(this); }, /** * Draw the in progress edit. * * @public * @method draw_current_edit * @param M.assignfeedback_editpdf.edit edit */ draw_current_edit: function(edit) { var bounds = new M.assignfeedback_editpdf.rect(), drawable = new M.assignfeedback_editpdf.drawable(this.editor), drawingregion = this.editor.get_dialogue_element(SELECTOR.DRAWINGREGION), node, position; bounds.bound([edit.start, edit.end]); position = this.editor.get_window_coordinates(new M.assignfeedback_editpdf.point(bounds.x, bounds.y)); node = Y.Node.create('
'); node.setStyles({ 'position': 'absolute', 'display': 'inline-block', 'backgroundImage': 'url(' + this.editor.get_stamp_image_url(edit.stamp) + ')', 'width': bounds.width, 'height': bounds.height, 'backgroundSize': '100% 100%', 'zIndex': 50 }); drawingregion.append(node); node.setX(position.x); node.setY(position.y); drawable.store_position(node, position.x, position.y); drawable.nodes.push(node); return drawable; }, /** * Promote the current edit to a real annotation. * * @public * @method init_from_edit * @param M.assignfeedback_editpdf.edit edit * @return bool if width/height is more than min. required. */ init_from_edit: function(edit) { var bounds = new M.assignfeedback_editpdf.rect(); bounds.bound([edit.start, edit.end]); if (bounds.width < 40) { bounds.width = 40; } if (bounds.height < 40) { bounds.height = 40; } this.gradeid = this.editor.get('gradeid'); this.pageno = this.editor.currentpage; this.x = bounds.x; this.y = bounds.y; this.endx = bounds.x + bounds.width; this.endy = bounds.y + bounds.height; this.colour = edit.annotationcolour; this.path = edit.stamp; // Min width and height is always more than 40px. return true; }, /** * Move an annotation to a new location. * @public * @param int newx * @param int newy * @method move_annotation */ move: function(newx, newy) { var diffx = newx - this.x, diffy = newy - this.y; this.x += diffx; this.y += diffy; this.endx += diffx; this.endy += diffy; if (this.drawable) { this.drawable.erase(); } this.editor.drawables.push(this.draw()); } }); M.assignfeedback_editpdf = M.assignfeedback_editpdf || {}; M.assignfeedback_editpdf.annotationstamp = ANNOTATIONSTAMP; var DROPDOWN_NAME = "Dropdown menu", DROPDOWN; /** * Provides an in browser PDF editor. * * @module moodle-assignfeedback_editpdf-editor */ /** * This is a drop down list of buttons triggered (and aligned to) a button. * * @namespace M.assignfeedback_editpdf * @class dropdown * @constructor * @extends M.core.dialogue */ DROPDOWN = function(config) { config.draggable = false; config.centered = false; config.width = 'auto'; config.visible = false; config.footerContent = ''; DROPDOWN.superclass.constructor.apply(this, [config]); }; Y.extend(DROPDOWN, M.core.dialogue, { /** * Initialise the menu. * * @method initializer * @return void */ initializer: function(config) { var button, body, headertext, bb; DROPDOWN.superclass.initializer.call(this, config); bb = this.get('boundingBox'); bb.addClass('assignfeedback_editpdf_dropdown'); // Align the menu to the button that opens it. button = this.get('buttonNode'); // Close the menu when clicked outside (excluding the button that opened the menu). body = this.bodyNode; headertext = Y.Node.create('

'); headertext.addClass('accesshide'); headertext.setHTML(this.get('headerText')); body.prepend(headertext); body.on('clickoutside', function(e) { if (this.get('visible')) { // Note: we need to compare ids because for some reason - sometimes button is an Object, not a Y.Node. if (e.target.get('id') !== button.get('id') && e.target.ancestor().get('id') !== button.get('id')) { e.preventDefault(); this.hide(); } } }, this); button.on('click', function(e) { e.preventDefault(); this.show(); }, this); button.on('key', this.show, 'enter,space', this); }, /** * Override the show method to align to the button. * * @method show * @return void */ show: function() { var button = this.get('buttonNode'), result = DROPDOWN.superclass.show.call(this); this.align(button, [Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.BL]); return result; } }, { NAME: DROPDOWN_NAME, ATTRS: { /** * The header for the drop down (only accessible to screen readers). * * @attribute headerText * @type String * @default '' */ headerText: { value: '' }, /** * The button used to show/hide this drop down menu. * * @attribute buttonNode * @type Y.Node * @default null */ buttonNode: { value: null } } }); Y.Base.modifyAttrs(DROPDOWN, { /** * Whether the widget should be modal or not. * * Moodle override: We override this for commentsearch to force it always false. * * @attribute Modal * @type Boolean * @default false */ modal: { getter: function() { return false; } } }); M.assignfeedback_editpdf = M.assignfeedback_editpdf || {}; M.assignfeedback_editpdf.dropdown = DROPDOWN; var COLOURPICKER_NAME = "Colourpicker", COLOURPICKER; /** * Provides an in browser PDF editor. * * @module moodle-assignfeedback_editpdf-editor */ /** * COLOURPICKER * This is a drop down list of colours. * * @namespace M.assignfeedback_editpdf * @class colourpicker * @constructor * @extends M.assignfeedback_editpdf.dropdown */ COLOURPICKER = function(config) { COLOURPICKER.superclass.constructor.apply(this, [config]); }; Y.extend(COLOURPICKER, M.assignfeedback_editpdf.dropdown, { /** * Initialise the menu. * * @method initializer * @return void */ initializer: function(config) { var colourlist = Y.Node.create('