source: main/trunk/model-sites-dev/pei-jones/collect/photos/script/image-annotator/js/jquery.annotate2.js@ 28246

Last change on this file since 28246 was 28246, checked in by sjm84, 11 years ago

Some more features added to the usertracker and hooking up the page to the editenabled variable

File size: 23.2 KB
Line 
1/// <reference path="jquery-1.2.6-vsdoc.js" />
2(function($) {
3
4 var _posCount = 1;
5 var _page;
6 /**
7 * Creates annotations on the given image.
8 * Images are loaded from the "getUrl" propety
9 * passed into the options.
10 **/
11 $.fn.annotateImage = function(options) {
12
13 var opts = $.extend({}, $.fn.annotateImage.defaults, options);
14 var image = this;
15
16 this.image = this;
17 this.mode = 'view';
18
19 // Assign defaults
20 this.getUrl = opts.getUrl;
21 this.saveUrl = opts.saveUrl;
22 this.deleteUrl = opts.deleteUrl;
23 this.editable = opts.editable;
24 this.useAjax = opts.useAjax;
25 this.notes = opts.notes;
26 _page = opts.page;
27
28 //With paged document images, the width and height are not being read, hence the addition of these if statements.
29 if(this.width() == 0 && opts.width !== undefined)
30 this.width(opts.width);
31 if(this.height() == 0 && opts.width !== undefined)
32 this.height(opts.height);
33
34 //get the last ID number and set _posCount to be the next number.
35 if(this.notes !== null && this.notes !== undefined){
36
37 if(this.notes.length > 0){
38
39 var lastId = this.notes[this.notes.length-1].id;
40
41 if(lastId != null && lastId !== undefined)
42 _posCount = lastId + 1;
43 }
44
45 }
46
47 // Add the canvas
48 this.canvas = $('<div class="image-annotate-canvas"><div class="image-annotate-view"></div><div class="image-annotate-edit"><div class="image-annotate-edit-area"></div></div></div>');
49 this.canvas.children('.image-annotate-edit').hide();
50 this.canvas.children('.image-annotate-view').hide();
51 this.image.after(this.canvas);
52
53 // Give the canvas and the container their size and background
54 this.canvas.height(this.height());
55 this.canvas.width(this.width());
56
57 this.canvas.css('background-image', 'url("' + this.attr('src') + '")');
58 this.canvas.children('.image-annotate-view, .image-annotate-edit').height(this.height());
59 this.canvas.children('.image-annotate-view, .image-annotate-edit').width(this.width());
60
61 // Add the behavior: hide/show the notes when hovering the picture
62 this.canvas.hover(function() {
63 if ($(this).children('.image-annotate-edit').css('display') == 'none') {
64 $(this).children('.image-annotate-view').show();
65 }
66 }, function() {
67 $(this).children('.image-annotate-view').hide();
68 });
69
70 this.canvas.children('.image-annotate-view').hover(function() {
71 $(this).show();
72 }, function() {
73 $(this).hide();
74 });
75
76 // load the notes
77 if (this.useAjax) {
78 $.fn.annotateImage.ajaxLoad(this);
79 } else {
80 $.fn.annotateImage.load(this);
81 }
82
83 // Add the "Add a note" button
84 if (this.editable) {
85
86 this.button = $('<button type="button" id="image-annotate-add">Add Note</button>');
87
88 this.button.click(function() {
89 $.fn.annotateImage.add(image);
90 });
91
92 //this.canvas.after(this.button);
93
94 this.br = $('<br/>');
95
96 this.canvas.before(this.button);
97 this.canvas.before(this.br);
98 }
99
100 // Hide the original image
101 this.hide();
102
103 return this;
104 };
105
106 /**
107 * Plugin Defaults
108 **/
109 $.fn.annotateImage.defaults = {
110 getUrl: 'cgi-bin/metadata-server.pl?a=get-metadata&site=' + gs.xsltParams.site_name + '&c=' + gs.cgiParams.c + '&d=' + gs.cgiParams.d + '&metaname=gsimg.Annotation',
111 saveUrl: 'cgi-bin/metadata-server.pl?a=insert-metadata&site=' + gs.xsltParams.site_name + '&c=' + gs.cgiParams.c + '&d=' + gs.cgiParams.d + '&metaname=gsimg.Annotation&metamode=accumulate&metavalue=',
112 deleteUrl: 'cgi-bin/metadata-server.pl?a=remove-metadata&site=' + gs.xsltParams.site_name + '&c=' + gs.cgiParams.c + '&d=' + gs.cgiParams.d + '&metaname=gsimg.Annotation&metamode=override&metavalue=' + 'testing',
113 editable: true,
114 useAjax: true,
115 notes: new Array(),
116 page: 0 //TODO: use this to annotate correct image when dealing with GSDL paged documents//
117 };
118
119 /**
120 * Clears all existing annotations from the image.
121 **/
122 $.fn.annotateImage.clear = function(image) {
123
124 for (var i = 0; i < image.notes.length; i++) {
125 image.notes[image.notes[i]].destroy();
126 }
127 image.notes = new Array();
128 };
129
130 /**
131 * Loads the annotations from the "getUrl" property passed in on the options object.
132 **/
133 $.fn.annotateImage.ajaxLoad = function(image) {
134
135 $.fn.annotateImage.load(image);
136
137 };
138
139 /**
140 * Loads the annotations from the notes property
141 * passed in on the options object (this method is
142 * only used if "useAjax" is set to false.
143 **/
144 $.fn.annotateImage.load = function(image) {
145
146 if(image.notes === undefined || image.notes === null){
147 console.log("No annotations to load in.");
148 image.notes = new Array();
149 }else{
150
151 if(image.notes.length > 0){
152 for (var i = 0; i < image.notes.length; i++) {
153 image.notes[image.notes[i]] = new $.fn.annotateView(image, image.notes[i]);
154 }
155 }else{
156 console.log("No annotations to load in.");
157 }
158 }
159
160 };
161
162 /**
163 * Gets a count of the ticks for the current date.
164 * This is used to ensure that URLs are always
165 * unique and not cached by the browser.
166 **/
167 $.fn.annotateImage.getTicks = function() {
168
169 var now = new Date();
170 return now.getTime();
171 };
172
173 /**
174 * Adds a note to the image.
175 **/
176 $.fn.annotateImage.add = function(image) {
177 console.log("image mode = " + image.mode);
178 if (image.mode == 'view') {
179 image.mode = 'edit';
180
181 gs.userInformation.currentAction = "editingNote";
182
183 // Create/prepare the editable note elements
184 var editable = new $.fn.annotateEdit(image);
185
186 $.fn.annotateImage.createSaveButton(editable, image);
187 $.fn.annotateImage.createCancelButton(editable, image);
188 }
189 };
190
191 /**
192 *Creates an OK button on the editable note.
193 **/
194 $.fn.annotateImage.createSaveButton = function(editable, image, note, prev) {
195
196 var ok = $('<a class="image-annotate-edit-ok">OK</a>');
197
198 ok.click(function() {
199 gs.userInformation.currentAction = "savingNote";
200 var form = $('#image-annotate-edit-form form');
201 var text = $('#image-annotate-text').val();
202 $.fn.annotateImage.appendPosition(form, editable)
203 image.mode = 'view';
204
205 // Save via AJAX
206 if (image.useAjax) {
207
208 var left_pos = editable.area.position().left;
209 var top_pos = editable.area.position().top;
210 var width = editable.area.width();
211 var height = editable.area.height();
212 var id = editable.note.id;
213 //var page = editable.note.page;
214 console.log(editable.note);
215
216 //var json = '{ "top": ' + top_pos + ', "left": ' + left_pos + ', "width": ' + width + ', "height": ' + height + ', "text": "' + text + '", "id": ' + id + ', "editable": true }';
217
218 var json = '{ "top": ' + top_pos + ', "left": ' + left_pos + ', "width": ' + width + ', "height": ' + height + ', "text": "' + text + '", "id": ' + id + ', "editable": true, "page": ' + _page + ' }';
219 var metaname = "gsimg.Annotation";
220 var metadata_server_url = "cgi-bin/metadata-server.pl?";
221
222 var saveIndexUrl = metadata_server_url + "a=set-metadata&site=" + gs.xsltParams.site_name + "&c=" + gs.cgiParams.c + "&d=" + gs.cgiParams.d + "&metaname=" + metaname + "&metavalue=" + json;
223 var saveArchivesUrl = metadata_server_url + "a=set-archives-metadata&site=" + gs.xsltParams.site_name + "&c=" + gs.cgiParams.c + "&d=" + gs.cgiParams.d + "&metaname=" + metaname + "&metavalue=" + json;
224 var saveImportUrl = metadata_server_url + "a=set-import-metadata&site=" + gs.xsltParams.site_name + "&c=" + gs.cgiParams.c + "&d=" + gs.cgiParams.d + "&metaname=" + metaname + "&metavalue=" + json;
225
226 if(prev !== undefined && prev !== null)
227 {
228 var prevJson = '{ "top": ' + prev.top + ', "left": ' + prev.left + ', "width": ' + prev.width + ', "height": ' + height + ', "text": "' + prev.text + '", "id": ' + prev.id + ', "editable": true, "page": ' + _page + ' }';
229 saveIndexUrl += "&prevmetavalue=" + prevJson + "&metamode=override";
230 saveArchivesUrl += "&prevmetavalue=" + prevJson + "&metamode=override";
231 saveImportUrl += "&prevmetavalue=" + prevJson + "&metamode=override";
232 }
233
234 var saveIndexCallBack = {
235 success: function(response)
236 {
237 YAHOO.util.Connect.asyncRequest("GET", gs.xsltParams.library_name + "?a=s&sa=c&c=" + gs.cgiParams.c, null);
238 console.log("Save index metata successful! Note id: " + id);
239 },
240 failed: function(response){ console.log("Failed to save index metadata of note with id: " + id);}
241 };
242
243 var saveImportCallBack =
244 {
245 sucess: function(response){ console.log("Save import metdata successful! Note id: " + id);},
246 failed: function(response){console.log("Failed in save import metadata of note with id: " + id);}
247 };
248
249 var saveArchivesCallBack = {
250 success: function(response){
251 //apparently should rebuild collection here.
252 console.log("Save archives metadata successful! Note id: " + id);
253 },
254 failed: function(response){
255 console.log("Failed to save archives metadata of note with id: " + id);
256 }
257 };
258
259 YAHOO.util.Connect.asyncRequest("GET",saveIndexUrl,saveIndexCallBack);
260 YAHOO.util.Connect.asyncRequest("GET",saveArchivesUrl,saveArchivesUrl);
261 YAHOO.util.Connect.asyncRequest("GET",saveImportUrl,saveImportCallBack);
262 }
263
264 // Add to canvas
265 if (note) {
266 note.resetPosition(editable, text);
267 } else {
268 editable.note.editable = true;
269 note = new $.fn.annotateView(image, editable.note);
270 note.resetPosition(editable, text);
271 image.notes.push(editable.note);
272 }
273
274 editable.destroy();
275 });
276 editable.form.append(ok);
277 };
278
279 /**
280 * Creates a cancel button on the editable note.
281 **/
282 $.fn.annotateImage.createCancelButton = function(editable, image) {
283
284 var cancel = $('<a class="image-annotate-edit-close">Cancel</a>');
285 cancel.click(function() {
286 editable.destroy();
287 image.mode = 'view';
288 });
289 editable.form.append(cancel);
290 };
291
292 $.fn.annotateImage.saveAsHtml = function(image, target) {
293 var element = $(target);
294 var html = "";
295 for (var i = 0; i < image.notes.length; i++) {
296 html += $.fn.annotateImage.createHiddenField("text_" + i, image.notes[i].text);
297 html += $.fn.annotateImage.createHiddenField("top_" + i, image.notes[i].top);
298 html += $.fn.annotateImage.createHiddenField("left_" + i, image.notes[i].left);
299 html += $.fn.annotateImage.createHiddenField("height_" + i, image.notes[i].height);
300 html += $.fn.annotateImage.createHiddenField("width_" + i, image.notes[i].width);
301 }
302 element.html(html);
303 };
304
305 $.fn.annotateImage.createHiddenField = function(name, value) {
306 return '&lt;input type="hidden" name="' + name + '" value="' + value + '" /&gt;<br />';
307 };
308
309 /**
310 * Defines an editable annotation area.
311 **/
312 $.fn.annotateEdit = function(image, note) {
313
314 this.image = image;
315
316 if (note) {
317 this.note = note;
318 } else {
319 var newNote = new Object();
320
321 newNote.id = _posCount;
322 _posCount++;
323 newNote.top = 30;
324 newNote.left = 30;
325 newNote.width = 30;
326 newNote.height = 30;
327 newNote.text = "";
328 newNote.page = _page;
329 this.note = newNote;
330 }
331
332 // Set area
333 var area = image.canvas.children('.image-annotate-edit').children('.image-annotate-edit-area');
334 this.area = area;
335 this.area.css('height', this.note.height + 'px');
336 this.area.css('width', this.note.width + 'px');
337 this.area.css('left', this.note.left + 'px');
338 this.area.css('top', this.note.top + 'px');
339
340 // Show the edition canvas and hide the view canvas
341 image.canvas.children('.image-annotate-view').hide();
342 image.canvas.children('.image-annotate-edit').show();
343
344 // Add the note (which we'll load with the form afterwards)
345 var form = $('<div id="image-annotate-edit-form"><form><textarea id="image-annotate-text" name="text" rows="3" cols="30">' + this.note.text + '</textarea></form></div>');
346 this.form = form;
347
348 $('body').append(this.form);
349 this.form.css('left', this.area.offset().left + 'px');
350 this.form.css('top', (parseInt(this.area.offset().top) + parseInt(this.area.height()) + 7) + 'px');
351
352 // Set the area as a draggable/resizable element contained in the image canvas.
353 // Would be better to use the containment option for resizable but buggy
354 area.resizable({
355 handles: 'all',
356
357 resize: function(e, ui) {
358 form.css('left', area.offset().left + 'px');
359 form.css('top', (parseInt(area.offset().top) + parseInt(area.height()) + 2) + 'px');
360 },
361 stop: function(e, ui) {
362 form.css('left', area.offset().left + 'px');
363 form.css('top', (parseInt(area.offset().top) + parseInt(area.height()) + 2) + 'px');
364 }
365 })
366 .draggable({
367 containment: image.canvas,
368 drag: function(e, ui) {
369 form.css('left', area.offset().left + 'px');
370 form.css('top', (parseInt(area.offset().top) + parseInt(area.height()) + 2) + 'px');
371 },
372 stop: function(e, ui) {
373 form.css('left', area.offset().left + 'px');
374 form.css('top', (parseInt(area.offset().top) + parseInt(area.height()) + 2) + 'px');
375 }
376 });
377 return this;
378 };
379
380 /**
381 * Destroys an editable annotation area.
382 **/
383 $.fn.annotateEdit.prototype.destroy = function() {
384
385 this.image.canvas.children('.image-annotate-edit').hide();
386 this.area.resizable('destroy');
387 this.area.draggable('destroy');
388 this.area.css('height', '');
389 this.area.css('width', '');
390 this.area.css('left', '');
391 this.area.css('top', '');
392 this.form.remove();
393 }
394
395 /**
396 * Defines an annotation area.
397 **/
398 $.fn.annotateView = function(image, note) {
399
400 this.image = image;
401
402 this.note = note;
403
404 this.editable = (note.editable && image.editable);
405
406 // Add the area
407 this.area = $('<div class="image-annotate-area' + (this.editable ? ' image-annotate-area-editable' : '') + '"><div></div></div>');
408 image.canvas.children('.image-annotate-view').prepend(this.area);
409
410 // Add the note
411 this.form = $('<div class="image-annotate-note">' + note.text + '</div>');
412 this.form.hide();
413 image.canvas.children('.image-annotate-view').append(this.form);
414 this.form.children('span.actions').hide();
415
416 // Set the position and size of the note
417 this.setPosition();
418
419 // Add the behavior: hide/display the note when hovering the area
420 var annotation = this;
421 this.area.hover(function() {
422 annotation.show();
423 }, function() {
424 annotation.hide();
425 });
426
427 // Edit a note feature
428 if (this.editable) {
429 var form = this;
430 this.area.click(function() {
431 form.edit();
432 });
433 }
434 };
435
436 $.fn.annotateView.prototype.setPosition = function() {
437 /// <summary>
438 /// Sets the position of an annotation.
439 /// </summary>
440 this.area.children('div').height((parseInt(this.note.height) - 2) + 'px');
441 this.area.children('div').width((parseInt(this.note.width) - 2) + 'px');
442 this.area.css('left', (this.note.left) + 'px');
443 this.area.css('top', (this.note.top) + 'px');
444 this.form.css('left', (this.note.left) + 'px');
445 this.form.css('top', (parseInt(this.note.top) + parseInt(this.note.height) + 7) + 'px');
446 };
447
448 $.fn.annotateView.prototype.show = function() {
449 /// <summary>
450 /// Highlights the annotation
451 /// </summary>
452 this.form.fadeIn(250);
453 if (!this.editable) {
454 this.area.addClass('image-annotate-area-hover');
455 } else {
456 this.area.addClass('image-annotate-area-editable-hover');
457 }
458 };
459
460 /**
461 * Removes the highlight from the annotation.
462 **/
463 $.fn.annotateView.prototype.hide = function() {
464
465 this.form.fadeOut(250);
466 this.area.removeClass('image-annotate-area-hover');
467 this.area.removeClass('image-annotate-area-editable-hover');
468 };
469
470 /**
471 * Destroys the annotation.
472 **/
473 $.fn.annotateView.prototype.destroy = function() {
474
475 this.area.remove();
476 this.form.remove();
477 }
478
479 /**
480 * Edits the annotation.
481 **/
482 $.fn.annotateView.prototype.edit = function() {
483
484 if (this.image.mode == 'view') {
485 this.image.mode = 'edit';
486 var annotation = this;
487
488 //Save the previous note (before the edit was made).
489 var storePrevNotes = this.image.notes;
490
491 console.log("this note's id: " + this.note.id);
492
493 var prev = null;
494 for(var i = 0; i < storePrevNotes.length; i++){
495
496 var curr = storePrevNotes[i];
497
498 if(curr.id == this.note.id){
499 prev = curr;
500 }
501 }
502
503 // Create/prepare the editable note elements
504 var editable = new $.fn.annotateEdit(this.image, this.note);
505
506 $.fn.annotateImage.createSaveButton(editable, this.image, annotation,prev);
507
508 // Add the delete button
509 var del = $('<a class="image-annotate-edit-delete">Delete</a>');
510 del.click(function() {
511
512 var form = $('#image-annotate-edit-form form');
513
514 $.fn.annotateImage.appendPosition(form, editable)
515
516 if (annotation.image.useAjax) {
517
518 var left_pos = annotation.note.left;
519 var top_pos = annotation.note.top;
520 var width = annotation.note.width;
521 var height = annotation.note.height;
522 var id = annotation.note.id;
523 var text = annotation.note.text;
524
525 //var page = annotation.note.page;
526
527 var json = '{ "top": ' + top_pos + ', "left": ' + left_pos + ', "width": ' + width + ', "height": ' + height + ', "text": "' + text + '", "id": ' + id + ', "editable": true ' + ', "page": ' + _page + ' }';
528
529 var metaposVal = id-1;
530
531 //make below variables global...
532 var metaname = "gsimg.Annotation";
533
534 var metadata_server_url = "cgi-bin/metadata-server.pl?";
535
536 var removeFromIndexUrl = metadata_server_url + "a=remove-metadata&site=" + gs.xsltParams.site_name + "&c=" + gs.cgiParams.c + "&d=" + gs.cgiParams.d + "&metaname=" + metaname + "&metavalue=" + json + "&metapos=" + metaposVal;
537
538 var removeFromArchivesUrl = metadata_server_url + "a=remove-archives-metadata&site=" + gs.xsltParams.site_name + "&c=" + gs.cgiParams.c + "&d=" + gs.cgiParams.d + "&metaname=" + metaname + "&metavalue=" + json + "&metapos=" + metaposVal;
539
540 var removeFromImportUrl = metadata_server_url + "a=remove-import-metadata&site=" + gs.xsltParams.site_name + "&c=" + gs.cgiParams.c + "&d=" + gs.cgiParams.d + "&metaname=" + metaname + "&metavalue=" + json;
541
542 var indexCallBack = {
543 success: function(response){
544
545 //need to renumber ids so that the correct note is deleted next time
546 for(var i = 0; i < annotation.image.notes.length; i++)
547 {
548 var currNote = annotation.image.notes[i];
549
550 if(currNote.id > id)
551 currNote.id--;
552 }
553 //_posCount--;
554
555 console.log("Index metadata successfully removed. Note id: " + id);
556 },
557 failed: function(){
558 console.log("Failed to delete index metadata of note with id: " + id);
559 }
560 };
561
562 var archiveCallBack = {
563 success: function(response){
564 //need to rebuild collection here.
565 console.log("Metadata successfully removed from archives. Note id: " + id);
566 },
567 failed: function(){
568 console.log("Failed to remove metadata from archives. Note id: " + id);
569 }
570 };
571
572 var importCallBack = {
573 success: function(){},
574 failed: function(){ alert("Failed to delete import metadata of note with id: " + id);}
575 };
576
577 YAHOO.util.Connect.asyncRequest("GET",removeFromIndexUrl,indexCallBack);
578 YAHOO.util.Connect.asyncRequest("GET",removeFromArchivesUrl,archiveCallBack);
579 YAHOO.util.Connect.asyncRequest("GET",removeFromImportUrl,importCallBack);
580
581 }
582
583 annotation.image.mode = 'view';
584 editable.destroy();
585 annotation.destroy();
586
587 });
588 editable.form.append(del);
589
590 $.fn.annotateImage.createCancelButton(editable, this.image);
591 }
592 };
593
594 /**
595 * Appends the annotations coordinates to the given form that is posted to the server.
596 **/
597 $.fn.annotateImage.appendPosition = function(form, editable) {
598
599 var areaFields = $('<input type="hidden" value="' + editable.area.height() + '" name="height"/>' +
600 '<input type="hidden" value="' + editable.area.width() + '" name="width"/>' +
601 '<input type="hidden" value="' + editable.area.position().top + '" name="top"/>' +
602 '<input type="hidden" value="' + editable.area.position().left + '" name="left"/>' +
603 '<input type="hidden" value="' + editable.note.id + '" name="id"/>');
604 form.append(areaFields);
605 }
606
607 /**
608 * Sets the position of an annotation.
609 **/
610 $.fn.annotateView.prototype.resetPosition = function(editable, text) {
611
612 this.form.html(text);
613 this.form.hide();
614
615 // Resize
616 this.area.children('div').height(editable.area.height() + 'px');
617 this.area.children('div').width((editable.area.width() - 2) + 'px');
618 this.area.css('left', (editable.area.position().left) + 'px');
619 this.area.css('top', (editable.area.position().top) + 'px');
620 this.form.css('left', (editable.area.position().left) + 'px');
621 this.form.css('top', (parseInt(editable.area.position().top) + parseInt(editable.area.height()) + 7) + 'px');
622
623 // Save new position to note
624 this.note.top = editable.area.position().top;
625 this.note.left = editable.area.position().left;
626 this.note.height = editable.area.height();
627 this.note.width = editable.area.width();
628 this.note.text = text;
629 this.note.id = editable.note.id;
630 this.editable = true;
631 };
632
633})(jQuery);
Note: See TracBrowser for help on using the repository browser.