MDL-55244 js: fix various lint warnings in yui
[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
DW
26 CSS = {
27 DIALOGUE : 'assignfeedback_editpdf_widget'
28 },
29 SELECTOR = {
da91de78
BL
30 PREVIOUSBUTTON : '.navigate-previous-button',
31 NEXTBUTTON : ' .navigate-next-button',
32 SEARCHCOMMENTSBUTTON : '.searchcommentsbutton',
5c386472
DW
33 SEARCHFILTER : '.assignfeedback_editpdf_commentsearch input',
34 SEARCHCOMMENTSLIST : '.assignfeedback_editpdf_commentsearch ul',
da91de78
BL
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',
5c386472 45 UNSAVEDCHANGESDIV : '.assignfeedback_editpdf_unsavedchanges',
bb690849 46 UNSAVEDCHANGESINPUT : 'input[name="assignfeedback_editpdf_haschanges"]',
da91de78 47 STAMPSBUTTON : '.currentstampbutton',
5c386472
DW
48 DIALOGUE : '.' + CSS.DIALOGUE
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
DW
53 COMMENTCOLOUR = {
54 'white' : 'rgb(255,255,255)',
1d38083c
DW
55 'yellow' : 'rgb(255,236,174)',
56 'red' : 'rgb(249,181,179)',
57 'green' : 'rgb(214,234,178)',
58 'blue' : 'rgb(203,217,237)',
5c386472
DW
59 'clear' : 'rgba(255,255,255, 0)'
60 },
61 ANNOTATIONCOLOUR = {
62 'white' : 'rgb(255,255,255)',
1d38083c
DW
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 */
558 editor : null,
559
560 /**
561 * Grade id
562 * @property gradeid
563 * @type Int
564 * @public
565 */
566 gradeid : 0,
567
568 /**
569 * Comment page number
570 * @property pageno
571 * @type Int
572 * @public
573 */
574 pageno : 0,
575
576 /**
577 * X position
578 * @property x
579 * @type Int
580 * @public
581 */
582 x : 0,
583
584 /**
585 * Y position
586 * @property y
587 * @type Int
588 * @public
589 */
590 y : 0,
591
592 /**
593 * Ending x position
594 * @property endx
595 * @type Int
596 * @public
597 */
598 endx : 0,
599
600 /**
601 * Ending y position
602 * @property endy
603 * @type Int
604 * @public
605 */
606 endy : 0,
607
608 /**
609 * Path
610 * @property path
611 * @type String - list of points like x1,y1:x2,y2
612 * @public
613 */
614 path : '',
615
616 /**
617 * Tool.
618 * @property type
619 * @type String
620 * @public
621 */
622 type : 'rect',
623
624 /**
625 * Annotation colour.
626 * @property colour
627 * @type String
628 * @public
629 */
630 colour : 'red',
631
632 /**
633 * Reference to M.assignfeedback_editpdf.drawable
634 * @property drawable
635 * @type M.assignfeedback_editpdf.drawable
636 * @public
637 */
638 drawable : false,
639
640 /**
641 * Initialise the annotation.
642 *
643 * @method initializer
644 * @return void
645 */
646 initializer : function(config) {
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 */
666 clean : function() {
667 return {
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
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 */
686 draw_highlight : function() {
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({
722 'backgroundColor' : 'white'
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 */
747 draw : function() {
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 */
114913e3 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 */
786 move : function(newx, newy) {
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 */
823 draw_current_edit : function(edit) {
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
DW
836 */
837 init_from_edit : function(edit) {
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 */
899 draw : function() {
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 */
930 draw_current_edit : function(edit) {
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
DW
959 */
960 init_from_edit : function(edit) {
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 */
1020 draw : function() {
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 */
1055 draw_current_edit : function(edit) {
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 */
1135 draw : function() {
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 */
1170 draw_current_edit : function(edit) {
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 */
1250 draw : function() {
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 */
1297 draw_current_edit : function(edit) {
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
DW
1338 */
1339 init_from_edit : function(edit) {
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 */
1412 draw : function() {
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 */
1455 draw_current_edit : function(edit) {
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
DW
1501 */
1502 init_from_edit : function(edit) {
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 */
1565 draw : function() {
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 */
1609 draw_current_edit : function(edit) {
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
DW
1647 */
1648 init_from_edit : function(edit) {
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 */
1678 move : function(newx, newy) {
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 */
1730 initializer : function(config) {
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
114913e3 1758 button.on('click', function(e) {e.preventDefault(); this.show();}, this);
5c386472
DW
1759 button.on('key', this.show, 'enter,space', this);
1760 },
1761
1762 /**
1763 * Override the show method to align to the button.
1764 *
1765 * @method show
1766 * @return void
1767 */
1768 show : function() {
557f44d9
AN
1769 var button = this.get('buttonNode'),
1770 result = DROPDOWN.superclass.show.call(this);
5c386472 1771 this.align(button, [Y.WidgetPositionAlign.TL, Y.WidgetPositionAlign.BL]);
557f44d9
AN
1772
1773 return result;
5c386472
DW
1774 }
1775}, {
1776 NAME : DROPDOWN_NAME,
1777 ATTRS : {
1778 /**
1779 * The header for the drop down (only accessible to screen readers).
1780 *
1781 * @attribute headerText
1782 * @type String
1783 * @default ''
1784 */
1785 headerText : {
1786 value : ''
1787 },
1788
1789 /**
1790 * The button used to show/hide this drop down menu.
1791 *
1792 * @attribute buttonNode
1793 * @type Y.Node
1794 * @default null
1795 */
1796 buttonNode : {
1797 value : null
1798 }
1799 }
1800});
1801
5947ab33
AN
1802Y.Base.modifyAttrs(DROPDOWN, {
1803 /**
1804 * Whether the widget should be modal or not.
1805 *
1806 * Moodle override: We override this for commentsearch to force it always false.
1807 *
1808 * @attribute Modal
1809 * @type Boolean
1810 * @default false
1811 */
1812 modal: {
1813 getter: function() {
1814 return false;
1815 }
1816 }
1817});
1818
5c386472
DW
1819M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
1820M.assignfeedback_editpdf.dropdown = DROPDOWN;
1821var COLOURPICKER_NAME = "Colourpicker",
1822 COLOURPICKER;
1823
1f777e5c
AN
1824/**
1825 * Provides an in browser PDF editor.
1826 *
1827 * @module moodle-assignfeedback_editpdf-editor
1828 */
1829
5c386472
DW
1830/**
1831 * COLOURPICKER
1832 * This is a drop down list of colours.
1833 *
1f777e5c
AN
1834 * @namespace M.assignfeedback_editpdf
1835 * @class colourpicker
5c386472 1836 * @constructor
1f777e5c 1837 * @extends M.assignfeedback_editpdf.dropdown
5c386472
DW
1838 */
1839COLOURPICKER = function(config) {
1840 COLOURPICKER.superclass.constructor.apply(this, [config]);
1841};
1842
1843Y.extend(COLOURPICKER, M.assignfeedback_editpdf.dropdown, {
1844
1845 /**
1846 * Initialise the menu.
1847 *
1848 * @method initializer
1849 * @return void
1850 */
1851 initializer : function(config) {
1852 var colourlist = Y.Node.create('<ul role="menu" class="assignfeedback_editpdf_menu"/>'),
1853 body;
1854
1855 // Build a list of coloured buttons.
1856 Y.each(this.get('colours'), function(rgb, colour) {
1857 var button, listitem, title, img, iconname;
1858
1859 title = M.util.get_string(colour, 'assignfeedback_editpdf');
1860 iconname = this.get('iconprefix') + colour;
1861 img = M.util.image_url(iconname, 'assignfeedback_editpdf');
1862 button = Y.Node.create('<button><img alt="' + title + '" src="' + img + '"/></button>');
1863 button.setAttribute('data-colour', colour);
1864 button.setAttribute('data-rgb', rgb);
1865 button.setStyle('backgroundImage', 'none');
1866 listitem = Y.Node.create('<li/>');
1867 listitem.append(button);
1868 colourlist.append(listitem);
1869 }, this);
1870
1871 body = Y.Node.create('<div/>');
1872
1873 // Set the call back.
1874 colourlist.delegate('click', this.callback_handler, 'button', this);
1875 colourlist.delegate('key', this.callback_handler, 'down:13', 'button', this);
1876
1877 // Set the accessible header text.
1878 this.set('headerText', M.util.get_string('colourpicker', 'assignfeedback_editpdf'));
1879
1880 // Set the body content.
1881 body.append(colourlist);
1882 this.set('bodyContent', body);
1883
1884 COLOURPICKER.superclass.initializer.call(this, config);
1885 },
1886 callback_handler : function(e) {
114913e3
DS
1887 e.preventDefault();
1888
5c386472
DW
1889 var callback = this.get('callback'),
1890 callbackcontext = this.get('context'),
1891 bind;
1892
1893 this.hide();
1894
1895 // Call the callback with the specified context.
1896 bind = Y.bind(callback, callbackcontext, e);
1897
1898 bind();
1899 }
1900}, {
1901 NAME : COLOURPICKER_NAME,
1902 ATTRS : {
1903 /**
1904 * The list of colours this colour picker supports.
1905 *
1906 * @attribute colours
1907 * @type {String: String} (The keys of the array are the colour names and the values are localized strings)
1908 * @default {}
1909 */
1910 colours : {
1911 value : {}
1912 },
1913
1914 /**
1915 * The function called when a new colour is chosen.
1916 *
1917 * @attribute callback
1918 * @type function
1919 * @default null
1920 */
1921 callback : {
1922 value : null
1923 },
1924
1925 /**
1926 * The context passed to the callback when a colour is chosen.
1927 *
1928 * @attribute context
1929 * @type Y.Node
1930 * @default null
1931 */
1932 context : {
1933 value : null
1934 },
1935
1936 /**
1937 * The prefix for the icon image names.
1938 *
1939 * @attribute iconprefix
1940 * @type String
1941 * @default 'colour_'
1942 */
1943 iconprefix : {
1944 value : 'colour_'
1945 }
1946 }
1947});
1948
1949M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
1950M.assignfeedback_editpdf.colourpicker = COLOURPICKER;
1951var STAMPPICKER_NAME = "Colourpicker",
1952 STAMPPICKER;
1953
1954/**
1f777e5c
AN
1955 * Provides an in browser PDF editor.
1956 *
1957 * @module moodle-assignfeedback_editpdf-editor
1958 */
1959
1960/**
5c386472
DW
1961 * This is a drop down list of stamps.
1962 *
1f777e5c
AN
1963 * @namespace M.assignfeedback_editpdf
1964 * @class stamppicker
5c386472 1965 * @constructor
1f777e5c 1966 * @extends M.assignfeedback_editpdf.dropdown
5c386472
DW
1967 */
1968STAMPPICKER = function(config) {
1969 STAMPPICKER.superclass.constructor.apply(this, [config]);
1970};
1971
1972Y.extend(STAMPPICKER, M.assignfeedback_editpdf.dropdown, {
1973
1974 /**
1975 * Initialise the menu.
1976 *
1977 * @method initializer
1978 * @return void
1979 */
1980 initializer : function(config) {
1981 var stamplist = Y.Node.create('<ul role="menu" class="assignfeedback_editpdf_menu"/>');
1982
1983 // Build a list of stamped buttons.
1984 Y.each(this.get('stamps'), function(stamp) {
1985 var button, listitem, title;
1986
1987 title = M.util.get_string('stamp', 'assignfeedback_editpdf');
7abb7c72 1988 button = Y.Node.create('<button><img height="16" width="16" alt="' + title + '" src="' + stamp + '"/></button>');
5c386472
DW
1989 button.setAttribute('data-stamp', stamp);
1990 button.setStyle('backgroundImage', 'none');
1991 listitem = Y.Node.create('<li/>');
1992 listitem.append(button);
1993 stamplist.append(listitem);
1994 }, this);
1995
1996
1997 // Set the call back.
1998 stamplist.delegate('click', this.callback_handler, 'button', this);
1999 stamplist.delegate('key', this.callback_handler, 'down:13', 'button', this);
2000
2001 // Set the accessible header text.
2002 this.set('headerText', M.util.get_string('stamppicker', 'assignfeedback_editpdf'));
2003
2004 // Set the body content.
2005 this.set('bodyContent', stamplist);
2006
2007 STAMPPICKER.superclass.initializer.call(this, config);
2008 },
2009 callback_handler : function(e) {
114913e3 2010 e.preventDefault();
5c386472
DW
2011 var callback = this.get('callback'),
2012 callbackcontext = this.get('context'),
2013 bind;
2014
2015 this.hide();
2016
2017 // Call the callback with the specified context.
2018 bind = Y.bind(callback, callbackcontext, e);
2019
2020 bind();
2021 }
2022}, {
2023 NAME : STAMPPICKER_NAME,
2024 ATTRS : {
2025 /**
2026 * The list of stamps this stamp picker supports.
2027 *
2028 * @attribute stamps
2029 * @type String[] - the stamp filenames.
2030 * @default {}
2031 */
2032 stamps : {
2033 value : []
2034 },
2035
2036 /**
2037 * The function called when a new stamp is chosen.
2038 *
2039 * @attribute callback
2040 * @type function
2041 * @default null
2042 */
2043 callback : {
2044 value : null
2045 },
2046
2047 /**
2048 * The context passed to the callback when a stamp is chosen.
2049 *
2050 * @attribute context
2051 * @type Y.Node
2052 * @default null
2053 */
2054 context : {
2055 value : null
2056 }
2057 }
2058});
2059
2060M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
2061M.assignfeedback_editpdf.stamppicker = STAMPPICKER;
2062var COMMENTMENUNAME = "Commentmenu",
2063 COMMENTMENU;
2064
1f777e5c
AN
2065/**
2066 * Provides an in browser PDF editor.
2067 *
2068 * @module moodle-assignfeedback_editpdf-editor
2069 */
2070
5c386472
DW
2071/**
2072 * COMMENTMENU
2073 * This is a drop down list of comment context functions.
2074 *
1f777e5c 2075 * @namespace M.assignfeedback_editpdf
5c386472
DW
2076 * @class commentmenu
2077 * @constructor
1f777e5c 2078 * @extends M.assignfeedback_editpdf.dropdown
5c386472
DW
2079 */
2080COMMENTMENU = function(config) {
2081 COMMENTMENU.superclass.constructor.apply(this, [config]);
2082};
2083
2084Y.extend(COMMENTMENU, M.assignfeedback_editpdf.dropdown, {
2085
2086 /**
2087 * Initialise the menu.
2088 *
2089 * @method initializer
2090 * @return void
2091 */
2092 initializer : function(config) {
2093 var commentlinks,
2094 link,
2095 body,
2096 comment;
2097
2098 comment = this.get('comment');
2099 // Build the list of menu items.
2100 commentlinks = Y.Node.create('<ul role="menu" class="assignfeedback_editpdf_menu"/>');
2101
557f44d9
AN
2102 link = Y.Node.create('<li><a tabindex="-1" href="#">' +
2103 M.util.get_string('addtoquicklist', 'assignfeedback_editpdf') +
2104 '</a></li>');
5c386472
DW
2105 link.on('click', comment.add_to_quicklist, comment);
2106 link.on('key', comment.add_to_quicklist, 'enter,space', comment);
2107
2108 commentlinks.append(link);
2109
557f44d9
AN
2110 link = Y.Node.create('<li><a tabindex="-1" href="#">' +
2111 M.util.get_string('deletecomment', 'assignfeedback_editpdf') +
2112 '</a></li>');
114913e3 2113 link.on('click', function(e) { e.preventDefault(); this.menu.hide(); this.remove(); }, comment);
5c386472
DW
2114 link.on('key', function() { comment.menu.hide(); comment.remove(); }, 'enter,space', comment);
2115
2116 commentlinks.append(link);
2117
2118 link = Y.Node.create('<li><hr/></li>');
2119 commentlinks.append(link);
2120
2121 // Set the accessible header text.
2122 this.set('headerText', M.util.get_string('commentcontextmenu', 'assignfeedback_editpdf'));
2123
2124 body = Y.Node.create('<div/>');
2125
2126 // Set the body content.
2127 body.append(commentlinks);
2128 this.set('bodyContent', body);
2129
2130 COMMENTMENU.superclass.initializer.call(this, config);
2131 },
2132
2133 /**
2134 * Show the menu.
2135 *
2136 * @method show
2137 * @return void
2138 */
2139 show : function() {
2140 var commentlinks = this.get('boundingBox').one('ul');
557f44d9
AN
2141 commentlinks.all('.quicklist_comment').remove(true);
2142 var comment = this.get('comment');
5c386472 2143
6e67d80d
DS
2144 comment.deleteme = false; // Cancel the deleting of blank comments.
2145
5c386472
DW
2146 // Now build the list of quicklist comments.
2147 Y.each(comment.editor.quicklist.comments, function(quickcomment) {
2148 var listitem = Y.Node.create('<li class="quicklist_comment"></li>'),
2149 linkitem = Y.Node.create('<a href="#" tabindex="-1">' + quickcomment.rawtext + '</a>'),
2150 deletelinkitem = Y.Node.create('<a href="#" tabindex="-1" class="delete_quicklist_comment">' +
2151 '<img src="' + M.util.image_url('t/delete', 'core') + '" ' +
2152 'alt="' + M.util.get_string('deletecomment', 'assignfeedback_editpdf') + '"/>' +
2153 '</a>');
2154 listitem.append(linkitem);
2155 listitem.append(deletelinkitem);
2156
2157 commentlinks.append(listitem);
2158
2159 linkitem.on('click', comment.set_from_quick_comment, comment, quickcomment);
2160 linkitem.on('key', comment.set_from_quick_comment, 'space,enter', comment, quickcomment);
2161
2162 deletelinkitem.on('click', comment.remove_from_quicklist, comment, quickcomment);
2163 deletelinkitem.on('key', comment.remove_from_quicklist, 'space,enter', comment, quickcomment);
2164 }, this);
2165
2166 COMMENTMENU.superclass.show.call(this);
2167 }
2168}, {
2169 NAME : COMMENTMENUNAME,
2170 ATTRS : {
2171 /**
2172 * The comment this menu is attached to.
2173 *
2174 * @attribute comment
2175 * @type M.assignfeedback_editpdf.comment
2176 * @default null
2177 */
2178 comment : {
2179 value : null
2180 }
2181
2182 }
2183});
2184
2185M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
2186M.assignfeedback_editpdf.commentmenu = COMMENTMENU;
ad3f8cd1
DP
2187/* eslint-disable no-unused-vars */
2188/* global SELECTOR */
5c386472
DW
2189var COMMENTSEARCHNAME = "commentsearch",
2190 COMMENTSEARCH;
2191
2192/**
1f777e5c
AN
2193 * Provides an in browser PDF editor.
2194 *
2195 * @module moodle-assignfeedback_editpdf-editor
2196 */
2197
2198/**
5c386472
DW
2199 * This is a searchable dialogue of comments.
2200 *
1f777e5c 2201 * @namespace M.assignfeedback_editpdf
5c386472
DW
2202 * @class commentsearch
2203 * @constructor
1f777e5c 2204 * @extends M.core.dialogue
5c386472
DW
2205 */
2206COMMENTSEARCH = function(config) {
2207 config.draggable = false;
2208 config.centered = true;
2209 config.width = '400px';
5c386472
DW
2210 config.visible = false;
2211 config.headerContent = M.util.get_string('searchcomments', 'assignfeedback_editpdf');
5c386472
DW
2212 config.footerContent = '';
2213 COMMENTSEARCH.superclass.constructor.apply(this, [config]);
2214};
2215
2216Y.extend(COMMENTSEARCH, M.core.dialogue, {
2217 /**
2218 * Initialise the menu.
2219 *
2220 * @method initializer
2221 * @return void
2222 */
2223 initializer : function(config) {
2224 var editor,
2225 container,
2226 placeholder,
2227 commentfilter,
2228 commentlist,
2229 bb;
2230
2231 bb = this.get('boundingBox');
2232 bb.addClass('assignfeedback_editpdf_commentsearch');
2233
2234 editor = this.get('editor');
2235 container = Y.Node.create('<div/>');
2236
2237 placeholder = M.util.get_string('filter', 'assignfeedback_editpdf');
2238 commentfilter = Y.Node.create('<input type="text" size="20" placeholder="' + placeholder + '"/>');
2239 container.append(commentfilter);
2240 commentlist = Y.Node.create('<ul role="menu" class="assignfeedback_editpdf_menu"/>');
2241 container.append(commentlist);
2242
402f4a1f 2243 commentfilter.on('keyup', this.filter_search_comments, this);
5c386472
DW
2244 commentlist.delegate('click', this.focus_on_comment, 'a', this);
2245 commentlist.delegate('key', this.focus_on_comment, 'enter,space', 'a', this);
2246
2247 // Set the body content.
2248 this.set('bodyContent', container);
2249
2250 COMMENTSEARCH.superclass.initializer.call(this, config);
2251 },
2252
2253 /**
2254 * Event handler to filter the list of comments.
2255 *
2256 * @protected
2257 * @method filter_search_comments
2258 */
2259 filter_search_comments : function() {
2260 var filternode,
2261 commentslist,
c181efe9
DM
2262 filtertext,
2263 dialogueid;
5c386472 2264
c181efe9
DM
2265 dialogueid = this.get('id');
2266 filternode = Y.one('#' + dialogueid + SELECTOR.SEARCHFILTER);
2267 commentslist = Y.one('#' + dialogueid + SELECTOR.SEARCHCOMMENTSLIST);
5c386472
DW
2268
2269 filtertext = filternode.get('value');
2270
2271 commentslist.all('li').each(function (node) {
2272 if (node.get('text').indexOf(filtertext) !== -1) {
2273 node.show();
2274 } else {
2275 node.hide();
2276 }
2277 });
2278 },
2279
2280 /**
2281 * Event handler to focus on a selected comment.
2282 *
2283 * @param Event e
2284 * @protected
2285 * @method focus_on_comment
2286 */
2287 focus_on_comment : function(e) {
114913e3 2288 e.preventDefault();
5c386472
DW
2289 var target = e.target.ancestor('li'),
2290 comment = target.getData('comment'),
2291 editor = this.get('editor');
2292
2293 this.hide();
2294
2295 if (comment.pageno === editor.currentpage) {
2296 comment.drawable.nodes[0].one('textarea').focus();
2297 } else {
2298 // Comment is on a different page.
2299 editor.currentpage = comment.pageno;
2300 editor.change_page();
2301 comment.drawable.nodes[0].one('textarea').focus();
2302 }
2303 },
2304
2305 /**
2306 * Show the menu.
2307 *
2308 * @method show
2309 * @return void
2310 */
2311 show : function() {
2312 var commentlist = this.get('boundingBox').one('ul'),
2313 editor = this.get('editor');
2314
2315 commentlist.all('li').remove(true);
2316
2317 // Rebuild the latest list of comments.
2318 Y.each(editor.pages, function(page) {
2319 Y.each(page.comments, function(comment) {
2320 var commentnode = Y.Node.create('<li><a href="#" tabindex="-1"><pre>' + comment.rawtext + '</pre></a></li>');
2321 commentlist.append(commentnode);
2322 commentnode.setData('comment', comment);
2323 }, this);
2324 }, this);
2325
2326 this.centerDialogue();
2327 COMMENTSEARCH.superclass.show.call(this);
2328 }
2329}, {
2330 NAME : COMMENTSEARCHNAME,
2331 ATTRS : {
2332 /**
2333 * The editor this search window is attached to.
2334 *
2335 * @attribute editor
2336 * @type M.assignfeedback_editpdf.editor
2337 * @default null
2338 */
2339 editor : {
2340 value : null
2341 }
2342
2343 }
2344});
2345
5947ab33
AN
2346Y.Base.modifyAttrs(COMMENTSEARCH, {
2347 /**
2348 * Whether the widget should be modal or not.
2349 *
2350 * Moodle override: We override this for commentsearch to force it always true.
2351 *
2352 * @attribute Modal
2353 * @type Boolean
2354 * @default true
2355 */
2356 modal: {
2357 getter: function() {
2358 return true;
2359 }
2360 }
2361});
2362
5c386472
DW
2363M.assignfeedback_editpdf = M.assignfeedback_editpdf || {};
2364M.assignfeedback_editpdf.commentsearch = COMMENTSEARCH;
2365// This file is part of Moodle - http://moodle.org/
2366//
2367// Moodle is free software: you can redistribute it and/or modify
2368// it under the terms of the GNU General Public License as published by
2369// the Free Software Foundation, either version 3 of the License, or
2370// (at your option) any later version.
2371//
2372// Moodle is distributed in the hope that it will be useful,
2373// but WITHOUT ANY WARRANTY; without even the implied warranty of
2374// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2375// GNU General Public License for more details.
2376//
2377// You should have received a copy of the GNU General Public License
2378// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
ad3f8cd1 2379/* global SELECTOR, COMMENTCOLOUR, COMMENTTEXTCOLOUR */
5c386472
DW
2380
2381/**
1f777e5c 2382 * Provides an in browser PDF editor.
5c386472
DW
2383 *
2384 * @module moodle-assignfeedback_editpdf-editor
2385 */
2386
2387/**
1f777e5c 2388 * Class representing a list of comments.
5c386472
DW
2389 *
2390 * @namespace M.assignfeedback_editpdf
2391 * @class comment
2392 * @param M.assignfeedback_editpdf.editor editor
2393 * @param Int gradeid
2394 * @param Int pageno
2395 * @param Int x
2396 * @param Int y
2397 * @param Int width
2398 * @param String colour
2399 * @param String rawtext
2400 */
557f44d9 2401var COMMENT = function(editor, gradeid, pageno, x, y, width, colour, rawtext) {
5c386472
DW
2402
2403 /**
2404 * Reference to M.assignfeedback_editpdf.editor.
2405 * @property editor
2406 * @type M.assignfeedback_editpdf.editor
2407 * @public
2408 */
2409 this.editor = editor;
2410
2411 /**
2412 * Grade id
2413 * @property gradeid
2414 * @type Int
2415 * @public
2416 */
2417 this.gradeid = gradeid || 0;
2418
2419 /**
2420 * X position
2421 * @property x
2422 * @type Int
2423 * @public
2424 */
2425 this.x = parseInt(x, 10) || 0;
2426
2427 /**
2428 * Y position
2429 * @property y
2430 * @type Int
2431 * @public
2432 */
2433 this.y = parseInt(y, 10) || 0;
2434
2435 /**
2436 * Comment width
2437 * @property width
2438 * @type Int
2439 * @public
2440 */
2441 this.width = parseInt(width, 10) || 0;
2442
2443 /**
2444 * Comment rawtext
2445 * @property rawtext
2446 * @type String
2447 * @public
2448 */
2449 this.rawtext = rawtext || '';
2450
2451 /**
2452 * Comment page number
2453 * @property pageno
2454 * @type Int
2455 * @public
2456 */
2457 this.pageno = pageno || 0;
2458
2459 /**
2460 * Comment background colour.
2461 * @property colour
2462 * @type String
2463 * @public
2464 */
2465 this.colour = colour || 'yellow';
2466
2467 /**
2468 * Reference to M.assignfeedback_editpdf.drawable
2469 * @property drawable
2470 * @type M.assignfeedback_editpdf.drawable
2471 * @public
2472 */
2473 this.drawable = false;
2474
2475 /**
2476 * Boolean used by a timeout to delete empty comments after a short delay.
2477 * @property deleteme
2478 * @type Boolean
2479 * @public
2480 */
2481 this.deleteme = false;
2482
2483 /**
2484 * Reference to the link that opens the menu.
2485 * @property menulink
2486 * @type Y.Node
2487 * @public
2488 */
2489 this.menulink = null;
2490
2491 /**
2492 * Reference to the dialogue that is the context menu.
2493 * @property menu
2494 * @type M.assignfeedback_editpdf.dropdown
2495 * @public
2496 */
2497 this.menu = null;
2498
2499 /**
2500 * Clean a comment record, returning an oject with only fields that are valid.
2501 * @public
2502 * @method clean
2503 * @return {}
2504 */
2505 this.clean = function() {
2506 return {
2507 gradeid : this.gradeid,
2508 x : parseInt(this.x, 10),
2509 y : parseInt(this.y, 10),
2510 width : parseInt(this.width, 10),
2511 rawtext : this.rawtext,
2512 pageno : this.currentpage,
2513 colour : this.colour
2514 };
2515 };
2516
2517 /**
2518 * Draw a comment.
2519 * @public
2520 * @method draw_comment
2521 * @param boolean focus - Set the keyboard focus to the new comment if true
2522 * @return M.assignfeedback_editpdf.drawable
2523 */
2524 this.draw = function(focus) {
2525 var drawable = new M.assignfeedback_editpdf.drawable(this.editor),
2526 node,
667cec9b 2527 drawingregion = this.editor.get_dialogue_element(SELECTOR.DRAWINGREGION),
5c386472
DW
2528 container,
2529 menu,
2530 position,
2531 scrollheight;
2532
2533 // Lets add a contenteditable div.
2534 node = Y.Node.create('<textarea/>');
2535 container = Y.Node.create('<div class="commentdrawable"/>');
2536 menu = Y.Node.create('<a href="#"><img src="' + M.util.image_url('t/contextmenu', 'core') + '"/></a>');
2537
2538 this.menulink = menu;
2539 container.append(node);
2540
2541 if (!this.editor.get('readonly')) {
2542 container.append(menu);
2543 } else {
2544 node.setAttribute('readonly', 'readonly');
2545 }
2546 if (this.width < 100) {
2547 this.width = 100;
2548 }
2549
2550 position = this.editor.get_window_coordinates(new M.assignfeedback_editpdf.point(this.x, this.y));
2551 node.setStyles({
2552 width: this.width + 'px',
1d38083c
DW
2553 backgroundColor: COMMENTCOLOUR[this.colour],
2554 color: COMMENTTEXTCOLOUR
5c386472
DW
2555 });
2556
667cec9b 2557 drawingregion.append(container);
d79d1bd8 2558 container.setStyle('position', 'absolute');
5c386472
DW
2559 container.setX(position.x);
2560 container.setY(position.y);
50c12f01 2561 drawable.store_position(container, position.x, position.y);
5c386472
DW
2562 drawable.nodes.push(container);
2563 node.set('value', this.rawtext);
8b766dd1 2564 scrollheight = node.get('scrollHeight');
5c386472
DW
2565 node.setStyles({
2566 'height' : scrollheight + 'px',
2567 'overflow': 'hidden'
2568 });
2569 if (!this.editor.get('readonly')) {
2570 this.attach_events(node, menu);
2571 }
2572 if (focus) {
2573 node.focus();
2574 }
2575 this.drawable = drawable;
2576
2577
2578 return drawable;
2579 };
2580
2581 /**
2582 * Delete an empty comment if it's menu hasn't been opened in time.
2583 * @method delete_comment_later
2584 */
2585 this.delete_comment_later = function() {
2586 if (this.deleteme) {
2587 this.remove();
2588 }
2589 };
2590
2591 /**
2592 * Comment nodes have a bunch of event handlers attached to them directly.
2593 * This is all done here for neatness.
2594 *
2595 * @protected
2596 * @method attach_comment_events
2597 * @param node - The Y.Node representing the comment.
2598 * @param menu - The Y.Node representing the menu.
2599 */
2600 this.attach_events = function(node, menu) {
2601 // Save the text on blur.
2602 node.on('blur', function() {
2603 // Save the changes back to the comment.
2604 this.rawtext = node.get('value');
2605 this.width = parseInt(node.getStyle('width'), 10);
2606
2607 // Trim.
2608 if (this.rawtext.replace(/^\s+|\s+$/g, "") === '') {
2609 // Delete empty comments.
2610 this.deleteme = true;
2611 Y.later(400, this, this.delete_comment_later);
2612 }
2613 this.editor.save_current_page();
60b87080 2614 this.editor.editingcomment = false;
5c386472
DW
2615 }, this);
2616
2617 // For delegated event handler.
2618 menu.setData('comment', this);
2619
2620 node.on('keyup', function() {
2621 var scrollheight = node.get('scrollHeight'),
2622 height = parseInt(node.getStyle('height'), 10);
2623
2624 // Webkit scrollheight fix.
2625 if (scrollheight === height + 8) {
2626 scrollheight -= 8;
2627 }
2628 node.setStyle('height', scrollheight + 'px');
2629
2630 });
2631
2632 node.on('gesturemovestart', function(e) {
2633 node.setData('dragging', true);
2634 node.setData('offsetx', e.clientX - node.getX());
2635 node.setData('offsety', e.clientY - node.getY());
2636 });
2637 node.on('gesturemoveend', function() {
2638 node.setData('dragging', false);
2639 this.editor.save_current_page();
2640 }, null, this);
2641 node.on('gesturemove', function(e) {
2642 var x = e.clientX - node.getData('offsetx'),
2643 y = e.clientY - node.getData('offsety'),
2644 nodewidth,
2645 nodeheight,
2646 newlocation,
2647 windowlocation,
2648 bounds;
2649
2650 nodewidth = parseInt(node.getStyle('width'), 10);
2651 nodeheight = parseInt(node.getStyle('height'), 10);
2652
2653 newlocation = this.editor.get_canvas_coordinates(new M.assignfeedback_editpdf.point(x, y));
2654 bounds = this.editor.get_canvas_bounds(true);
2655 bounds.x = 0;
2656 bounds.y = 0;
2657
2658 bounds.width -= nodewidth + 42;
2659 bounds.height -= nodeheight + 8;
2660 // Clip to the window size - the comment size.
2661 newlocation.clip(bounds);
2662
2663 this.x = newlocation.x;
2664 this.y = newlocation.y;
2665
2666 windowlocation = this.editor.get_window_coordinates(newlocation);
2667 node.ancestor().setX(windowlocation.x);
2668 node.ancestor().setY(windowlocation.y);
50c12f01 2669 this.drawable.store_position(node.ancestor(), windowlocation.x, windowlocation.y);
5c386472
DW
2670 }, null, this);
2671
2672 this.menu = new M.assignfeedback_editpdf.commentmenu({
2673 buttonNode: this.menulink,
2674 comment: this
2675 });
2676 };
2677
2678 /**
2679 * Delete a comment.
2680 * @method remove
2681 */
2682 this.remove = function() {
2683 var i = 0, comments;
2684
2685 comments = this.editor.pages[this.editor.currentpage].comments;
2686 for (i = 0; i < comments.length; i++) {
2687 if (comments[i] === this) {
2688 comments.splice(i, 1);
2689 this.drawable.erase();
2690 this.editor.save_current_page();
2691 return;
2692 }
2693 }
2694 };
2695
2696 /**
2697 * Event handler to remove a comment from the users quicklist.
2698 *
2699 * @protected
2700 * @method remove_from_quicklist
2701 */
2702 this.remove_from_quicklist = function(e, quickcomment) {
114913e3
DS
2703 e.preventDefault();
2704
5c386472
DW
2705 this.menu.hide();
2706
2707 this.editor.quicklist.remove(quickcomment);
2708 };
2709
2710 /**
2711 * A quick comment was selected in the list, update the active comment and redraw the page.
2712 *
2713 * @param Event e
2714 * @protected
2715 * @method set_from_quick_comment
2716 */
2717 this.set_from_quick_comment = function(e, quickcomment) {
114913e3
DS
2718 e.preventDefault();
2719
5c386472
DW
2720 this.menu.hide();
2721
2722 this.rawtext = quickcomment.rawtext;
2723 this.width = quickcomment.width;
2724 this.colour = quickcomment.colour;
2725
2726 this.editor.save_current_page();
2727
2728 this.editor.redraw();
2729 };
2730
2731 /**
2732 * Event handler to add a comment to the users quicklist.
2733 *
2734 * @protected
2735 * @method add_to_quicklist
2736 */
114913e3
DS
2737 this.add_to_quicklist = function(e) {
2738 e.preventDefault();
5c386472
DW
2739 this.menu.hide();
2740 this.editor.quicklist.add(this);
2741 };
2742
2743 /**
2744 * Draw the in progress edit.
2745 *
2746 * @public
2747 * @method draw_current_edit
2748 * @param M.assignfeedback_editpdf.edit edit
2749 */
2750 this.draw_current_edit = function(edit) {
2751 var drawable = new M.assignfeedback_editpdf.drawable(this.editor),
2752 shape,
2753 bounds;
2754
2755 bounds = new M.assignfeedback_editpdf.rect();
2756 bounds.bound([edit.start, edit.end]);
2757
2758 // We will draw a box with the current background colour.
2759 shape = this.editor.graphic.addShape({
2760 type: Y.Rect,
2761 width: bounds.width,
2762 height: bounds.height,
2763 fill: {
2764 color: COMMENTCOLOUR[edit.commentcolour]
2765 },
2766 x: bounds.x,
2767 y: bounds.y
2768 });
2769
2770 drawable.shapes.push(shape);
2771
2772 return drawable;
2773 };
2774
2775 /**
2776 * Promote the current edit to a real comment.
2777 *
2778 * @public
2779 * @method init_from_edit
2780 * @param M.assignfeedback_editpdf.edit edit
baf881b8 2781 * @return bool true if comment bound is more than min width/height, else false.
5c386472
DW
2782 */
2783 this.init_from_edit = function(edit) {
2784 var bounds = new M.assignfeedback_editpdf.rect();
2785 bounds.bound([edit.start, edit.end]);
2786
2787 // Minimum comment width.
2788 if (bounds.width < 100) {
2789 bounds.width = 100;
2790 }
2791
2792 // Save the current edit to the server and the current page list.
2793