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