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