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