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