on-demand release 4.0dev+
[moodle.git] / mod / assign / feedback / editpdf / yui / build / moodle-assignfeedback_editpdf-editor / moodle-assignfeedback_editpdf-editor-debug.js
CommitLineData
5c386472
DW
1YUI.add('moodle-assignfeedback_editpdf-editor', function (Y, NAME) {
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
ad3f8cd1 17/* eslint-disable no-unused-vars */
5c386472
DW
18
19/**
20 * A list of globals used by this module.
21 *
22 * @module moodle-assignfeedback_editpdf-editor
23 */
24var AJAXBASE = M.cfg.wwwroot + '/mod/assign/feedback/editpdf/ajax.php',
aa3e4bde 25 AJAXBASEPROGRESS = M.cfg.wwwroot + '/mod/assign/feedback/editpdf/ajax_progress.php',
5c386472 26 CSS = {
3a0bc0fd 27 DIALOGUE: 'assignfeedback_editpdf_widget'
5c386472
DW
28 },
29 SELECTOR = {
3a0bc0fd
DP
30 PREVIOUSBUTTON: '.navigate-previous-button',
31 NEXTBUTTON: ' .navigate-next-button',
32 SEARCHCOMMENTSBUTTON: '.searchcommentsbutton',
23990a0a 33 EXPCOLCOMMENTSBUTTON: '.expcolcommentsbutton',
3a0bc0fd
DP
34 SEARCHFILTER: '.assignfeedback_editpdf_commentsearch input',
35 SEARCHCOMMENTSLIST: '.assignfeedback_editpdf_commentsearch ul',
36 PAGESELECT: '.navigate-page-select',
37 LOADINGICON: '.loading',
38 PROGRESSBARCONTAINER: '.progress-info.progress-striped',
39 DRAWINGREGION: '.drawingregion',
40 DRAWINGCANVAS: '.drawingcanvas',
41 SAVE: '.savebutton',
42 COMMENTCOLOURBUTTON: '.commentcolourbutton',
43 COMMENTMENU: '.commentdrawable a',
44 ANNOTATIONCOLOURBUTTON: '.annotationcolourbutton',
45 DELETEANNOTATIONBUTTON: '.deleteannotationbutton',
e3511e79
DW
46 WARNINGMESSAGECONTAINER: '.warningmessages',
47 ICONMESSAGECONTAINER: '.infoicon',
48 UNSAVEDCHANGESDIV: '.assignfeedback_editpdf_warningmessages',
3a0bc0fd
DP
49 UNSAVEDCHANGESINPUT: 'input[name="assignfeedback_editpdf_haschanges"]',
50 STAMPSBUTTON: '.currentstampbutton',
77f31a47 51 USERINFOREGION: '[data-region="user-info"]',
9432553b
NN
52 ROTATELEFTBUTTON: '.rotateleftbutton',
53 ROTATERIGHTBUTTON: '.rotaterightbutton',
3a0bc0fd 54 DIALOGUE: '.' + CSS.DIALOGUE
5c386472
DW
55 },
56 SELECTEDBORDERCOLOUR = 'rgba(200, 200, 255, 0.9)',
57 SELECTEDFILLCOLOUR = 'rgba(200, 200, 255, 0.5)',
1d38083c 58 COMMENTTEXTCOLOUR = 'rgb(51, 51, 51)',
5c386472 59 COMMENTCOLOUR = {
3a0bc0fd
DP
60 'white': 'rgb(255,255,255)',
61 'yellow': 'rgb(255,236,174)',
62 'red': 'rgb(249,181,179)',
63 'green': 'rgb(214,234,178)',
64 'blue': 'rgb(203,217,237)',
65 'clear': 'rgba(255,255,255, 0)'
5c386472
DW
66 },
67 ANNOTATIONCOLOUR = {
3a0bc0fd
DP
68 'white': 'rgb(255,255,255)',
69 'yellow': 'rgb(255,207,53)',
70 'red': 'rgb(239,69,64)',
71 'green': 'rgb(152,202,62)',
72 'blue': 'rgb(125,159,211)',
73 'black': 'rgb(51,51,51)'
5c386472
DW
74 },
75 CLICKTIMEOUT = 300,
76 TOOLSELECTOR = {
da91de78
BL
77 'comment': '.commentbutton',
78 'pen': '.penbutton',
79 'line': '.linebutton',
80 'rectangle': '.rectanglebutton',
81 'oval': '.ovalbutton',
82 'stamp': '.stampbutton',
83 'select': '.selectbutton',
55907a73 84 'drag': '.dragbutton',
da91de78 85 'highlight': '.highlightbutton'
5c386472
DW
86 },
87 STROKEWEIGHT = 4;
88// This file is part of Moodle - http://moodle.org/
89//
90// Moodle is free software: you can redistribute it and/or modify
91// it under the terms of the GNU General Public License as published by
92// the Free Software Foundation, either version 3 of the License, or
93// (at your option) any later version.
94//
95// Moodle is distributed in the hope that it will be useful,
96// but WITHOUT ANY WARRANTY; without even the implied warranty of
97// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
98// GNU General Public License for more details.
99//
100// You should have received a copy of the GNU General Public License
101// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
102
103/**
1f777e5c 104 * Provides an in browser PDF editor.
5c386472
DW
105 *
106 * @module moodle-assignfeedback_editpdf-editor
107 */
108
109/**
1f777e5c 110 * Class representing a 2d point.
5c386472
DW
111 *
112 * @namespace M.assignfeedback_editpdf
1f777e5c
AN
113 * @param Number x
114 * @param Number y
5c386472
DW
115 * @class point
116 */
557f44d9 117var POINT = function(x, y) {
5c386472
DW
118
119 /**
120 * X coordinate.
121 * @property x
122 * @type int
123 * @public
124 */
125 this.x = parseInt(x, 10);
126
127 /**
128 * Y coordinate.
129 * @property y
130 * @type int
131 * @public
132 */
133 this.y = parseInt(y, 10);
134
135 /**
136 * Clip this point to the rect
137 * @method clip
138 * @param M.assignfeedback_editpdf.point
139 * @public
140 */
141 this.clip = function(bounds) {
142 if (this.x < bounds.x) {
143 this.x = bounds.x;
144 }
145 if (this.x > (bounds.x + bounds.width)) {
146 this.x = bounds.x + bounds.width;
147 }
148 if (this.y < bounds.y) {
149 this.y = bounds.y;
150 }
151 if (this.y > (bounds.y + bounds.height)) {
152 this.y = bounds.y + bounds.height;
153 }
154 // For chaining.
155 return this;
156 };
157};
158
159M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
160M.assignfeedback_editpdf.point = POINT;
161// This file is part of Moodle - http://moodle.org/
162//
163// Moodle is free software: you can redistribute it and/or modify
164// it under the terms of the GNU General Public License as published by
165// the Free Software Foundation, either version 3 of the License, or
166// (at your option) any later version.
167//
168// Moodle is distributed in the hope that it will be useful,
169// but WITHOUT ANY WARRANTY; without even the implied warranty of
170// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
171// GNU General Public License for more details.
172//
173// You should have received a copy of the GNU General Public License
174// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
175
176/**
1f777e5c 177 * Provides an in browser PDF editor.
5c386472
DW
178 *
179 * @module moodle-assignfeedback_editpdf-editor
180 */
181
182/**
1f777e5c 183 * Class representing a 2d rect.
5c386472
DW
184 *
185 * @namespace M.assignfeedback_editpdf
186 * @param int x
187 * @param int y
188 * @param int width
189 * @param int height
190 * @class rect
191 */
557f44d9 192var RECT = function(x, y, width, height) {
5c386472
DW
193
194 /**
195 * X coordinate.
196 * @property x
197 * @type int
198 * @public
199 */
200 this.x = x;
201
202 /**
203 * Y coordinate.
204 * @property y
205 * @type int
206 * @public
207 */
208 this.y = y;
209
210 /**
211 * Width
212 * @property width
213 * @type int
214 * @public
215 */
216 this.width = width;
217
218 /**
219 * Height
220 * @property height
221 * @type int
222 * @public
223 */
224 this.height = height;
225
226 /**
227 * Set this rect to represent the smallest possible rectangle containing this list of points.
228 * @method bounds
229 * @param M.assignfeedback_editpdf.point[]
230 * @public
231 */
232 this.bound = function(points) {
233 var minx = 0,
234 maxx = 0,
235 miny = 0,
236 maxy = 0,
237 i = 0,
238 point;
239
240 for (i = 0; i < points.length; i++) {
241 point = points[i];
242 if (point.x < minx || i === 0) {
243 minx = point.x;
244 }
245 if (point.x > maxx || i === 0) {
246 maxx = point.x;
247 }
248 if (point.y < miny || i === 0) {
249 miny = point.y;
250 }
251 if (point.y > maxy || i === 0) {
252 maxy = point.y;
253 }
254 }
255 this.x = minx;
256 this.y = miny;
257 this.width = maxx - minx;
258 this.height = maxy - miny;
259 // Allow chaining.
260 return this;
261 };
baf881b8
RT
262
263 /**
264 * Checks if rect has min width.
265 * @method has_min_width
266 * @return bool true if width is more than 5px.
267 * @public
268 */
269 this.has_min_width = function() {
270 return (this.width >= 5);
271 };
272
273 /**
274 * Checks if rect has min height.
275 * @method has_min_height
276 * @return bool true if height is more than 5px.
277 * @public
278 */
279 this.has_min_height = function() {
280 return (this.height >= 5);
281 };
282
283 /**
284 * Set min. width of annotation bound.
285 * @method set_min_width
286 * @public
287 */
288 this.set_min_width = function() {
289 this.width = 5;
290 };
291
292 /**
293 * Set min. height of annotation bound.
294 * @method set_min_height
295 * @public
296 */
297 this.set_min_height = function() {
298 this.height = 5;
299 };
5c386472
DW
300};
301
302M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
303M.assignfeedback_editpdf.rect = RECT;
304// This file is part of Moodle - http://moodle.org/
305//
306// Moodle is free software: you can redistribute it and/or modify
307// it under the terms of the GNU General Public License as published by
308// the Free Software Foundation, either version 3 of the License, or
309// (at your option) any later version.
310//
311// Moodle is distributed in the hope that it will be useful,
312// but WITHOUT ANY WARRANTY; without even the implied warranty of
313// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
314// GNU General Public License for more details.
315//
316// You should have received a copy of the GNU General Public License
317// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
318
319/**
1f777e5c 320 * Provides an in browser PDF editor.
5c386472
DW
321 *
322 * @module moodle-assignfeedback_editpdf-editor
323 */
324
325/**
326 * EDIT
327 *
328 * @namespace M.assignfeedback_editpdf
329 * @class edit
330 */
557f44d9 331var EDIT = function() {
5c386472
DW
332
333 /**
334 * Starting point for the edit.
335 * @property start
336 * @type M.assignfeedback_editpdf.point|false
337 * @public
338 */
339 this.start = false;
340
341 /**
342 * Finishing point for the edit.
343 * @property end
344 * @type M.assignfeedback_editpdf.point|false
345 * @public
346 */
347 this.end = false;
348
349 /**
350 * Starting time for the edit.
351 * @property starttime
352 * @type int
353 * @public
354 */
355 this.starttime = 0;
356
357 /**
358 * Starting point for the currently selected annotation.
359 * @property annotationstart
360 * @type M.assignfeedback_editpdf.point|false
361 * @public
362 */
363 this.annotationstart = false;
364
365 /**
366 * The currently selected tool
367 * @property tool
368 * @type String
369 * @public
370 */
55907a73 371 this.tool = "drag";
5c386472
DW
372
373 /**
374 * The currently comment colour
375 * @property commentcolour
376 * @type String
377 * @public
378 */
379 this.commentcolour = 'yellow';
380
381 /**
382 * The currently annotation colour
383 * @property annotationcolour
384 * @type String
385 * @public
386 */
387 this.annotationcolour = 'red';
388
389 /**
390 * The current stamp image.
391 * @property stamp
392 * @type String
393 * @public
394 */
395 this.stamp = '';
396
397 /**
398 * List of points the the current drawing path.
399 * @property path
400 * @type M.assignfeedback_editpdf.point[]
401 * @public
402 */
403 this.path = [];
404};
405
406M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
407M.assignfeedback_editpdf.edit = EDIT;
408// This file is part of Moodle - http://moodle.org/
409//
410// Moodle is free software: you can redistribute it and/or modify
411// it under the terms of the GNU General Public License as published by
412// the Free Software Foundation, either version 3 of the License, or
413// (at your option) any later version.
414//
415// Moodle is distributed in the hope that it will be useful,
416// but WITHOUT ANY WARRANTY; without even the implied warranty of
417// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
418// GNU General Public License for more details.
419//
420// You should have received a copy of the GNU General Public License
421// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
422
423/**
1f777e5c 424 * Provides an in browser PDF editor.
5c386472
DW
425 *
426 * @module moodle-assignfeedback_editpdf-editor
427 */
428
429/**
1f777e5c 430 * Class representing a drawable thing which contains both Y.Nodes, and Y.Shapes.
5c386472
DW
431 *
432 * @namespace M.assignfeedback_editpdf
433 * @param M.assignfeedback_editpdf.editor editor
434 * @class drawable
435 */
557f44d9 436var DRAWABLE = function(editor) {
5c386472
DW
437
438 /**
439 * Reference to M.assignfeedback_editpdf.editor.
440 * @property editor
441 * @type M.assignfeedback_editpdf.editor
442 * @public
443 */
444 this.editor = editor;
445
446 /**
447 * Array of Y.Shape
448 * @property shapes
449 * @type Y.Shape[]
450 * @public
451 */
452 this.shapes = [];
453
454 /**
455 * Array of Y.Node
456 * @property nodes
457 * @type Y.Node[]
458 * @public
459 */
460 this.nodes = [];
461
462 /**
463 * Delete the shapes from the drawable.
464 * @protected
465 * @method erase_drawable
466 */
467 this.erase = function() {
468 if (this.shapes) {
469 while (this.shapes.length > 0) {
470 this.editor.graphic.removeShape(this.shapes.pop());
471 }
472 }
473 if (this.nodes) {
474 while (this.nodes.length > 0) {
475 this.nodes.pop().remove();
476 }
477 }
478 };
479
50c12f01
DS
480 /**
481 * Update the positions of all absolutely positioned nodes, when the drawing canvas is scrolled
482 * @public
483 * @method scroll_update
484 * @param scrollx int
485 * @param scrolly int
486 */
487 this.scroll_update = function(scrollx, scrolly) {
488 var i, x, y;
489 for (i = 0; i < this.nodes.length; i++) {
490 x = this.nodes[i].getData('x');
491 y = this.nodes[i].getData('y');
492 if (x !== undefined && y !== undefined) {
493 this.nodes[i].setX(parseInt(x, 10) - scrollx);
494 this.nodes[i].setY(parseInt(y, 10) - scrolly);
495 }
496 }
497 };
498
499 /**
500 * Store the initial position of the node, so it can be updated when the drawing canvas is scrolled
501 * @public
502 * @method store_position
503 * @param container
504 * @param x
505 * @param y
506 */
507 this.store_position = function(container, x, y) {
508 var drawingregion, scrollx, scrolly;
509
da91de78 510 drawingregion = this.editor.get_dialogue_element(SELECTOR.DRAWINGREGION);
50c12f01
DS
511 scrollx = parseInt(drawingregion.get('scrollLeft'), 10);
512 scrolly = parseInt(drawingregion.get('scrollTop'), 10);
513 container.setData('x', x + scrollx);
514 container.setData('y', y + scrolly);
515 };
5c386472
DW
516};
517
518M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
519M.assignfeedback_editpdf.drawable = DRAWABLE;
520// This file is part of Moodle - http://moodle.org/
521//
522// Moodle is free software: you can redistribute it and/or modify
523// it under the terms of the GNU General Public License as published by
524// the Free Software Foundation, either version 3 of the License, or
525// (at your option) any later version.
526//
527// Moodle is distributed in the hope that it will be useful,
528// but WITHOUT ANY WARRANTY; without even the implied warranty of
529// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
530// GNU General Public License for more details.
531//
532// You should have received a copy of the GNU General Public License
533// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
534
535/**
1f777e5c 536 * Provides an in browser PDF editor.
5c386472
DW
537 *
538 * @module moodle-assignfeedback_editpdf-editor
539 */
1f777e5c
AN
540
541/**
542 * Class representing a highlight.
543 *
544 * @namespace M.assignfeedback_editpdf
545 * @class annotation
546 * @constructor
547 */
557f44d9 548var ANNOTATION = function(config) {
5c386472
DW
549 ANNOTATION.superclass.constructor.apply(this, [config]);
550};
551
552ANNOTATION.NAME = "annotation";
553ANNOTATION.ATTRS = {};
554
555Y.extend(ANNOTATION, Y.Base, {
556 /**
557 * Reference to M.assignfeedback_editpdf.editor.
558 * @property editor
559 * @type M.assignfeedback_editpdf.editor
560 * @public
561 */
3a0bc0fd 562 editor: null,
5c386472
DW
563
564 /**
565 * Grade id
566 * @property gradeid
567 * @type Int
568 * @public
569 */
3a0bc0fd 570 gradeid: 0,
5c386472
DW
571
572 /**
573 * Comment page number
574 * @property pageno
575 * @type Int
576 * @public
577 */
3a0bc0fd 578 pageno: 0,
5c386472
DW
579
580 /**
581 * X position
582 * @property x
583 * @type Int
584 * @public
585 */
3a0bc0fd 586 x: 0,
5c386472
DW
587
588 /**
589 * Y position
590 * @property y
591 * @type Int
592 * @public
593 */
3a0bc0fd 594 y: 0,
5c386472
DW
595
596 /**
597 * Ending x position
598 * @property endx
599 * @type Int
600 * @public
601 */
3a0bc0fd 602 endx: 0,
5c386472
DW
603
604 /**
605 * Ending y position
606 * @property endy
607 * @type Int
608 * @public
609 */
3a0bc0fd 610 endy: 0,
5c386472
DW
611
612 /**
613 * Path
614 * @property path
615 * @type String - list of points like x1,y1:x2,y2
616 * @public
617 */
3a0bc0fd 618 path: '',
5c386472
DW
619
620 /**
621 * Tool.
622 * @property type
623 * @type String
624 * @public
625 */
3a0bc0fd 626 type: 'rect',
5c386472
DW
627
628 /**
629 * Annotation colour.
630 * @property colour
631 * @type String
632 * @public
633 */
3a0bc0fd 634 colour: 'red',
5c386472
DW
635
636 /**
637 * Reference to M.assignfeedback_editpdf.drawable
638 * @property drawable
639 * @type M.assignfeedback_editpdf.drawable
640 * @public
641 */
3a0bc0fd 642 drawable: false,
5c386472
DW
643
644 /**
645 * Initialise the annotation.
646 *
647 * @method initializer
648 * @return void
649 */
3a0bc0fd 650 initializer: function(config) {
5c386472
DW
651 this.editor = config.editor || null;
652 this.gradeid = parseInt(config.gradeid, 10) || 0;
653 this.pageno = parseInt(config.pageno, 10) || 0;
654 this.x = parseInt(config.x, 10) || 0;
655 this.y = parseInt(config.y, 10) || 0;
656 this.endx = parseInt(config.endx, 10) || 0;
657 this.endy = parseInt(config.endy, 10) || 0;
658 this.path = config.path || '';
659 this.type = config.type || 'rect';
660 this.colour = config.colour || 'red';
661 this.drawable = false;
662 },
663
664 /**
665 * Clean a comment record, returning an oject with only fields that are valid.
666 * @public
667 * @method clean
668 * @return {}
669 */
3a0bc0fd 670 clean: function() {
5c386472 671 return {
3a0bc0fd
DP
672 gradeid: this.gradeid,
673 x: parseInt(this.x, 10),
674 y: parseInt(this.y, 10),
675 endx: parseInt(this.endx, 10),
676 endy: parseInt(this.endy, 10),
677 type: this.type,
678 path: this.path,
679 pageno: this.pageno,
680 colour: this.colour
5c386472
DW
681 };
682 },
683
684 /**
685 * Draw a selection around this annotation if it is selected.
686 * @public
687 * @method draw_highlight
688 * @return M.assignfeedback_editpdf.drawable
689 */
3a0bc0fd 690 draw_highlight: function() {
5c386472 691 var bounds,
da91de78
BL
692 drawingregion = this.editor.get_dialogue_element(SELECTOR.DRAWINGREGION),
693 offsetcanvas = this.editor.get_dialogue_element(SELECTOR.DRAWINGCANVAS).getXY(),
5c386472
DW
694 shape;
695
696 if (this.editor.currentannotation === this) {
697 // Draw a highlight around the annotation.
698 bounds = new M.assignfeedback_editpdf.rect();
699 bounds.bound([new M.assignfeedback_editpdf.point(this.x, this.y),
700 new M.assignfeedback_editpdf.point(this.endx, this.endy)]);
701
702 shape = this.editor.graphic.addShape({
703 type: Y.Rect,
704 width: bounds.width,
705 height: bounds.height,
706 stroke: {
707 weight: STROKEWEIGHT,
708 color: SELECTEDBORDERCOLOUR
709 },
710 fill: {
711 color: SELECTEDFILLCOLOUR
712 },
713 x: bounds.x,
714 y: bounds.y
715 });
716 this.drawable.shapes.push(shape);
717
718 // Add a delete X to the annotation.
719 var deleteicon = Y.Node.create('<img src="' + M.util.image_url('trash', 'assignfeedback_editpdf') + '"/>'),
720 deletelink = Y.Node.create('<a href="#" role="button"></a>');
721
722 deleteicon.setAttrs({
723 'alt': M.util.get_string('deleteannotation', 'assignfeedback_editpdf')
724 });
725 deleteicon.setStyles({
3a0bc0fd 726 'backgroundColor': 'white'
5c386472
DW
727 });
728 deletelink.addClass('deleteannotationbutton');
729 deletelink.append(deleteicon);
730
731 drawingregion.append(deletelink);
732 deletelink.setData('annotation', this);
5c386472
DW
733
734 deletelink.on('click', this.remove, this);
735 deletelink.on('key', this.remove, 'space,enter', this);
736
737 deletelink.setX(offsetcanvas[0] + bounds.x + bounds.width - 18);
738 deletelink.setY(offsetcanvas[1] + bounds.y + 6);
739 this.drawable.nodes.push(deletelink);
740 }
741 return this.drawable;
742 },
743
744 /**
745 * Draw an annotation
746 * @public
747 * @method draw
748 * @return M.assignfeedback_editpdf.drawable|false
749 */
3a0bc0fd 750 draw: function() {
5c386472
DW
751 // Should be overridden by the subclass.
752 this.draw_highlight();
753 return this.drawable;
754 },
755
756 /**
757 * Delete an annotation
758 * @protected
759 * @method remove
760 * @param event
761 */
3a0bc0fd 762 remove: function(e) {
557f44d9
AN
763 var annotations,
764 i;
5c386472 765
114913e3
DS
766 e.preventDefault();
767
5c386472
DW
768 annotations = this.editor.pages[this.editor.currentpage].annotations;
769 for (i = 0; i < annotations.length; i++) {
770 if (annotations[i] === this) {
771 annotations.splice(i, 1);
772 if (this.drawable) {
773 this.drawable.erase();
774 }
775 this.editor.currentannotation = false;
776 this.editor.save_current_page();
777 return;
778 }
779 }
780 },
781
782 /**
783 * Move an annotation to a new location.
784 * @public
785 * @param int newx
786 * @param int newy
787 * @method move_annotation
788 */
3a0bc0fd 789 move: function(newx, newy) {
5c386472
DW
790 var diffx = newx - this.x,
791 diffy = newy - this.y,
792 newpath, oldpath, xy,
793 x, y;
794
795 this.x += diffx;
796 this.y += diffy;
797 this.endx += diffx;
798 this.endy += diffy;
799
800 if (this.path) {
801 newpath = [];
802 oldpath = this.path.split(':');
803 Y.each(oldpath, function(position) {
804 xy = position.split(',');
805 x = parseInt(xy[0], 10);
806 y = parseInt(xy[1], 10);
807 newpath.push((x + diffx) + ',' + (y + diffy));
808 });
809
810 this.path = newpath.join(':');
811
812 }
813 if (this.drawable) {
814 this.drawable.erase();
815 }
816 this.editor.drawables.push(this.draw());
817 },
818
819 /**
820 * Draw the in progress edit.
821 *
822 * @public
823 * @method draw_current_edit
824 * @param M.assignfeedback_editpdf.edit edit
825 */
3a0bc0fd 826 draw_current_edit: function(edit) {
5c386472
DW
827 var noop = edit && false;
828 // Override me please.
829 return noop;
830 },
831
832 /**
833 * Promote the current edit to a real annotation.
834 *
835 * @public
836 * @method init_from_edit
837 * @param M.assignfeedback_editpdf.edit edit
baf881b8 838 * @return bool if width/height is more than min. required.
5c386472 839 */
3a0bc0fd 840 init_from_edit: function(edit) {
5c386472
DW
841 var bounds = new M.assignfeedback_editpdf.rect();
842 bounds.bound([edit.start, edit.end]);
843
844 this.gradeid = this.editor.get('gradeid');
845 this.pageno = this.editor.currentpage;
846 this.x = bounds.x;
847 this.y = bounds.y;
848 this.endx = bounds.x + bounds.width;
849 this.endy = bounds.y + bounds.height;
850 this.colour = edit.annotationcolour;
851 this.path = '';
baf881b8 852 return (bounds.has_min_width() && bounds.has_min_height());
5c386472
DW
853 }
854
855});
856
857M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
858M.assignfeedback_editpdf.annotation = ANNOTATION;
859// This file is part of Moodle - http://moodle.org/
860//
861// Moodle is free software: you can redistribute it and/or modify
862// it under the terms of the GNU General Public License as published by
863// the Free Software Foundation, either version 3 of the License, or
864// (at your option) any later version.
865//
866// Moodle is distributed in the hope that it will be useful,
867// but WITHOUT ANY WARRANTY; without even the implied warranty of
868// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
869// GNU General Public License for more details.
870//
871// You should have received a copy of the GNU General Public License
872// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
873
1f777e5c
AN
874/**
875 * Provides an in browser PDF editor.
876 *
877 * @module moodle-assignfeedback_editpdf-editor
878 */
879
5c386472
DW
880/**
881 * Class representing a line.
882 *
883 * @namespace M.assignfeedback_editpdf
884 * @class annotationline
1f777e5c 885 * @extends M.assignfeedback_editpdf.annotation
5c386472 886 */
557f44d9 887var ANNOTATIONLINE = function(config) {
5c386472
DW
888 ANNOTATIONLINE.superclass.constructor.apply(this, [config]);
889};
890
891ANNOTATIONLINE.NAME = "annotationline";
892ANNOTATIONLINE.ATTRS = {};
893
894Y.extend(ANNOTATIONLINE, M.assignfeedback_editpdf.annotation, {
895 /**
896 * Draw a line annotation
897 * @protected
898 * @method draw
899 * @return M.assignfeedback_editpdf.drawable
900 */
3a0bc0fd 901 draw: function() {
5c386472
DW
902 var drawable,
903 shape;
904
905 drawable = new M.assignfeedback_editpdf.drawable(this.editor);
906
907 shape = this.editor.graphic.addShape({
908 type: Y.Path,
909 fill: false,
910 stroke: {
911 weight: STROKEWEIGHT,
912 color: ANNOTATIONCOLOUR[this.colour]
913 }
914 });
915
916 shape.moveTo(this.x, this.y);
917 shape.lineTo(this.endx, this.endy);
918 shape.end();
919 drawable.shapes.push(shape);
920 this.drawable = drawable;
921
922 return ANNOTATIONLINE.superclass.draw.apply(this);
923 },
924
925 /**
926 * Draw the in progress edit.
927 *
928 * @public
929 * @method draw_current_edit
930 * @param M.assignfeedback_editpdf.edit edit
931 */
3a0bc0fd 932 draw_current_edit: function(edit) {
5c386472
DW
933 var drawable = new M.assignfeedback_editpdf.drawable(this.editor),
934 shape;
935
936 shape = this.editor.graphic.addShape({
937 type: Y.Path,
938 fill: false,
939 stroke: {
940 weight: STROKEWEIGHT,
941 color: ANNOTATIONCOLOUR[edit.annotationcolour]
942 }
943 });
944
945 shape.moveTo(edit.start.x, edit.start.y);
946 shape.lineTo(edit.end.x, edit.end.y);
947 shape.end();
948
949 drawable.shapes.push(shape);
950
951 return drawable;
952 },
953
954 /**
955 * Promote the current edit to a real annotation.
956 *
957 * @public
958 * @method init_from_edit
959 * @param M.assignfeedback_editpdf.edit edit
baf881b8 960 * @return bool true if line bound is more than min width/height, else false.
5c386472 961 */
3a0bc0fd 962 init_from_edit: function(edit) {
5c386472
DW
963 this.gradeid = this.editor.get('gradeid');
964 this.pageno = this.editor.currentpage;
965 this.x = edit.start.x;
966 this.y = edit.start.y;
967 this.endx = edit.end.x;
968 this.endy = edit.end.y;
969 this.colour = edit.annotationcolour;
970 this.path = '';
baf881b8
RT
971
972 return !(((this.endx - this.x) === 0) && ((this.endy - this.y) === 0));
5c386472
DW
973 }
974
975});
976
977M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
978M.assignfeedback_editpdf.annotationline = ANNOTATIONLINE;
979// This file is part of Moodle - http://moodle.org/
980//
981// Moodle is free software: you can redistribute it and/or modify
982// it under the terms of the GNU General Public License as published by
983// the Free Software Foundation, either version 3 of the License, or
984// (at your option) any later version.
985//
986// Moodle is distributed in the hope that it will be useful,
987// but WITHOUT ANY WARRANTY; without even the implied warranty of
988// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
989// GNU General Public License for more details.
990//
991// You should have received a copy of the GNU General Public License
992// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
993
1f777e5c
AN
994/**
995 * Provides an in browser PDF editor.
996 *
997 * @module moodle-assignfeedback_editpdf-editor
998 */
999
5c386472
DW
1000/**
1001 * Class representing a rectangle.
1002 *
1003 * @namespace M.assignfeedback_editpdf
1004 * @class annotationrectangle
1f777e5c 1005 * @extends M.assignfeedback_editpdf.annotation
5c386472 1006 */
557f44d9 1007var ANNOTATIONRECTANGLE = function(config) {
5c386472
DW
1008 ANNOTATIONRECTANGLE.superclass.constructor.apply(this, [config]);
1009};
1010
1011ANNOTATIONRECTANGLE.NAME = "annotationrectangle";
1012ANNOTATIONRECTANGLE.ATTRS = {};
1013
1014Y.extend(ANNOTATIONRECTANGLE, M.assignfeedback_editpdf.annotation, {
1015 /**
1016 * Draw a rectangle annotation
1017 * @protected
1018 * @method draw
1019 * @return M.assignfeedback_editpdf.drawable
1020 */
3a0bc0fd 1021 draw: function() {
5c386472 1022 var drawable,
557f44d9 1023 bounds,
5c386472
DW
1024 shape;
1025
1026 drawable = new M.assignfeedback_editpdf.drawable(this.editor);
1027
1028 bounds = new M.assignfeedback_editpdf.rect();
1029 bounds.bound([new M.assignfeedback_editpdf.point(this.x, this.y),
1030 new M.assignfeedback_editpdf.point(this.endx, this.endy)]);
1031
1032 shape = this.editor.graphic.addShape({
1033 type: Y.Rect,
1034 width: bounds.width,
1035 height: bounds.height,
1036 stroke: {
1037 weight: STROKEWEIGHT,
1038 color: ANNOTATIONCOLOUR[this.colour]
1039 },
1040 x: bounds.x,
1041 y: bounds.y
1042 });
1043 drawable.shapes.push(shape);
1044 this.drawable = drawable;
1045
1046 return ANNOTATIONRECTANGLE.superclass.draw.apply(this);
1047 },
1048
1049 /**
1050 * Draw the in progress edit.
1051 *
1052 * @public
1053 * @method draw_current_edit
1054 * @param M.assignfeedback_editpdf.edit edit
1055 */
3a0bc0fd 1056 draw_current_edit: function(edit) {
5c386472
DW
1057 var drawable = new M.assignfeedback_editpdf.drawable(this.editor),
1058 shape,
1059 bounds;
1060
1061 bounds = new M.assignfeedback_editpdf.rect();
1062 bounds.bound([new M.assignfeedback_editpdf.point(edit.start.x, edit.start.y),
1063 new M.assignfeedback_editpdf.point(edit.end.x, edit.end.y)]);
1064
baf881b8
RT
1065 // Set min. width and height of rectangle.
1066 if (!bounds.has_min_width()) {
1067 bounds.set_min_width();
1068 }
1069 if (!bounds.has_min_height()) {
1070 bounds.set_min_height();
1071 }
1072
5c386472
DW
1073 shape = this.editor.graphic.addShape({
1074 type: Y.Rect,
1075 width: bounds.width,
1076 height: bounds.height,
1077 stroke: {
1078 weight: STROKEWEIGHT,
1079 color: ANNOTATIONCOLOUR[edit.annotationcolour]
1080 },
1081 x: bounds.x,
1082 y: bounds.y
1083 });
1084
1085 drawable.shapes.push(shape);
1086
1087 return drawable;
1088 }
1089});
1090
1091M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
1092M.assignfeedback_editpdf.annotationrectangle = ANNOTATIONRECTANGLE;
1093// This file is part of Moodle - http://moodle.org/
1094//
1095// Moodle is free software: you can redistribute it and/or modify
1096// it under the terms of the GNU General Public License as published by
1097// the Free Software Foundation, either version 3 of the License, or
1098// (at your option) any later version.
1099//
1100// Moodle is distributed in the hope that it will be useful,
1101// but WITHOUT ANY WARRANTY; without even the implied warranty of
1102// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1103// GNU General Public License for more details.
1104//
1105// You should have received a copy of the GNU General Public License
1106// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
1107
1f777e5c
AN
1108/**
1109 * Provides an in browser PDF editor.
1110 *
1111 * @module moodle-assignfeedback_editpdf-editor
1112 */
1113
5c386472
DW
1114/**
1115 * Class representing a oval.
1116 *
1117 * @namespace M.assignfeedback_editpdf
1118 * @class annotationoval
1f777e5c 1119 * @extends M.assignfeedback_editpdf.annotation
5c386472 1120 */
557f44d9 1121var ANNOTATIONOVAL = function(config) {
5c386472
DW
1122 ANNOTATIONOVAL.superclass.constructor.apply(this, [config]);
1123};
1124
1125ANNOTATIONOVAL.NAME = "annotationoval";
1126ANNOTATIONOVAL.ATTRS = {};
1127
1128Y.extend(ANNOTATIONOVAL, M.assignfeedback_editpdf.annotation, {
1129 /**
1130 * Draw a oval annotation
1131 * @protected
1132 * @method draw
1133 * @return M.assignfeedback_editpdf.drawable
1134 */
3a0bc0fd 1135 draw: function() {
5c386472 1136 var drawable,
557f44d9 1137 bounds,
5c386472
DW
1138 shape;
1139
1140 drawable = new M.assignfeedback_editpdf.drawable(this.editor);
1141
1142 bounds = new M.assignfeedback_editpdf.rect();
1143 bounds.bound([new M.assignfeedback_editpdf.point(this.x, this.y),
1144 new M.assignfeedback_editpdf.point(this.endx, this.endy)]);
1145
1146 shape = this.editor.graphic.addShape({
1147 type: Y.Ellipse,
1148 width: bounds.width,
1149 height: bounds.height,
1150 stroke: {
1151 weight: STROKEWEIGHT,
1152 color: ANNOTATIONCOLOUR[this.colour]
1153 },
1154 x: bounds.x,
1155 y: bounds.y
1156 });
1157 drawable.shapes.push(shape);
1158 this.drawable = drawable;
1159
1160 return ANNOTATIONOVAL.superclass.draw.apply(this);
1161 },
1162
1163 /**
1164 * Draw the in progress edit.
1165 *
1166 * @public
1167 * @method draw_current_edit
1168 * @param M.assignfeedback_editpdf.edit edit
1169 */
3a0bc0fd 1170 draw_current_edit: function(edit) {
5c386472
DW
1171 var drawable = new M.assignfeedback_editpdf.drawable(this.editor),
1172 shape,
1173 bounds;
1174
1175 bounds = new M.assignfeedback_editpdf.rect();
1176 bounds.bound([new M.assignfeedback_editpdf.point(edit.start.x, edit.start.y),
1177 new M.assignfeedback_editpdf.point(edit.end.x, edit.end.y)]);
1178
baf881b8
RT
1179 // Set min. width and height of oval.
1180 if (!bounds.has_min_width()) {
1181 bounds.set_min_width();
1182 }
1183 if (!bounds.has_min_height()) {
1184 bounds.set_min_height();
1185 }
1186
5c386472
DW
1187 shape = this.editor.graphic.addShape({
1188 type: Y.Ellipse,
1189 width: bounds.width,
1190 height: bounds.height,
1191 stroke: {
1192 weight: STROKEWEIGHT,
1193 color: ANNOTATIONCOLOUR[edit.annotationcolour]
1194 },
1195 x: bounds.x,
1196 y: bounds.y
1197 });
1198
1199 drawable.shapes.push(shape);
1200
1201 return drawable;
1202 }
1203});
1204
1205M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
1206M.assignfeedback_editpdf.annotationoval = ANNOTATIONOVAL;
1207// This file is part of Moodle - http://moodle.org/
1208//
1209// Moodle is free software: you can redistribute it and/or modify
1210// it under the terms of the GNU General Public License as published by
1211// the Free Software Foundation, either version 3 of the License, or
1212// (at your option) any later version.
1213//
1214// Moodle is distributed in the hope that it will be useful,
1215// but WITHOUT ANY WARRANTY; without even the implied warranty of
1216// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1217// GNU General Public License for more details.
1218//
1219// You should have received a copy of the GNU General Public License
1220// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
1221
1f777e5c
AN
1222/**
1223 * Provides an in browser PDF editor.
1224 *
1225 * @module moodle-assignfeedback_editpdf-editor
1226 */
1227
5c386472
DW
1228/**
1229 * Class representing a pen.
1230 *
1231 * @namespace M.assignfeedback_editpdf
1232 * @class annotationpen
1f777e5c 1233 * @extends M.assignfeedback_editpdf.annotation
5c386472 1234 */
557f44d9 1235var ANNOTATIONPEN = function(config) {
5c386472
DW
1236 ANNOTATIONPEN.superclass.constructor.apply(this, [config]);
1237};
1238
1239ANNOTATIONPEN.NAME = "annotationpen";
1240ANNOTATIONPEN.ATTRS = {};
1241
1242Y.extend(ANNOTATIONPEN, M.assignfeedback_editpdf.annotation, {
1243 /**
1244 * Draw a pen annotation
1245 * @protected
1246 * @method draw
1247 * @return M.assignfeedback_editpdf.drawable
1248 */
3a0bc0fd 1249 draw: function() {
5c386472
DW
1250 var drawable,
1251 shape,
1252 first,
1253 positions,
1254 xy;
1255
1256 drawable = new M.assignfeedback_editpdf.drawable(this.editor);
1257
1258 shape = this.editor.graphic.addShape({
1259 type: Y.Path,
1260 fill: false,
1261 stroke: {
1262 weight: STROKEWEIGHT,
1263 color: ANNOTATIONCOLOUR[this.colour]
1264 }
1265 });
1266
1267 first = true;
1268 // Recreate the pen path array.
1269 positions = this.path.split(':');
1270 // Redraw all the lines.
1271 Y.each(positions, function(position) {
1272 xy = position.split(',');
1273 if (first) {
1274 shape.moveTo(xy[0], xy[1]);
1275 first = false;
1276 } else {
1277 shape.lineTo(xy[0], xy[1]);
1278 }
1279 }, this);
1280
1281 shape.end();
1282
1283 drawable.shapes.push(shape);
1284 this.drawable = drawable;
1285
1286 return ANNOTATIONPEN.superclass.draw.apply(this);
1287 },
1288
1289 /**
1290 * Draw the in progress edit.
1291 *
1292 * @public
1293 * @method draw_current_edit
1294 * @param M.assignfeedback_editpdf.edit edit
1295 */
3a0bc0fd 1296 draw_current_edit: function(edit) {
5c386472
DW
1297 var drawable = new M.assignfeedback_editpdf.drawable(this.editor),
1298 shape,
1299 first;
1300
1301 shape = this.editor.graphic.addShape({
1302 type: Y.Path,
1303 fill: false,
1304 stroke: {
1305 weight: STROKEWEIGHT,
1306 color: ANNOTATIONCOLOUR[edit.annotationcolour]
1307 }
1308 });
1309
1310 first = true;
1311 // Recreate the pen path array.
1312 // Redraw all the lines.
1313 Y.each(edit.path, function(position) {
1314 if (first) {
1315 shape.moveTo(position.x, position.y);
1316 first = false;
1317 } else {
1318 shape.lineTo(position.x, position.y);
1319 }
1320 }, this);
1321
1322 shape.end();
1323
1324 drawable.shapes.push(shape);
1325
1326 return drawable;
1327 },
1328
1329
1330 /**
1331 * Promote the current edit to a real annotation.
1332 *
1333 * @public
1334 * @method init_from_edit
1335 * @param M.assignfeedback_editpdf.edit edit
baf881b8 1336 * @return bool true if pen bound is more than min width/height, else false.
5c386472 1337 */
3a0bc0fd 1338 init_from_edit: function(edit) {
5c386472
DW
1339 var bounds = new M.assignfeedback_editpdf.rect(),
1340 pathlist = [],
1341 i = 0;
1342
1343 // This will get the boundaries of all points in the path.
1344 bounds.bound(edit.path);
1345
1346 for (i = 0; i < edit.path.length; i++) {
1347 pathlist.push(parseInt(edit.path[i].x, 10) + ',' + parseInt(edit.path[i].y, 10));
1348 }
1349
1350 this.gradeid = this.editor.get('gradeid');
1351 this.pageno = this.editor.currentpage;
1352 this.x = bounds.x;
1353 this.y = bounds.y;
1354 this.endx = bounds.x + bounds.width;
1355 this.endy = bounds.y + bounds.height;
1356 this.colour = edit.annotationcolour;
1357 this.path = pathlist.join(':');
baf881b8
RT
1358
1359 return (bounds.has_min_width() || bounds.has_min_height());
5c386472
DW
1360 }
1361
1362
1363});
1364
1365M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
1366M.assignfeedback_editpdf.annotationpen = ANNOTATIONPEN;
1367// This file is part of Moodle - http://moodle.org/
1368//
1369// Moodle is free software: you can redistribute it and/or modify
1370// it under the terms of the GNU General Public License as published by
1371// the Free Software Foundation, either version 3 of the License, or
1372// (at your option) any later version.
1373//
1374// Moodle is distributed in the hope that it will be useful,
1375// but WITHOUT ANY WARRANTY; without even the implied warranty of
1376// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1377// GNU General Public License for more details.
1378//
1379// You should have received a copy of the GNU General Public License
1380// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
1381
1f777e5c
AN
1382/**
1383 * Provides an in browser PDF editor.
1384 *
1385 * @module moodle-assignfeedback_editpdf-editor
29c5faff 1386*/
1f777e5c 1387
5c386472
DW
1388/**
1389 * Class representing a highlight.
1390 *
1391 * @namespace M.assignfeedback_editpdf
1392 * @class annotationhighlight
1f777e5c 1393 * @extends M.assignfeedback_editpdf.annotation
5c386472
DW
1394 * @module moodle-assignfeedback_editpdf-editor
1395 */
557f44d9 1396var ANNOTATIONHIGHLIGHT = function(config) {
5c386472
DW
1397 ANNOTATIONHIGHLIGHT.superclass.constructor.apply(this, [config]);
1398};
1399
1400ANNOTATIONHIGHLIGHT.NAME = "annotationhighlight";
1401ANNOTATIONHIGHLIGHT.ATTRS = {};
1402
1403Y.extend(ANNOTATIONHIGHLIGHT, M.assignfeedback_editpdf.annotation, {
1404 /**
1405 * Draw a highlight annotation
1406 * @protected
1407 * @method draw
1408 * @return M.assignfeedback_editpdf.drawable
1409 */
3a0bc0fd 1410 draw: function() {
5c386472
DW
1411 var drawable,
1412 shape,
1413 bounds,
1414 highlightcolour;
1415
1416 drawable = new M.assignfeedback_editpdf.drawable(this.editor);
1417 bounds = new M.assignfeedback_editpdf.rect();
1418 bounds.bound([new M.assignfeedback_editpdf.point(this.x, this.y),
1419 new M.assignfeedback_editpdf.point(this.endx, this.endy)]);
1420
1421 highlightcolour = ANNOTATIONCOLOUR[this.colour];
1422
1423 // Add an alpha channel to the rgb colour.
1424
1425 highlightcolour = highlightcolour.replace('rgb', 'rgba');
1426 highlightcolour = highlightcolour.replace(')', ',0.5)');
1427
1428 shape = this.editor.graphic.addShape({
1429 type: Y.Rect,
1430 width: bounds.width,
1431 height: bounds.height,
1432 stroke: false,
1433 fill: {
1434 color: highlightcolour
1435 },
1436 x: bounds.x,
1437 y: bounds.y
1438 });
1439
1440 drawable.shapes.push(shape);
1441 this.drawable = drawable;
1442
1443 return ANNOTATIONHIGHLIGHT.superclass.draw.apply(this);
1444 },
1445
1446 /**
1447 * Draw the in progress edit.
1448 *
1449 * @public
1450 * @method draw_current_edit
1451 * @param M.assignfeedback_editpdf.edit edit
1452 */
3a0bc0fd 1453 draw_current_edit: function(edit) {
5c386472
DW
1454 var drawable = new M.assignfeedback_editpdf.drawable(this.editor),
1455 shape,
1456 bounds,
1457 highlightcolour;
1458
1459 bounds = new M.assignfeedback_editpdf.rect();
1460 bounds.bound([new M.assignfeedback_editpdf.point(edit.start.x, edit.start.y),
1461 new M.assignfeedback_editpdf.point(edit.end.x, edit.end.y)]);
1462
baf881b8
RT
1463 // Set min. width of highlight.
1464 if (!bounds.has_min_width()) {
1465 bounds.set_min_width();
1466 }
1467
5c386472
DW
1468 highlightcolour = ANNOTATIONCOLOUR[edit.annotationcolour];
1469 // Add an alpha channel to the rgb colour.
1470
1471 highlightcolour = highlightcolour.replace('rgb', 'rgba');
1472 highlightcolour = highlightcolour.replace(')', ',0.5)');
1473
1474 // We will draw a box with the current background colour.
1475 shape = this.editor.graphic.addShape({
1476 type: Y.Rect,
1477 width: bounds.width,
166ac972 1478 height: 20,
5c386472
DW
1479 stroke: false,
1480 fill: {
1481 color: highlightcolour
1482 },
1483 x: bounds.x,
166ac972 1484 y: edit.start.y - 10
5c386472
DW
1485 });
1486
1487 drawable.shapes.push(shape);
1488
1489 return drawable;
1490 },
1491
1492 /**
1493 * Promote the current edit to a real annotation.
1494 *
1495 * @public
1496 * @method init_from_edit
1497 * @param M.assignfeedback_editpdf.edit edit
baf881b8 1498 * @return bool true if highlight bound is more than min width/height, else false.
5c386472 1499 */
3a0bc0fd 1500 init_from_edit: function(edit) {
5c386472
DW
1501 var bounds = new M.assignfeedback_editpdf.rect();
1502 bounds.bound([edit.start, edit.end]);
1503
1504 this.gradeid = this.editor.get('gradeid');
1505 this.pageno = this.editor.currentpage;
1506 this.x = bounds.x;
166ac972 1507 this.y = edit.start.y - 10;
5c386472 1508 this.endx = bounds.x + bounds.width;
166ac972 1509 this.endy = edit.start.y + 10;
5c386472
DW
1510 this.colour = edit.annotationcolour;
1511 this.page = '';
baf881b8
RT
1512
1513 return (bounds.has_min_width());
5c386472
DW
1514 }
1515
1516});
1517
1518M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
1519M.assignfeedback_editpdf.annotationhighlight = ANNOTATIONHIGHLIGHT;
1520// This file is part of Moodle - http://moodle.org/
1521//
1522// Moodle is free software: you can redistribute it and/or modify
1523// it under the terms of the GNU General Public License as published by
1524// the Free Software Foundation, either version 3 of the License, or
1525// (at your option) any later version.
1526//
1527// Moodle is distributed in the hope that it will be useful,
1528// but WITHOUT ANY WARRANTY; without even the implied warranty of
1529// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1530// GNU General Public License for more details.
1531//
1532// You should have received a copy of the GNU General Public License
1533// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
1534
1f777e5c
AN
1535/**
1536 * Provides an in browser PDF editor.
1537 *
1538 * @module moodle-assignfeedback_editpdf-editor
1539 */
1540
5c386472
DW
1541/**
1542 * Class representing a stamp.
1543 *
1544 * @namespace M.assignfeedback_editpdf
1545 * @class annotationstamp
1f777e5c 1546 * @extends M.assignfeedback_editpdf.annotation
5c386472 1547 */
557f44d9 1548var ANNOTATIONSTAMP = function(config) {
5c386472
DW
1549 ANNOTATIONSTAMP.superclass.constructor.apply(this, [config]);
1550};
1551
1552ANNOTATIONSTAMP.NAME = "annotationstamp";
1553ANNOTATIONSTAMP.ATTRS = {};
1554
1555Y.extend(ANNOTATIONSTAMP, M.assignfeedback_editpdf.annotation, {
1556 /**
1557 * Draw a stamp annotation
1558 * @protected
1559 * @method draw
1560 * @return M.assignfeedback_editpdf.drawable
1561 */
3a0bc0fd 1562 draw: function() {
5c386472 1563 var drawable = new M.assignfeedback_editpdf.drawable(this.editor),
e349db4b 1564 drawingcanvas = this.editor.get_dialogue_element(SELECTOR.DRAWINGCANVAS),
5c386472
DW
1565 node,
1566 position;
1567
1568 position = this.editor.get_window_coordinates(new M.assignfeedback_editpdf.point(this.x, this.y));
1569 node = Y.Node.create('<div/>');
7be52eb2
AN
1570 node.addClass('annotation');
1571 node.addClass('stamp');
5c386472 1572 node.setStyles({
2269b06c 1573 'position': 'absolute',
5c386472
DW
1574 'display': 'inline-block',
1575 'backgroundImage': 'url(' + this.editor.get_stamp_image_url(this.path) + ')',
1576 'width': (this.endx - this.x),
1577 'height': (this.endy - this.y),
7be52eb2 1578 'backgroundSize': '100% 100%'
5c386472
DW
1579 });
1580
e349db4b 1581 drawingcanvas.append(node);
5c386472
DW
1582 node.setX(position.x);
1583 node.setY(position.y);
50c12f01 1584 drawable.store_position(node, position.x, position.y);
667cec9b
JP
1585
1586 // Bind events only when editing.
1587 if (!this.editor.get('readonly')) {
1588 // Pass through the event handlers on the div.
1589 node.on('gesturemovestart', this.editor.edit_start, null, this.editor);
1590 node.on('gesturemove', this.editor.edit_move, null, this.editor);
1591 node.on('gesturemoveend', this.editor.edit_end, null, this.editor);
1592 }
1593
5c386472
DW
1594 drawable.nodes.push(node);
1595
1596 this.drawable = drawable;
1597 return ANNOTATIONSTAMP.superclass.draw.apply(this);
1598 },
1599
1600 /**
1601 * Draw the in progress edit.
1602 *
1603 * @public
1604 * @method draw_current_edit
1605 * @param M.assignfeedback_editpdf.edit edit
1606 */
3a0bc0fd 1607 draw_current_edit: function(edit) {
5c386472
DW
1608 var bounds = new M.assignfeedback_editpdf.rect(),
1609 drawable = new M.assignfeedback_editpdf.drawable(this.editor),
da91de78 1610 drawingregion = this.editor.get_dialogue_element(SELECTOR.DRAWINGREGION),
5c386472
DW
1611 node,
1612 position;
1613
1614 bounds.bound([edit.start, edit.end]);
1615 position = this.editor.get_window_coordinates(new M.assignfeedback_editpdf.point(bounds.x, bounds.y));
1616
1617 node = Y.Node.create('<div/>');
7be52eb2
AN
1618 node.addClass('annotation');
1619 node.addClass('stamp');
5c386472 1620 node.setStyles({
d79d1bd8 1621 'position': 'absolute',
5c386472
DW
1622 'display': 'inline-block',
1623 'backgroundImage': 'url(' + this.editor.get_stamp_image_url(edit.stamp) + ')',
1624 'width': bounds.width,
1625 'height': bounds.height,
7be52eb2 1626 'backgroundSize': '100% 100%'
5c386472
DW
1627 });
1628
1629 drawingregion.append(node);
1630 node.setX(position.x);
1631 node.setY(position.y);
50c12f01 1632 drawable.store_position(node, position.x, position.y);
5c386472
DW
1633
1634 drawable.nodes.push(node);
1635
1636 return drawable;
1637 },
1638
1639 /**
1640 * Promote the current edit to a real annotation.
1641 *
1642 * @public
1643 * @method init_from_edit
1644 * @param M.assignfeedback_editpdf.edit edit
baf881b8 1645 * @return bool if width/height is more than min. required.
5c386472 1646 */
3a0bc0fd 1647 init_from_edit: function(edit) {
5c386472
DW
1648 var bounds = new M.assignfeedback_editpdf.rect();
1649 bounds.bound([edit.start, edit.end]);
1650
1651 if (bounds.width < 40) {
1652 bounds.width = 40;
1653 }
1654 if (bounds.height < 40) {
1655 bounds.height = 40;
1656 }
1657 this.gradeid = this.editor.get('gradeid');
1658 this.pageno = this.editor.currentpage;
1659 this.x = bounds.x;
1660 this.y = bounds.y;
1661 this.endx = bounds.x + bounds.width;
1662 this.endy = bounds.y + bounds.height;
1663 this.colour = edit.annotationcolour;
1664 this.path = edit.stamp;
baf881b8
RT
1665
1666 // Min width and height is always more than 40px.
1667 return true;
5c386472
DW
1668 },
1669
1670 /**
1671 * Move an annotation to a new location.
1672 * @public
1673 * @param int newx
1674 * @param int newy
1675 * @method move_annotation
1676 */
3a0bc0fd 1677 move: function(newx, newy) {
5c386472
DW
1678 var diffx = newx - this.x,
1679 diffy = newy - this.y;
1680
1681 this.x += diffx;
1682 this.y += diffy;
1683 this.endx += diffx;
1684 this.endy += diffy;
1685
1686 if (this.drawable) {
1687 this.drawable.erase();
1688 }
1689 this.editor.drawables.push(this.draw());
1690 }
1691
1692});
1693
1694M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
1695M.assignfeedback_editpdf.annotationstamp = ANNOTATIONSTAMP;
1696var DROPDOWN_NAME = "Dropdown menu",
1697 DROPDOWN;
1698
1699/**
1f777e5c
AN
1700 * Provides an in browser PDF editor.
1701 *
1702 * @module moodle-assignfeedback_editpdf-editor
1703 */
1704
1705/**
5c386472
DW
1706 * This is a drop down list of buttons triggered (and aligned to) a button.
1707 *
1f777e5c 1708 * @namespace M.assignfeedback_editpdf
5c386472
DW
1709 * @class dropdown
1710 * @constructor
1f777e5c 1711 * @extends M.core.dialogue
5c386472
DW
1712 */
1713DROPDOWN = function(config) {
1714 config.draggable = false;
1715 config.centered = false;
1716 config.width = 'auto';
5c386472 1717 config.visible = false;
5c386472
DW
1718 config.footerContent = '';
1719 DROPDOWN.superclass.constructor.apply(this, [config]);
1720};
1721
1722Y.extend(DROPDOWN, M.core.dialogue, {
1723 /**
1724 * Initialise the menu.
1725 *
1726 * @method initializer
1727 * @return void
1728 */
3a0bc0fd 1729 initializer: function(config) {
5c386472
DW
1730 var button, body, headertext, bb;
1731 DROPDOWN.superclass.initializer.call(this, config);
1732
1733 bb = this.get('boundingBox');
1734 bb.addClass('assignfeedback_editpdf_dropdown');
1735
1736 // Align the menu to the button that opens it.
1737 button = this.get('buttonNode');
1738
1739 // Close the menu when clicked outside (excluding the button that opened the menu).
1740 body = this.bodyNode;
1741
1742 headertext = Y.Node.create('<h3/>');
1743 headertext.addClass('accesshide');
1744 headertext.setHTML(this.get('headerText'));
1745 body.prepend(headertext);
1746
1747 body.on('clickoutside', function(e) {
1748 if (this.get('visible')) {
cf1110eb
DW
1749 // Note: we need to compare ids because for some reason - sometimes button is an Object, not a Y.Node.
1750 if (e.target.get('id') !== button.get('id') && e.target.ancestor().get('id') !== button.get('id')) {
5c386472
DW
1751 e.preventDefault();
1752 this.hide();
1753 }
1754 }
1755 }, this);
1756
3a0bc0fd
DP
1757 button.on('click', function(e) {
1758 e.preventDefault(); this.show();
1759 }, this);
5c386472
DW
1760 button.on('key', this.show, 'enter,space', this);
1761 },
1762
1763 /**
1764 * Override the show method to align to the button.
1765 *
1766 * @method show
1767 * @return void
1768 */
3a0bc0fd 1769 show: function() {
557f44d9
AN
1770 var button = this.get('buttonNode'),
1771 result = DROPDOWN.superclass.show.call(this);
5c386472 1772 this.align(button, [Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.BL]);
557f44d9
AN
1773
1774 return result;
5c386472
DW
1775 }
1776}, {
3a0bc0fd
DP
1777 NAME: DROPDOWN_NAME,
1778 ATTRS: {
5c386472
DW
1779 /**
1780 * The header for the drop down (only accessible to screen readers).
1781 *
1782 * @attribute headerText
1783 * @type String
1784 * @default ''
1785 */
3a0bc0fd
DP
1786 headerText: {
1787 value: ''
5c386472
DW
1788 },
1789
1790 /**
1791 * The button used to show/hide this drop down menu.
1792 *
1793 * @attribute buttonNode
1794 * @type Y.Node
1795 * @default null
1796 */
3a0bc0fd
DP
1797 buttonNode: {
1798 value: null
5c386472
DW
1799 }
1800 }
1801});
1802
5947ab33
AN
1803Y.Base.modifyAttrs(DROPDOWN, {
1804 /**
1805 * Whether the widget should be modal or not.
1806 *
1807 * Moodle override: We override this for commentsearch to force it always false.
1808 *
1809 * @attribute Modal
1810 * @type Boolean
1811 * @default false
1812 */
1813 modal: {
1814 getter: function() {
1815 return false;
1816 }
1817 }
1818});
1819
5c386472
DW
1820M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
1821M.assignfeedback_editpdf.dropdown = DROPDOWN;
1822var COLOURPICKER_NAME = "Colourpicker",
1823 COLOURPICKER;
1824
1f777e5c
AN
1825/**
1826 * Provides an in browser PDF editor.
1827 *
1828 * @module moodle-assignfeedback_editpdf-editor
1829 */
1830
5c386472
DW
1831/**
1832 * COLOURPICKER
1833 * This is a drop down list of colours.
1834 *
1f777e5c
AN
1835 * @namespace M.assignfeedback_editpdf
1836 * @class colourpicker
5c386472 1837 * @constructor
1f777e5c 1838 * @extends M.assignfeedback_editpdf.dropdown
5c386472
DW
1839 */
1840COLOURPICKER = function(config) {
1841 COLOURPICKER.superclass.constructor.apply(this, [config]);
1842};
1843
1844Y.extend(COLOURPICKER, M.assignfeedback_editpdf.dropdown, {
1845
1846 /**
1847 * Initialise the menu.
1848 *
1849 * @method initializer
1850 * @return void
1851 */
3a0bc0fd 1852 initializer: function(config) {
5c386472
DW
1853 var colourlist = Y.Node.create('<ul role="menu" class="assignfeedback_editpdf_menu"/>'),
1854 body;
1855
1856 // Build a list of coloured buttons.
1857 Y.each(this.get('colours'), function(rgb, colour) {
1858 var button, listitem, title, img, iconname;
1859
1860 title = M.util.get_string(colour, 'assignfeedback_editpdf');
1861 iconname = this.get('iconprefix') + colour;
1862 img = M.util.image_url(iconname, 'assignfeedback_editpdf');
1863 button = Y.Node.create('<button><img alt="' + title + '" src="' + img + '"/></button>');
1864 button.setAttribute('data-colour', colour);
1865 button.setAttribute('data-rgb', rgb);
43df3c3f 1866 button.setAttribute('role', 'menuitem');
5c386472
DW
1867 button.setStyle('backgroundImage', 'none');
1868 listitem = Y.Node.create('<li/>');
1869 listitem.append(button);
43df3c3f 1870 listitem.setAttribute('role', 'none');
5c386472
DW
1871 colourlist.append(listitem);
1872 }, this);
1873
1874 body = Y.Node.create('<div/>');
1875
1876 // Set the call back.
1877 colourlist.delegate('click', this.callback_handler, 'button', this);
1878 colourlist.delegate('key', this.callback_handler, 'down:13', 'button', this);
1879
1880 // Set the accessible header text.
1881 this.set('headerText', M.util.get_string('colourpicker', 'assignfeedback_editpdf'));
1882
1883 // Set the body content.
1884 body.append(colourlist);
1885 this.set('bodyContent', body);
1886
1887 COLOURPICKER.superclass.initializer.call(this, config);
1888 },
3a0bc0fd 1889 callback_handler: function(e) {
114913e3
DS
1890 e.preventDefault();
1891
5c386472
DW
1892 var callback = this.get('callback'),
1893 callbackcontext = this.get('context'),
1894 bind;
1895
1896 this.hide();
1897
1898 // Call the callback with the specified context.
1899 bind = Y.bind(callback, callbackcontext, e);
1900
1901 bind();
1902 }
1903}, {
3a0bc0fd
DP
1904 NAME: COLOURPICKER_NAME,
1905 ATTRS: {
5c386472
DW
1906 /**
1907 * The list of colours this colour picker supports.
1908 *
1909 * @attribute colours
1910 * @type {String: String} (The keys of the array are the colour names and the values are localized strings)
1911 * @default {}
1912 */
3a0bc0fd
DP
1913 colours: {
1914 value: {}
5c386472
DW
1915 },
1916
1917 /**
1918 * The function called when a new colour is chosen.
1919 *
1920 * @attribute callback
1921 * @type function
1922 * @default null
1923 */
3a0bc0fd
DP
1924 callback: {
1925 value: null
5c386472
DW
1926 },
1927
1928 /**
1929 * The context passed to the callback when a colour is chosen.
1930 *
1931 * @attribute context
1932 * @type Y.Node
1933 * @default null
1934 */
3a0bc0fd
DP
1935 context: {
1936 value: null
5c386472
DW
1937 },
1938
1939 /**
1940 * The prefix for the icon image names.
1941 *
1942 * @attribute iconprefix
1943 * @type String
1944 * @default 'colour_'
1945 */
3a0bc0fd
DP
1946 iconprefix: {
1947 value: 'colour_'
5c386472
DW
1948 }
1949 }
1950});
1951
1952M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
1953M.assignfeedback_editpdf.colourpicker = COLOURPICKER;
1954var STAMPPICKER_NAME = "Colourpicker",
1955 STAMPPICKER;
1956
1957/**
1f777e5c
AN
1958 * Provides an in browser PDF editor.
1959 *
1960 * @module moodle-assignfeedback_editpdf-editor
1961 */
1962
1963/**
5c386472
DW
1964 * This is a drop down list of stamps.
1965 *
1f777e5c
AN
1966 * @namespace M.assignfeedback_editpdf
1967 * @class stamppicker
5c386472 1968 * @constructor
1f777e5c 1969 * @extends M.assignfeedback_editpdf.dropdown
5c386472
DW
1970 */
1971STAMPPICKER = function(config) {
1972 STAMPPICKER.superclass.constructor.apply(this, [config]);
1973};
1974
1975Y.extend(STAMPPICKER, M.assignfeedback_editpdf.dropdown, {
1976
1977 /**
1978 * Initialise the menu.
1979 *
1980 * @method initializer
1981 * @return void
1982 */
3a0bc0fd 1983 initializer: function(config) {
5c386472
DW
1984 var stamplist = Y.Node.create('<ul role="menu" class="assignfeedback_editpdf_menu"/>');
1985
1986 // Build a list of stamped buttons.
1987 Y.each(this.get('stamps'), function(stamp) {
1988 var button, listitem, title;
1989
1990 title = M.util.get_string('stamp', 'assignfeedback_editpdf');
7abb7c72 1991 button = Y.Node.create('<button><img height="16" width="16" alt="' + title + '" src="' + stamp + '"/></button>');
5c386472 1992 button.setAttribute('data-stamp', stamp);
e1fdd3f7 1993 button.setAttribute('role', 'menuitem');
5c386472
DW
1994 button.setStyle('backgroundImage', 'none');
1995 listitem = Y.Node.create('<li/>');
1996 listitem.append(button);
e1fdd3f7 1997 listitem.setAttribute('role', 'none');
5c386472
DW
1998 stamplist.append(listitem);
1999 }, this);
2000
2001
2002 // Set the call back.
2003 stamplist.delegate('click', this.callback_handler, 'button', this);
2004 stamplist.delegate('key', this.callback_handler, 'down:13', 'button', this);
2005
2006 // Set the accessible header text.
2007 this.set('headerText', M.util.get_string('stamppicker', 'assignfeedback_editpdf'));
2008
2009 // Set the body content.
2010 this.set('bodyContent', stamplist);
2011
2012 STAMPPICKER.superclass.initializer.call(this, config);
2013 },
3a0bc0fd 2014 callback_handler: function(e) {
114913e3 2015 e.preventDefault();
5c386472
DW
2016 var callback = this.get('callback'),
2017 callbackcontext = this.get('context'),
2018 bind;
2019
2020 this.hide();
2021
2022 // Call the callback with the specified context.
2023 bind = Y.bind(callback, callbackcontext, e);
2024
2025 bind();
2026 }
2027}, {
3a0bc0fd
DP
2028 NAME: STAMPPICKER_NAME,
2029 ATTRS: {
5c386472
DW
2030 /**
2031 * The list of stamps this stamp picker supports.
2032 *
2033 * @attribute stamps
2034 * @type String[] - the stamp filenames.
2035 * @default {}
2036 */
3a0bc0fd
DP
2037 stamps: {
2038 value: []
5c386472
DW
2039 },
2040
2041 /**
2042 * The function called when a new stamp is chosen.
2043 *
2044 * @attribute callback
2045 * @type function
2046 * @default null
2047 */
3a0bc0fd
DP
2048 callback: {
2049 value: null
5c386472
DW
2050 },
2051
2052 /**
2053 * The context passed to the callback when a stamp is chosen.
2054 *
2055 * @attribute context
2056 * @type Y.Node
2057 * @default null
2058 */
3a0bc0fd
DP
2059 context: {
2060 value: null
5c386472
DW
2061 }
2062 }
2063});
2064
2065M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
2066M.assignfeedback_editpdf.stamppicker = STAMPPICKER;
2067var COMMENTMENUNAME = "Commentmenu",
2068 COMMENTMENU;
2069
1f777e5c
AN
2070/**
2071 * Provides an in browser PDF editor.
2072 *
2073 * @module moodle-assignfeedback_editpdf-editor
2074 */
2075
5c386472
DW
2076/**
2077 * COMMENTMENU
2078 * This is a drop down list of comment context functions.
2079 *
1f777e5c 2080 * @namespace M.assignfeedback_editpdf
5c386472
DW
2081 * @class commentmenu
2082 * @constructor
1f777e5c 2083 * @extends M.assignfeedback_editpdf.dropdown
5c386472
DW
2084 */
2085COMMENTMENU = function(config) {
2086 COMMENTMENU.superclass.constructor.apply(this, [config]);
2087};
2088
2089Y.extend(COMMENTMENU, M.assignfeedback_editpdf.dropdown, {
2090
2091 /**
2092 * Initialise the menu.
2093 *
2094 * @method initializer
2095 * @return void
2096 */
3a0bc0fd 2097 initializer: function(config) {
5c386472
DW
2098 var commentlinks,
2099 link,
2100 body,
2101 comment;
2102
2103 comment = this.get('comment');
2104 // Build the list of menu items.
2105 commentlinks = Y.Node.create('<ul role="menu" class="assignfeedback_editpdf_menu"/>');
2106
557f44d9
AN
2107 link = Y.Node.create('<li><a tabindex="-1" href="#">' +
2108 M.util.get_string('addtoquicklist', 'assignfeedback_editpdf') +
2109 '</a></li>');
5c386472
DW
2110 link.on('click', comment.add_to_quicklist, comment);
2111 link.on('key', comment.add_to_quicklist, 'enter,space', comment);
2112
2113 commentlinks.append(link);
2114
557f44d9
AN
2115 link = Y.Node.create('<li><a tabindex="-1" href="#">' +
2116 M.util.get_string('deletecomment', 'assignfeedback_editpdf') +
2117 '</a></li>');
3a0bc0fd
DP
2118 link.on('click', function(e) {
2119 e.preventDefault();
2120 this.menu.hide();
2121 this.remove();
2122 }, comment);
2123
2124 link.on('key', function() {
2125 comment.menu.hide();
2126 comment.remove();
2127 }, 'enter,space', comment);
5c386472
DW
2128
2129 commentlinks.append(link);
2130
2131 link = Y.Node.create('<li><hr/></li>');
2132 commentlinks.append(link);
2133
2134 // Set the accessible header text.
2135 this.set('headerText', M.util.get_string('commentcontextmenu', 'assignfeedback_editpdf'));
2136
2137 body = Y.Node.create('<div/>');
2138
2139 // Set the body content.
2140 body.append(commentlinks);
2141 this.set('bodyContent', body);
2142
2143 COMMENTMENU.superclass.initializer.call(this, config);
2144 },
2145
2146 /**
2147 * Show the menu.
2148 *
2149 * @method show
2150 * @return void
2151 */
3a0bc0fd 2152 show: function() {
5c386472 2153 var commentlinks = this.get('boundingBox').one('ul');
557f44d9
AN
2154 commentlinks.all('.quicklist_comment').remove(true);
2155 var comment = this.get('comment');
5c386472 2156
6e67d80d
DS
2157 comment.deleteme = false; // Cancel the deleting of blank comments.
2158
5c386472
DW
2159 // Now build the list of quicklist comments.
2160 Y.each(comment.editor.quicklist.comments, function(quickcomment) {
2161 var listitem = Y.Node.create('<li class="quicklist_comment"></li>'),
2162 linkitem = Y.Node.create('<a href="#" tabindex="-1">' + quickcomment.rawtext + '</a>'),
2163 deletelinkitem = Y.Node.create('<a href="#" tabindex="-1" class="delete_quicklist_comment">' +
2164 '<img src="' + M.util.image_url('t/delete', 'core') + '" ' +
2165 'alt="' + M.util.get_string('deletecomment', 'assignfeedback_editpdf') + '"/>' +
2166 '</a>');
284babb0 2167 linkitem.setAttribute('title', quickcomment.rawtext);
5c386472
DW
2168 listitem.append(linkitem);
2169 listitem.append(deletelinkitem);
2170
2171 commentlinks.append(listitem);
2172
23990a0a
TB
2173 listitem.on('click', comment.set_from_quick_comment, comment, quickcomment);
2174 listitem.on('key', comment.set_from_quick_comment, 'space,enter', comment, quickcomment);
5c386472
DW
2175
2176 deletelinkitem.on('click', comment.remove_from_quicklist, comment, quickcomment);
2177 deletelinkitem.on('key', comment.remove_from_quicklist, 'space,enter', comment, quickcomment);
2178 }, this);
2179
2180 COMMENTMENU.superclass.show.call(this);
2181 }
2182}, {
3a0bc0fd
DP
2183 NAME: COMMENTMENUNAME,
2184 ATTRS: {
5c386472
DW
2185 /**
2186 * The comment this menu is attached to.
2187 *
2188 * @attribute comment
2189 * @type M.assignfeedback_editpdf.comment
2190 * @default null
2191 */
3a0bc0fd
DP
2192 comment: {
2193 value: null
5c386472
DW
2194 }
2195
2196 }
2197});
2198
2199M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
2200M.assignfeedback_editpdf.commentmenu = COMMENTMENU;
ad3f8cd1 2201/* eslint-disable no-unused-vars */
5c386472
DW
2202var COMMENTSEARCHNAME = "commentsearch",
2203 COMMENTSEARCH;
2204
2205/**
1f777e5c
AN
2206 * Provides an in browser PDF editor.
2207 *
2208 * @module moodle-assignfeedback_editpdf-editor
2209 */
2210
2211/**
5c386472
DW
2212 * This is a searchable dialogue of comments.
2213 *
1f777e5c 2214 * @namespace M.assignfeedback_editpdf
5c386472
DW
2215 * @class commentsearch
2216 * @constructor
1f777e5c 2217 * @extends M.core.dialogue
5c386472
DW
2218 */
2219COMMENTSEARCH = function(config) {
2220 config.draggable = false;
2221 config.centered = true;
2222 config.width = '400px';
5c386472
DW
2223 config.visible = false;
2224 config.headerContent = M.util.get_string('searchcomments', 'assignfeedback_editpdf');
5c386472
DW
2225 config.footerContent = '';
2226 COMMENTSEARCH.superclass.constructor.apply(this, [config]);
2227};
2228
2229Y.extend(COMMENTSEARCH, M.core.dialogue, {
2230 /**
2231 * Initialise the menu.
2232 *
2233 * @method initializer
2234 * @return void
2235 */
3a0bc0fd 2236 initializer: function(config) {
5c386472
DW
2237 var editor,
2238 container,
2239 placeholder,
2240 commentfilter,
2241 commentlist,
2242 bb;
2243
2244 bb = this.get('boundingBox');
2245 bb.addClass('assignfeedback_editpdf_commentsearch');
2246
2247 editor = this.get('editor');
2248 container = Y.Node.create('<div/>');
2249
2250 placeholder = M.util.get_string('filter', 'assignfeedback_editpdf');
2251 commentfilter = Y.Node.create('<input type="text" size="20" placeholder="' + placeholder + '"/>');
2252 container.append(commentfilter);
d9f730fd 2253 commentlist = Y.Node.create('<ul role="menu" class="assignfeedback_editpdf_search"/>');
5c386472
DW
2254 container.append(commentlist);
2255
402f4a1f 2256 commentfilter.on('keyup', this.filter_search_comments, this);
5c386472
DW
2257 commentlist.delegate('click', this.focus_on_comment, 'a', this);
2258 commentlist.delegate('key', this.focus_on_comment, 'enter,space', 'a', this);
2259
2260 // Set the body content.
2261 this.set('bodyContent', container);
2262
2263 COMMENTSEARCH.superclass.initializer.call(this, config);
2264 },
2265
2266 /**
2267 * Event handler to filter the list of comments.
2268 *
2269 * @protected
2270 * @method filter_search_comments
2271 */
3a0bc0fd 2272 filter_search_comments: function() {
5c386472
DW
2273 var filternode,
2274 commentslist,
c181efe9
DM
2275 filtertext,
2276 dialogueid;
5c386472 2277
c181efe9
DM
2278 dialogueid = this.get('id');
2279 filternode = Y.one('#' + dialogueid + SELECTOR.SEARCHFILTER);
2280 commentslist = Y.one('#' + dialogueid + SELECTOR.SEARCHCOMMENTSLIST);
5c386472
DW
2281
2282 filtertext = filternode.get('value');
2283
3a0bc0fd 2284 commentslist.all('li').each(function(node) {
5c386472
DW
2285 if (node.get('text').indexOf(filtertext) !== -1) {
2286 node.show();
2287 } else {
2288 node.hide();
2289 }
2290 });
2291 },
2292
2293 /**
2294 * Event handler to focus on a selected comment.
2295 *
2296 * @param Event e
2297 * @protected
2298 * @method focus_on_comment
2299 */
3a0bc0fd 2300 focus_on_comment: function(e) {
114913e3 2301 e.preventDefault();
5c386472
DW
2302 var target = e.target.ancestor('li'),
2303 comment = target.getData('comment'),
05aa787b 2304 editor = this.get('editor');
5c386472
DW
2305
2306 this.hide();
2307
23990a0a
TB
2308 comment.pageno = comment.clean().pageno;
2309 if (comment.pageno !== editor.currentpage) {
5c386472
DW
2310 // Comment is on a different page.
2311 editor.currentpage = comment.pageno;
2312 editor.change_page();
5c386472 2313 }
23990a0a
TB
2314
2315 comment.node = comment.drawable.nodes[0].one('textarea');
2316 comment.node.ancestor('div').removeClass('commentcollapsed');
2317 comment.node.focus();
5c386472
DW
2318 },
2319
2320 /**
2321 * Show the menu.
2322 *
2323 * @method show
2324 * @return void
2325 */
3a0bc0fd 2326 show: function() {
5c386472
DW
2327 var commentlist = this.get('boundingBox').one('ul'),
2328 editor = this.get('editor');
2329
2330 commentlist.all('li').remove(true);
2331
2332 // Rebuild the latest list of comments.
2333 Y.each(editor.pages, function(page) {
2334 Y.each(page.comments, function(comment) {
2335 var commentnode = Y.Node.create('<li><a href="#" tabindex="-1"><pre>' + comment.rawtext + '</pre></a></li>');
2336 commentlist.append(commentnode);
2337 commentnode.setData('comment', comment);
2338 }, this);
2339 }, this);
2340
2341 this.centerDialogue();
2342 COMMENTSEARCH.superclass.show.call(this);
2343 }
2344}, {
3a0bc0fd
DP
2345 NAME: COMMENTSEARCHNAME,
2346 ATTRS: {
5c386472
DW
2347 /**
2348 * The editor this search window is attached to.
2349 *
2350 * @attribute editor
2351 * @type M.assignfeedback_editpdf.editor
2352 * @default null
2353 */
3a0bc0fd
DP
2354 editor: {
2355 value: null
5c386472
DW
2356 }
2357
2358 }
2359});
2360
5947ab33
AN
2361Y.Base.modifyAttrs(COMMENTSEARCH, {
2362 /**
2363 * Whether the widget should be modal or not.
2364 *
2365 * Moodle override: We override this for commentsearch to force it always true.
2366 *
2367 * @attribute Modal
2368 * @type Boolean
2369 * @default true
2370 */
2371 modal: {
2372 getter: function() {
2373 return true;
2374 }
2375 }
2376});
2377
5c386472
DW
2378M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
2379M.assignfeedback_editpdf.commentsearch = COMMENTSEARCH;
2380// This file is part of Moodle - http://moodle.org/
2381//
2382// Moodle is free software: you can redistribute it and/or modify
2383// it under the terms of the GNU General Public License as published by
2384// the Free Software Foundation, either version 3 of the License, or
2385// (at your option) any later version.
2386//
2387// Moodle is distributed in the hope that it will be useful,
2388// but WITHOUT ANY WARRANTY; without even the implied warranty of
2389// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2390// GNU General Public License for more details.
2391//
2392// You should have received a copy of the GNU General Public License
2393// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
2394
2395/**
1f777e5c 2396 * Provides an in browser PDF editor.
5c386472
DW
2397 *
2398 * @module moodle-assignfeedback_editpdf-editor
2399 */
2400
2401/**
1f777e5c 2402 * Class representing a list of comments.
5c386472
DW
2403 *
2404 * @namespace M.assignfeedback_editpdf
2405 * @class comment
2406 * @param M.assignfeedback_editpdf.editor editor
2407 * @param Int gradeid
2408 * @param Int pageno
2409 * @param Int x
2410 * @param Int y
2411 * @param Int width
2412 * @param String colour
2413 * @param String rawtext
2414 */
557f44d9 2415var COMMENT = function(editor, gradeid, pageno, x, y, width, colour, rawtext) {
5c386472
DW
2416
2417 /**
2418 * Reference to M.assignfeedback_editpdf.editor.
2419 * @property editor
2420 * @type M.assignfeedback_editpdf.editor
2421 * @public
2422 */
2423 this.editor = editor;
2424
2425 /**
2426 * Grade id
2427 * @property gradeid
2428 * @type Int
2429 * @public
2430 */
2431 this.gradeid = gradeid || 0;
2432
2433 /**
2434 * X position
2435 * @property x
2436 * @type Int
2437 * @public
2438 */
2439 this.x = parseInt(x, 10) || 0;
2440
2441 /**
2442 * Y position
2443 * @property y
2444 * @type Int
2445 * @public
2446 */
2447 this.y = parseInt(y, 10) || 0;
2448
2449 /**
2450 * Comment width
2451 * @property width
2452 * @type Int
2453 * @public
2454 */
2455 this.width = parseInt(width, 10) || 0;
2456
2457 /**
2458 * Comment rawtext
2459 * @property rawtext
2460 * @type String
2461 * @public
2462 */
2463 this.rawtext = rawtext || '';
2464
2465 /**
2466 * Comment page number
2467 * @property pageno
2468 * @type Int
2469 * @public
2470 */
2471 this.pageno = pageno || 0;
2472
2473 /**
2474 * Comment background colour.
2475 * @property colour
2476 * @type String
2477 * @public
2478 */
2479 this.colour = colour || 'yellow';
2480
2481 /**
2482 * Reference to M.assignfeedback_editpdf.drawable
2483 * @property drawable
2484 * @type M.assignfeedback_editpdf.drawable
2485 * @public
2486 */
2487 this.drawable = false;
2488
2489 /**
2490 * Boolean used by a timeout to delete empty comments after a short delay.
2491 * @property deleteme
2492 * @type Boolean
2493 * @public
2494 */
2495 this.deleteme = false;
2496
2497 /**
2498 * Reference to the link that opens the menu.
2499 * @property menulink
2500 * @type Y.Node
2501 * @public
2502 */
2503 this.menulink = null;
2504
2505 /**
2506 * Reference to the dialogue that is the context menu.
2507 * @property menu
2508 * @type M.assignfeedback_editpdf.dropdown
2509 * @public
2510 */
2511 this.menu = null;
2512
2513 /**
2514 * Clean a comment record, returning an oject with only fields that are valid.
2515 * @public
2516 * @method clean
2517 * @return {}
2518 */
2519 this.clean = function() {
2520 return {
3a0bc0fd
DP
2521 gradeid: this.gradeid,
2522 x: parseInt(this.x, 10),
2523 y: parseInt(this.y, 10),
2524 width: parseInt(this.width, 10),
2525 rawtext: this.rawtext,
23990a0a 2526 pageno: parseInt(this.pageno, 10),
3a0bc0fd 2527 colour: this.colour
5c386472
DW
2528 };
2529 };
2530
2531 /**
2532 * Draw a comment.
2533 * @public
2534 * @method draw_comment
2535 * @param boolean focus - Set the keyboard focus to the new comment if true
2536 * @return M.assignfeedback_editpdf.drawable
2537 */
2538 this.draw = function(focus) {
2539 var drawable = new M.assignfeedback_editpdf.drawable(this.editor),
2540 node,
e349db4b 2541 drawingcanvas = this.editor.get_dialogue_element(SELECTOR.DRAWINGCANVAS),
5c386472 2542 container,
23990a0a
TB
2543 label,
2544 marker,
5c386472
DW
2545 menu,
2546 position,
2547 scrollheight;
2548
2549 // Lets add a contenteditable div.
2550 node = Y.Node.create('<textarea/>');
2551 container = Y.Node.create('<div class="commentdrawable"/>');
23990a0a
TB
2552 label = Y.Node.create('<label/>');
2553 marker = Y.Node.create('<svg xmlns="http://www.w3.org/2000/svg" viewBox="-0.5 -0.5 13 13" ' +
2554 'preserveAspectRatio="xMinYMin meet">' +
2555 '<path d="M11 0H1C.4 0 0 .4 0 1v6c0 .6.4 1 1 1h1v4l4-4h5c.6 0 1-.4 1-1V1c0-.6-.4-1-1-1z" ' +
2556 'fill="currentColor" opacity="0.9" stroke="rgb(153, 153, 153)" stroke-width="0.5"/></svg>');
5c386472
DW
2557 menu = Y.Node.create('<a href="#"><img src="' + M.util.image_url('t/contextmenu', 'core') + '"/></a>');
2558
2559 this.menulink = menu;
23990a0a
TB
2560 container.append(label);
2561 label.append(node);
2562 container.append(marker);
2563 container.setAttribute('tabindex', '-1');
2564 label.setAttribute('tabindex', '0');
2565 node.setAttribute('tabindex', '-1');
e082fbd9 2566 menu.setAttribute('tabindex', '0');
5c386472
DW
2567
2568 if (!this.editor.get('readonly')) {
2569 container.append(menu);
2570 } else {
2571 node.setAttribute('readonly', 'readonly');
2572 }
2573 if (this.width < 100) {
2574 this.width = 100;
2575 }
2576
2577 position = this.editor.get_window_coordinates(new M.assignfeedback_editpdf.point(this.x, this.y));
2578 node.setStyles({
2579 width: this.width + 'px',
1d38083c
DW
2580 backgroundColor: COMMENTCOLOUR[this.colour],
2581 color: COMMENTTEXTCOLOUR
5c386472
DW
2582 });
2583
e349db4b 2584 drawingcanvas.append(container);
2269b06c 2585 container.setStyle('position', 'absolute');
5c386472
DW
2586 container.setX(position.x);
2587 container.setY(position.y);
50c12f01 2588 drawable.store_position(container, position.x, position.y);
5c386472
DW
2589 drawable.nodes.push(container);
2590 node.set('value', this.rawtext);
8b766dd1 2591 scrollheight = node.get('scrollHeight');
5c386472 2592 node.setStyles({
3a0bc0fd 2593 'height': scrollheight + 'px',
5c386472
DW
2594 'overflow': 'hidden'
2595 });
ad7c719d 2596 marker.setStyle('color', COMMENTCOLOUR[this.colour]);
23990a0a 2597 this.attach_events(node, menu);
5c386472
DW
2598 if (focus) {
2599 node.focus();
23990a0a
TB
2600 } else if (editor.collapsecomments) {
2601 container.addClass('commentcollapsed');
5c386472
DW
2602 }
2603 this.drawable = drawable;
2604
2605
2606 return drawable;
2607 };
2608
2609 /**
2610 * Delete an empty comment if it's menu hasn't been opened in time.
2611 * @method delete_comment_later
2612 */
2613 this.delete_comment_later = function() {