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