/// var button_ok = ""; var button_cancel = ""; var button_delete = ""; var button_add = ""; var button_toggle=""; var button_toggle_off=""; var error_saving = ""; var error_deleting = ""; function isInt(value) { return !isNaN(parseInt(value)) && (parseFloat(value) == parseInt(value)); } (function($) { var areasurrogate = 0; $.fn.annotateImage = function(options) { /// /// Creates annotations on the given image. /// Images are loaded from the "getUrl" propety passed into the options. /// var opts = $.extend({}, $.fn.annotateImage.defaults, options); var image = this; this.image = this; this.mode = 'view'; // Assign defaults this.getUrl = opts.getUrl; this.saveUrl = opts.saveUrl; this.deleteUrl = opts.deleteUrl; this.editable = opts.editable; this.useAjax = opts.useAjax; this.notes = opts.notes; this.toggle= opts.toggle; this.height = (this.height() == 0 ? this[0]["height"]:this.height()); this.width = (this.width() == 0 ? this[0]["width"]:this.width()) // Specific to ResourceSpace var modal = (typeof opts.modal !== "undefined" ? opts.modal : false); $.fn.annotateImage.modal = modal; // Add the canvas this.canvas = $('
'); this.canvas.children('.image-annotate-edit').hide(); this.canvas.children('.image-annotate-view').hide(); this.image.after(this.canvas); // Give the canvas and the container their size and background this.canvas.height(this.height); this.canvas.width(this.width); this.canvas.css('background-image', 'url("' + this.attr('src') + '")'); this.canvas.children('.image-annotate-view, .image-annotate-edit').height(this.height); this.canvas.children('.image-annotate-view, .image-annotate-edit').width(this.width); // load the notes if (this.useAjax) { $.fn.annotateImage.ajaxLoad(this); } else { $.fn.annotateImage.load(this); } /* this.canvas.children('.image-annotate-view').hover(function() {image.canvas.css({"overflow":"visible"}); $(this).show(); }, function() {image.canvas.css({"overflow":"hidden"}); if (image.toggle==false){ $(this).hide();} });this.canvas.children('.image-annotate-note').hover(function() {image.canvas.css({"overflow":"visible"}); $(this).show(); }, function() {image.canvas.css({"overflow":"hidden"}); if (image.toggle==false){ $(this).hide();} }); */ // Add the image actions if (this.editable) { this.button = $('
'); this.canvas.append(this.button); $.fn.annotateImage.getImageActionsTarget(modal).hide(); this.button = $('' + button_add + ''); this.button.css({width: 'auto', 'padding-right': '5px'}); this.button.click(function() { $.fn.annotateImage.add(image); return false; }); $.fn.annotateImage.getImageActionsTarget(modal).append(this.button); this.button = $(''); this.button.css({width: 'auto', 'padding-right': '5px'});this.button.click(function() { $.fn.annotateImage.toggle(image); }); this.button.css({}); $.fn.annotateImage.getImageActionsTarget(modal).append(this.button); $.fn.annotateImage.toggle(image); $.fn.annotateImage.toggle(image); $.fn.annotateImage.getImageActionsTarget(modal).hover(function(){ toTop($.fn.annotateImage.getImageActionsTarget(modal, true)); }); } // Add the behavior: hide/show the notes when hovering the picture this.canvas.hover(function() { image.canvas.css({"overflow":"visible"}); if ($(this).children('.image-annotate-edit').css('display') == 'none') { $(this).children('.image-annotate-view').show(); $.fn.annotateImage.getImageActionsTarget(modal).show(); toTop($.fn.annotateImage.getImageActionsTarget(modal, true)); } }, function() { image.canvas.css({"overflow":"hidden"}); if (image.toggle==false){ $(this).children('.image-annotate-view').hide(); $(this).children('.image-annotate-note','.image-annotate-toggle').hide(); } $.fn.annotateImage.getImageActionsTarget(modal).hide(); }); // Hide the original this.hide(); return this; }; /** * Plugin Defaults **/ $.fn.annotateImage.defaults = { getUrl: 'your-get.rails', saveUrl: 'your-save.rails', deleteUrl: 'your-delete.rails', editable: true, useAjax: true, notes: new Array() }; $.fn.annotateImage.clear = function(image) { /// /// Clears all existing annotations from the image. /// for (var i = 0; i < image.notes.length; i++) { image.notes[image.notes[i]].destroy(); } image.notes = new Array(); }; $.fn.annotateImage.getImageActionsTarget = function(modal, as_str) { /// /// Specific to ResourceSpace /// Return the image-actions target based on image being in a modal or normal page. /// // $.fn.annotateImage.modal is shared between a normal page and the modal. We rely on the passed modal arg to reset // this value to false once we closed the modal. if(typeof modal !== "undefined" && modal && modal != $.fn.annotateImage.modal) { $.fn.annotateImage.modal = modal; } if(modal) { return (as_str === true ? '#modal #image-actions' : $('#modal #image-actions')); } return (as_str === true ? '#image-actions' : $('#image-actions')); }; $.fn.annotateImage.ajaxLoad = function(image) { /// /// Loads the annotations from the "getUrl" property passed in on the /// options object. /// var append_separator = '?'; if(image.getUrl.indexOf('?') > -1) { append_separator = '&'; } $.getJSON(image.getUrl + append_separator + 'ticks=' + $.fn.annotateImage.getTicks(), function(data) { image.notes = data; $.fn.annotateImage.load(image); }); }; $.fn.annotateImage.load = function(image) { /// /// Loads the annotations from the notes property passed in on the /// options object. /// for (var i = 0; i < image.notes.length; i++) { image.notes[image.notes[i]] = new $.fn.annotateView(image, image.notes[i]); } // load the default toggle if (image.toggle==true){ $('.image-annotate-view').show(); $('.image-annotate-note').show(); } // Set initial z-indices $('.image-annotate-area').each(function(i, area) { if (!isBlocker(area)) { toTop(area); } }); }; $.fn.annotateImage.getTicks = function() { /// /// Gets a count og the ticks for the current date. /// This is used to ensure that URLs are always unique and not cached by the browser. /// var now = new Date(); return now.getTime(); }; $.fn.annotateImage.add = function(image) { /// /// Adds a note to the image. /// if (image.mode == 'view') { image.mode = 'edit'; // Create/prepare the editable note elements var editable = new $.fn.annotateEdit(image); $.fn.annotateImage.createSaveButton(editable, image); $.fn.annotateImage.createCancelButton(editable, image); } }; $.fn.annotateImage.toggle = function(image) { /// /// Toggle notes /// if (image.mode == 'view') { if (image.toggle==false){ image.toggle=true; $('#image-annotate-toggle').html('' + button_toggle_off + ''); SetCookie ('annotate_toggle',true); $('.image-annotate-view').show(); $('.image-annotate-note').show(); } else { image.toggle=false; $('#image-annotate-toggle').html('' + button_toggle + ''); SetCookie ('annotate_toggle',false); $('.image-annotate-view').hide(); $('.image-annotate-note').hide(); } } }; $.fn.annotateImage.createSaveButton = function(editable, image, note) { /// /// Creates a Save button on the editable note. /// var ok = $('' + button_ok + ''); ok.click(function() { var form = $('#image-annotate-edit-form form'); var text = $('#image-annotate-text').val(); $.fn.annotateImage.appendPosition(form, editable) image.mode = 'view'; // Save via AJAX if (image.useAjax) { $.ajax({ url: image.saveUrl, data: form.serialize(), error: function(e) { alert(error_saving) }, success: function(data) { if (data != undefined) { editable.note.id = data; } }, dataType: "json" }); } // Add to canvas if (note) { note.resetPosition(editable, text); } else { editable.note.editable = true; note = new $.fn.annotateView(image, editable.note) note.resetPosition(editable, text); image.notes.push(editable.note); } editable.destroy(); if (image.toggle==true){$('.image-annotate-view').show();$('.image-annotate-note').show(); } }); editable.form.append(ok); }; $.fn.annotateImage.createCancelButton = function(editable, image) { /// /// Creates a Cancel button on the editable note. /// var cancel = $('' + button_cancel + ''); cancel.click(function() { editable.destroy(); image.mode = 'view'; }); editable.form.append(cancel); }; $.fn.annotateImage.saveAsHtml = function(image, target) { var element = $(target); var html = ""; for (var i = 0; i < image.notes.length; i++) { html += $.fn.annotateImage.createHiddenField("text_" + i, image.notes[i].text); html += $.fn.annotateImage.createHiddenField("top_" + i, image.notes[i].top); html += $.fn.annotateImage.createHiddenField("left_" + i, image.notes[i].left); html += $.fn.annotateImage.createHiddenField("height_" + i, image.notes[i].height); html += $.fn.annotateImage.createHiddenField("width_" + i, image.notes[i].width); } element.html(html); }; $.fn.annotateImage.createHiddenField = function(name, value) { return '<input type="hidden" name="' + name + '" value="' + value + '" />
'; }; $.fn.annotateEdit = function(image, note) { /// /// Defines an editable annotation area. /// this.image = image; console.log(image); var top=30; var left=30; if (note) { this.note = note; } else { var newNote = new Object(); // check if there is an identical note position, and offset it. for (var x=0;x
'); this.form = form; //$('body').append(this.form); // Set the area as a draggable/resizable element contained in the image canvas. // Would be better to use the containment option for resizable but buggy //this.form.css('left', this.area.offset().left + 'px'); //this.form.css('top', (parseInt(this.area.offset().top) + parseInt(this.area.height()) + 7) + 'px'); // modified for RS image.canvas.after(this.form); this.form.css('left', (this.area.offset().left / 2) + 'px'); this.form.css('top', (parseInt(this.area.offset().top) + parseInt(this.area.height()) + 7) + 'px'); this.form.css('z-index',3); // area.resizable({ handles: 'all', resize: function(e, ui) { form.css('left', (area.offset().left / 2) + 'px'); form.css('top', (parseInt(area.offset().top) + parseInt(area.height()) + 2) + 'px'); }, stop: function(e, ui) { form.css('left', (area.offset().left / 2) + $('.ui-layout-center').scrollLeft() + 'px'); form.css('top', (parseInt(area.offset().top) + parseInt(area.height()) + 2) + 'px'); } }) .draggable({ containment: image.canvas, drag: function(e, ui) { form.css('left', (area.offset().left / 2) + 'px'); form.css('top', (parseInt(area.offset().top) + parseInt(area.height()) + 2) + 'px'); }, stop: function(e, ui) { form.css('left', (area.offset().left / 2) + 'px'); form.css('top', (parseInt(area.offset().top) + parseInt(area.height()) + 2) + 'px'); } }); return this; }; $.fn.annotateEdit.prototype.destroy = function() { /// /// Destroys an editable annotation area. /// this.image.canvas.children('.image-annotate-edit').hide(); this.area.resizable('destroy'); this.area.draggable('destroy'); this.area.css('height', ''); this.area.css('width', ''); this.area.css('left', ''); this.area.css('top', ''); this.form.remove(); } $.fn.annotateView = function(image, note) { /// /// Defines a annotation area. /// this.image = image; this.note = note; this.editable = (note.editable && image.editable); areasurrogate += 1; // Add the area this.area = $('
'); image.canvas.children('.image-annotate-view').prepend(this.area); // image.canvas.children('.image-annotate-view').prepend(this.area); // Add the note this.form = $('
' + note.text + '
'); this.form.hide(); image.canvas.children('.image-annotate-view').append(this.form); this.form.children('span.actions').hide(); // Set the position and size of the note this.setPosition(); // Add the behavior: hide/display the note when hovering the area var annotation = this; // Fix z-index when necessary where multiple notes are visible this.area.hover(function() { annotation.show(); // Send this element to the top if it doesn't fully block another area element if (!isBlocker(annotation.area)) { toTop(annotation.area); toTop(annotation.form); }; }, function() { annotation.hide(); }); this.form.hover(function() { annotation.show(); // Send this element to the top if it doesn't fully block another area element if (!isBlocker(annotation.area)) { toTop(annotation.area); toTop(annotation.form); }; }, function() { annotation.hide(); }); // Edit a note feature if (this.editable) { var form = this; this.area.click(function() { form.edit(); }); this.form.click(function() { form.edit(); }); } }; // Is the selected area element fully blocking any other area element function isBlocker(element){ var selected_id = $(element)[0].id; var selected_top = $(element)[0].offsetTop; var selected_height = $(element)[0].offsetHeight; var selected_left = $(element)[0].offsetLeft; var selected_width = $(element)[0].offsetWidth; var selected_bottom = selected_top + selected_height; var selected_right = selected_left + selected_width; var fullyBlockedFound = false; $(".image-annotate-area").each(function(i, area) { if ($(area)[0].id != selected_id) { if ( selected_top <= $(area)[0].offsetTop && selected_bottom >= ($(area)[0].offsetTop + $(area)[0].offsetHeight) && selected_left <= $(area)[0].offsetLeft && selected_right >= ($(area)[0].offsetLeft + $(area)[0].offsetWidth) ) { // console.log("SELECTED_ID="+selected_id+" BLOCKS="+$(area)[0].id); fullyBlockedFound = true; return false; // No need to check any more areas; break out of .each loop } } }); return fullyBlockedFound; }; function toTop(element){ var index_highest = 50; $(".image-annotate-area,.image-annotate-note,.image-actions").each(function() { var index_current = parseInt($(this).css("z-index"), 10); //console.log(index_current ); if(index_current > index_highest) { index_highest = index_current; } }); //console.log('highest '+index_highest); $(element).css({'z-index':index_highest+1}); }; $.fn.annotateView.prototype.setPosition = function() { /// /// Sets the position of an annotation. /// this.area.children('div').height((parseInt(this.note.height) - 2) + 'px'); this.area.children('div').width((parseInt(this.note.width) - 2) + 'px'); this.area.css('left', (this.note.left) + 'px'); this.area.css('top', (this.note.top) + 'px'); this.form.css('left', (this.note.left) + 'px'); this.form.css('top', (parseInt(this.note.top) + parseInt(this.note.height) + 7) + 'px'); }; $.fn.annotateView.prototype.show = function() { /// /// Highlights the annotation /// this.form.fadeIn(50); if (!this.editable) { this.area.addClass('image-annotate-area-hover'); } else { this.area.addClass('image-annotate-area-editable-hover'); } }; $.fn.annotateView.prototype.hide = function() { /// /// Removes the highlight from the annotation. /// if (this.image.toggle==false){this.form.fadeOut(50);} this.area.removeClass('image-annotate-area-hover'); this.area.removeClass('image-annotate-area-editable-hover'); }; $.fn.annotateView.prototype.destroy = function() { /// /// Destroys the annotation. /// this.area.remove(); this.form.remove(); } $.fn.annotateView.prototype.edit = function() { /// /// Edits the annotation. /// if (this.image.mode == 'view') { this.image.mode = 'edit'; var annotation = this; // Create/prepare the editable note elements var editable = new $.fn.annotateEdit(this.image, this.note); $.fn.annotateImage.createSaveButton(editable, this.image, annotation); // Add the delete button var del = $('' + button_delete + ''); del.click(function() { var form = $('#image-annotate-edit-form form'); $.fn.annotateImage.appendPosition(form, editable) if (annotation.image.useAjax) { $.ajax({ url: annotation.image.deleteUrl, data: form.serialize(), error: function(e) { alert(error_deleting) } }); } annotation.image.mode = 'view'; editable.destroy(); annotation.destroy(); }); editable.form.append(del); $.fn.annotateImage.createCancelButton(editable, this.image); } }; $.fn.annotateImage.appendPosition = function(form, editable) { /// /// Appends the annotations coordinates to the given form that is posted to the server. /// var areaFields = $('' + '' + '' + '' + ''); form.append(areaFields); } $.fn.annotateView.prototype.resetPosition = function(editable, text) { /// /// Sets the position of an annotation. /// this.form.html(text.replace(new RegExp('\n', 'g'), '
')); this.form.hide(); // Resize this.area.children('div').height(editable.area.height() + 'px'); this.area.children('div').width((editable.area.width() - 2) + 'px'); this.area.css('left', (editable.area.position().left) + 'px'); this.area.css('top', (editable.area.position().top) + 'px'); this.form.css('left', (editable.area.position().left) + 'px'); this.form.css('top', (parseInt(editable.area.position().top) + parseInt(editable.area.height()) + 7) + 'px'); // Save new position to note this.note.top = editable.area.position().top; this.note.left = editable.area.position().left; this.note.height = editable.area.height(); this.note.width = editable.area.width(); this.note.text = text; this.note.id = editable.note.id; this.editable = true; // Send this element to the top if it doesn't fully block another area element if (!isBlocker(this.area)) { toTop(this.area); toTop(this.form); } }; })(jQuery);