Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
  • 8 commits
  • 4 files changed
  • 5 commit comments
  • 1 contributor
View
116 css/jquery.tag.css
@@ -1,96 +1,60 @@
-.jTagArea{
+.jTagImageContainer{
+ position: relative;
+ background-color: black;
+ padding: 0;
+ margin: 0;
}
-.jTagOverlay{
- width:100%;
- height:100%;
- position:relative;
-}
-
-.jTagDrag{
- width:100px;
- height:100px;
- border:1px dashed black;
- cursor: move;
-}
-
-.jTagInput{
- margin-right:44px;
-}
-
-.jTagSave{
- width:100%;
- background: black;
+.jTagTagWindow{
+ border:3px solid #fff;
+ position: absolute;
+ z-index: 2;
+ -moz-box-shadow: 0 0 8px #CACACA;
+ -webkit-box-shadow: 0 0 8px#CACACA;
+ box-shadow: 0 0 8px #CACACA;
+ border-radius: 2px;
}
-.jTagInput input{
- border:1px solid black;
- width:100%;
- float:left;
- padding:0;
- margin:0;
+.jTagTag{
+ position: absolute;
+ border: 1px solid black;
}
-.jTagSaveClose{
- cursor:pointer;
- float: right;
- width:20px;
- height:20px;
- background: url('../images/cancel.png') no-repeat;
- background-position: center center;
+.jTagInputcontainer {
+ position: absolute;
+ top: 0;
+ display: none;
+ margin-top: 10px;
}
-.jTagDeleteTag{
- display: none;
- cursor: pointer;
- position: absolute;
- bottom: 0px;
- right: 0px;
- z-index:5;
- width: 20px;
- height: 20px;
- background: url('../images/cancel.png') no-repeat;
+.jTagInputcontainer input{
+ border:3px solid #fff;
+ -moz-box-shadow: 0 0 8px #CACACA;
+ -webkit-box-shadow: 0 0 8px#CACACA;
+ box-shadow: 0 0 8px #CACACA;
+ border-radius: 2px;
}
-.jTagSaveBtn{
- cursor:pointer;
- float: right;
- width: 20px;
- height: 20px;
- background: url('../images/save.png') no-repeat;
- background-position: center center;
+.jTagImageContainer.tagging .jTagInputcontainer{
+ display: block;
}
-.jTagPngOverlay{
- background: url(../images/trans.png);
+.jTagImageContainer.tagging .jTagImage{
+ opacity: 0.6;
}
-.jTagTag{
- opacity: 0;
- border:2px solid black;
- position:absolute;
-}
-.jTagTag span{
- width:100%;
- background-color:black;
- color:#fff;
- height:20px;
+.jTagHandle{
position: absolute;
- bottom: 0px;
- text-align: center;
- font-size: 10px;
- line-height:20px;
+ width: 16px;
+ height: 16px;
+ bottom: 0;
+ right: 0;
+ background-color: #CACACA;
+ background: url(../images/resize.png) no-repeat;
+ cursor: se-resize;
}
-.jTagLabels{
- padding:5px;
-}
-.jTagLabels label{
- font-weight:bold;
- padding:5px;
- cursor:pointer;
- float:left;
-}
+
View
12 demo/1.html
@@ -1,8 +1,8 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
- <script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js'></script>
- <script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.7/jquery-ui.min.js'></script>
+ <script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js'>
+ </script>
<script type='text/javascript' src='../source/jquery.tag.js'></script>
<link media="screen" rel="stylesheet" href="../css/jquery.tag.css" type="text/css" />
<link media="screen" rel="stylesheet" href="../css/jquery-ui.custom.css" type="text/css" />
@@ -18,7 +18,13 @@
<script>
$(document).ready(function(){
- $("#img1").tag();
+ $("#img1").jTag({
+ maxWidth: 200,
+ maxHeight: 200,
+ save: function(top, left, width, height, text){
+ console.log(top);
+ }
+ });
});
</script>
View
BIN  images/resize.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
707 source/jquery.tag.js
@@ -11,385 +11,360 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.*/
(function($){
+
+ jTag = {
+
+ listeners: {
+ imageListener: function(image){
+
+ image.on('click', function(event){
+
+ /* add window if tagging is enabled and if no window allready present */
+ if(image.data('options').canTag && image.data('currentlyjTagging') == false ){
+
+ image.data('currentlyjTagging', true);
+
+ var tagWindow = jTag.domMethods.createTagWindow(image);
+ image.parent().data('tagWindow', tagWindow)
+ .data('currentlyjTagging', true)
+ .addClass('tagging');
+
+ inputContainer = image.parent().find('.jTagInputcontainer input').focus();
+
+
+ jTag.privateMethods.positionTagWindow(tagWindow, event, 'center');
+
+ } else if(image.data('currentlyjTagging') == true){
+
+ jTag.privateMethods.positionTagWindow(image.parent().find('.jTagTagWindow'), event, 'center');
+
+ }
+
+ });
+
+ },
+
+ tagWindow: function(){
+
+ $(document).on('mousemove', '.jTagImageContainer', function(event){
+
+ event.preventDefault();
+
+ if($(this).data('currentlyjTagging') == true){
+
+ var tagWindow = $(this).data('tagWindow');
+
+ if(tagWindow.data('mousedown') == true){
+ jTag.privateMethods.positionTagWindow(tagWindow, event, 'relative');
+ }
+
+ }
+
+ if($(this).data('jTagResizing') != false){
+ //find cursor position relative to the container
+ container_offset = $(this).offset();
+ var tagWindow = $(this).data('tagWindow');
+
+ x = event.pageX - container_offset.left;
+ y = event.pageY - container_offset.top;
+
+ desired_width = x - parseInt(tagWindow.css('left'),10);
+ desired_height = y - parseInt(tagWindow.css('top'),10);
+
+ //handle minwidth & height
+ if( $(this).data('options').minWidth != null )
+ {
+ desired_width = Math.max(desired_width, $(this).data('options').minWidth);
+ } else {
+ desired_width = Math.max(desired_width, 1);
+ }
+
+ if( $(this).data('options').minHeight != null )
+ {
+ desired_height = Math.max(desired_height, $(this).data('options').minHeight);
+ } else {
+ desired_height = Math.max(desired_height, 1);
+ }
+
+ //handle maxwidth & height
+ if( $(this).data('options').maxWidth != null )
+ {
+ desired_width = Math.min(desired_width, $(this).data('options').maxWidth);
+ }
+
+ if( $(this).data('options').maxHeight != null )
+ {
+ desired_height = Math.min(desired_height, $(this).data('options').maxHeight);
+ }
+
+ //handle image constraint
+
+ previous_height = tagWindow.height();
+
+ tagWindow.css('width', desired_width +"px");
+ tagWindow.css('height', desired_height +"px");
+
+ inputContainer = tagWindow.parent().find('.jTagInputcontainer');
+ inputContainer.css('top', parseInt(inputContainer.css('top'), 10) + (desired_height - previous_height));
+ input = inputContainer.find('input');
+ input.width(desired_width);
+
+
+
+ }
+
+ });
+
+ $(document).on('mouseleave',".jTagImageContainer", function(event){
+
+ event.preventDefault();
+
+ if($(this).data('currentlyjTagging') == true){
+
+ var tagWindow = $(this).data('tagWindow');
+
+ if(tagWindow.data('mousedown') == true){
+ tagWindow.css('cursor', 'auto');
+ tagWindow.data('mousedown', false);
+ }
+
+ }
+
+ });
+
+ $(document).on('mousedown','.jTagTagWindow', function(event){
+
+ event.preventDefault();
+ $(this).css('cursor', 'move')
+ .data('mousedown', true)
+ .data('mouseOffsetX', event.pageX - $(this).data('offset').left - parseInt($(this).css('left'), 10))
+ .data('mouseOffsetY', event.pageY - $(this).data('offset').top - parseInt($(this).css('top'), 10))
+
+ });
+
+ $(document).on('mouseup',".jTagTagWindow", function(event){
+
+ event.preventDefault();
+ $(this).css('cursor', 'auto');
+ $(this).data('mousedown', false)
+
+ });
+
+ },
+
+ handles: function(){
+
+ $(document).on('mouseup',".jTagImageContainer", function(event){
+
+ $(this).data('jTagResizing',false)
+
+ });
+
+ $(document).on('mousedown', '.jTagHandle', function(event){
+ event.preventDefault();
+ event.stopPropagation();
+ $(this).parent().parent().data('jTagResizing', true);
+ });
+
+ },
+
+ input: function(){
+
+ $(document).on('keypress', '.jTagInputcontainer input', function(event){
+ if(event.keyCode == 13){
+
+ var container = $(this).parent().parent();
+ var tagWindow = container.data('tagWindow');
+
+ var top = parseInt(tagWindow.css('top'), 10);
+ var left = parseInt(tagWindow.css('left'), 10);
+ var width = tagWindow.width();
+ var height = tagWindow.height();
+ var text = $(this).val();
+
+ //reset text
+ $(this).val('');
+
+ jTag.domMethods.createTag(container, top, left, height, width, text);
+
+ jTag.domMethods.closeTagWindow(container);
+
+ //call callback is applicable
+ if(container.data('options').save != null){
+ container.data('options').save.call(top, left, width, height, text);
+ }
+ }
+ });
+
+ }
+ },
+
+ domMethods: {
+
+ createInput: function(image){
+
+ $("<div class='jTagInputcontainer'><input type='text' /></div>").appendTo(image.parent());
+
+ },
+
+ createTagWindow: function(image){
+
+ var offset = image.offset();
+ var container = image.parent();
+
+ var tagWindow = $("<div class='jTagTagWindow'></div>").css('width', image.data('options').defaultWidth)
+ .css('height', image.data('options').defaultHeight)
+ .css('background-image', 'url('+image.attr('src') +') ')
+ .data("offset", offset)
+ .data("imageWidth", image.width())
+ .data("imageHeight", image.height())
+ .appendTo(container);
+
+ $("<div class='jTagHandle'></div>").appendTo(tagWindow);
+
+ return tagWindow;
+
+ },
+
+ createTag: function(container, top, left, width, height, text){
+
+ var tag = $("<div class='jTagTag'></div>").css('top', top)
+ .css('left', left)
+ .width(width)
+ .height(height);
+
+ tag.appendTo(container);
+
+ },
+
+ closeTagWindow: function(container){
+ container.data('currentlyjTagging', false)
+ .removeClass('tagging');
+
+ container.data('image').data('currentlyjTagging', false);
+
+ container.data('tagWindow').remove();
+ container.data('tagWindow', null);
+ }
+
+ },
+
+ privateMethods: {
+
+ setupWrappers: function(image){
+
+ image.addClass("jTagImage");
+
+ var container = $("<div class='jTagImageContainer'></div>").css('width', image.width())
+ .css('height', image.height())
+ .data('image', image)
+ .data("options", image.data('options'))
+ .data('jTagResizing', false);
+
+
+ image.wrap(container);
+
+ },
+
+ setupListeners: function(image){
+
+ jTag.listeners.imageListener(image);
+ jTag.listeners.tagWindow();
+ jTag.listeners.handles();
+ jTag.listeners.input();
+
+
+ },
+
+ positionTagWindow: function(tagWindow, event, type){
+
+ inputContainer = tagWindow.parent().find('.jTagInputcontainer');
+
+ if(type == "center"){
+
+ inputContainer.find('input').width(tagWindow.width())
+
+ window_x = event.pageX - tagWindow.data('offset').left - tagWindow.outerWidth() / 2
+ window_y = event.pageY - tagWindow.data('offset').top - tagWindow.outerHeight() / 2
+
+ } else {
+
+ relative_mouse_to_image_x = event.pageX - tagWindow.data('offset').left;
+ relative_mouse_to_image_y = event.pageY - tagWindow.data('offset').top;
+
+ mouse_offset_x = relative_mouse_to_image_x - parseInt(tagWindow.css('left'), 10)
+
+ window_x = relative_mouse_to_image_x - tagWindow.data('mouseOffsetX')
+ window_y = relative_mouse_to_image_y - tagWindow.data('mouseOffsetY')
+
+ }
+
+ window_x = Math.min(window_x, tagWindow.data('imageWidth') - tagWindow.outerWidth())
+ window_y = Math.min(window_y, tagWindow.data('imageHeight') - tagWindow.outerHeight())
+
+ window_x = Math.max(window_x, 0)
+ window_y = Math.max(window_y, 0)
+
+ image_position_x = tagWindow.data('imageWidth') - window_x - parseInt(tagWindow.css('border-left-width'), 10);
+ image_position_y = tagWindow.data('imageHeight') - window_y - parseInt(tagWindow.css('border-top-width'), 10);
+
+ tagWindow.css('top', window_y)
+ .css('left', window_x)
+ .css('background-position', image_position_x+"px " + image_position_y+"px");
+
+ inputContainer.css('top', window_y + tagWindow.outerHeight())
+ .css('left', window_x);
+
+ }
+
+ }
+
+ }
$.extend($.fn,{
- tag: function(options) {
+
+ jTag: function(custom_options) {
var defaults = {
- minWidth: 100,
- minHeight : 100,
- defaultWidth : 100,
- defaultHeight: 100,
- maxHeight : null,
- maxWidth : null,
- save : null,
- remove: null,
- canTag: true,
- canDelete: true,
- autoShowDrag: false,
- autoComplete: null,
- defaultTags: null,
- clickToTag: true,
- draggable: true,
- resizable: true,
- showTag: 'hover',
- showLabels: true,
- debug: false,
- clickable: false,
- click: null
+ minWidth : 100,
+ minHeight : 100,
+ defaultWidth : 100,
+ defaultHeight : 100,
+ maxHeight : null,
+ maxWidth : null,
+ save : null,
+ remove : null,
+ canTag : true,
+ canDelete : true,
+ autoShowDrag : false,
+ autoComplete : null,
+ defaultTags : null,
+ clickToTag : true,
+ draggable : true,
+ resizable : true,
+ showTag : 'hover',
+ showLabels : true,
+ debug : false,
+ clickable : false,
+ click : null
};
- var options = $.extend(defaults, options);
+ options = $.extend(defaults, custom_options);
return this.each(function() {
- var obj = $(this);
-
- obj.data("options",options);
-
- /* we need to wait for load because we need the img to be fully loaded to get proper width & height */
- $(window).load(function(){
-
- obj.wrap('<div class="jTagContainer" />');
-
- obj.wrap('<div class="jTagArea" />');
-
- $("<div class='jTagLabels'><div style='clear:both'></div></div>").insertAfter(obj.parent());
-
- $('<div class="jTagOverlay"></div>').insertBefore(obj);
-
- container = obj.parent().parent();
- overlay = obj.prev();
-
- obj.parent().css("backgroundImage","url("+obj.attr('src')+")");
-
- obj.parent().width(obj.width());
- obj.parent().height(obj.height());
-
- obj.parent().parent().width(obj.width());
-
- obj.hide();
-
- if(options.autoShowDrag){
- obj.showDrag();
- }
-
- container.delegate('.jTagTag','mouseenter',function(){
- if($(".jTagDrag",container).length==0){
- $(this).css("opacity",1);
- if(options.canDelete){
- $(".jTagDeleteTag",this).show();
- }
- $(this).find("span").show();
- obj.disableClickToTag();
- }
- });
-
- container.delegate('.jTagTag','mouseleave',function(){
- if($(".jTagDrag",container).length==0){
- if(options.showTag == 'hover'){
- $(this).css("opacity",0);
- if(options.canDelete){
- $(".jTagDeleteTag",this).hide();
- }
- $(this).find("span").hide();
- }
- obj.enableClickToTag();
- }
- });
-
- if(options.showLabels && options.showTag != 'always'){
-
- container.delegate('.jTagLabels label','mouseenter',function(){
- $("#"+$(this).attr('rel'),container).css('opacity',1).find("span").show();
- if(options.canDelete){
- $(".jTagDeleteTag",container).show();
- }
- });
-
- container.delegate('.jTagLabels label','mouseleave',function(){
- $("#"+$(this).attr('rel'),container).css('opacity',0).find("span").hide();
- if(options.canDelete){
- $(".jTagDeleteTag",container).hide();
- }
-
- });
-
- }
-
- if(options.canDelete){
-
- container.delegate('.jTagDeleteTag','click',function(){
-
- /* launch callback */
- if(options.remove){
- options.remove($(this).parent().parent().getId());
- }
-
- /* remove the label */
- if(options.showLabels){
- $(".jTagLabels",container).find('label[rel="'+$(this).parent().parent().attr('id')+'"]').remove();
- }
-
- /* remove the actual tag from dom */
- $(this).parent().parent().remove();
-
- obj.enableClickToTag();
-
- });
-
- }
-
- if(options.clickable){
- container.delegate('.jTagTag','click',function(){
- /* launch callback */
- if(options.click){
- options.click($(this).find('span').html());
- }
- });
- }
-
- if(options.defaultTags){
- $.each(options.defaultTags, function (index,value){
- obj.addTag(value.width,value.height,value.top,value.left,value.label,value.id);
- });
- }
-
- obj.enableClickToTag();
-
- });
-
- });
- },
- hideDrag: function(){
- var obj = $(this);
-
- var options = obj.data('options');
-
- obj.prev().removeClass("jTagPngOverlay");
-
- obj.parent().parent().find(".jTagDrag").remove();
-
- if(options.showTag == 'always'){
- obj.parent().parent().find(".jTagTag").show();
- }
-
- obj.enableClickToTag();
-
- },
- showDrag: function(e){
+ var image = $(this);
+ image.data('options', options);
+ image.data('currentlyjTagging', false);
- var obj = $(this);
-
- var container = obj.parent().parent();
- var overlay = obj.prev();
-
- obj.disableClickToTag();
-
- var options = obj.data('options');
-
- var position = function(context){
- var jtagdrag = $(".jTagDrag",context);
- border = parseInt(jtagdrag.css('borderTopWidth'));
- left_pos = parseInt(jtagdrag.attr('offsetLeft')) + border;
- top_pos = parseInt(jtagdrag.attr('offsetTop')) + border;
- return "-"+left_pos+"px -"+top_pos+"px";
- }
-
- if($(".jTagDrag",overlay).length==1){
- return;
- }
-
- if(!options.canTag){
- return;
- }
-
- if(options.showTag == 'always'){
- $(".jTagTag",overlay).hide();
- }
-
- $('<div style="width:'+options.defaultWidth+'px;height:'+options.defaultHeight+'px"class="jTagDrag"><div class="jTagSave"><div class="jTagInput"><input type="text" id="jTagLabel"></div><div class="jTagSaveClose"></div><div class="jTagSaveBtn"></div><div style="clear:both"></div></div>').appendTo(overlay);
-
- overlay.addClass("jTagPngOverlay");
-
- jtagdrag = $(".jTagDrag",overlay);
-
- jtagdrag.css("backgroundImage","url("+obj.attr('src')+")");
-
- jtagdrag.css("position", "absolute");
-
- if(e){
-
- function findPos(someObj){
- var curleft = curtop = 0;
- if (someObj.offsetParent) {
- do {
- curleft += someObj.offsetLeft;
- curtop += someObj.offsetTop;
- } while (someObj = someObj.offsetParent);
- return [curleft,curtop];
- }
- }
-
- /* get real offset */
- pos = findPos(obj.parent()[0]);
-
- x = Math.max(0,e.pageX - pos[0] - (options.defaultWidth / 2));
- y = Math.max(0,e.pageY - pos[1] - (options.defaultHeight / 2));
-
- if(x + jtagdrag.width() > obj.parent().width()){
- x = obj.parent().width() - jtagdrag.width() - 2;
- }
-
-
-
- if(y + jtagdrag.height() > obj.parent().height()){
- y = obj.parent().height() - jtagdrag.height() - 2;
- }
+ jTag.privateMethods.setupWrappers(image);
+ jTag.domMethods.createInput(image);
+ jTag.privateMethods.setupListeners(image);
- } else {
-
- x = 0;
- y = 0;
-
- }
-
- jtagdrag.css("top",y)
- .css("left",x);
-
-
- if(options.autoComplete){
- $("#jTagLabel",container).autocomplete({
- source: options.autoComplete
- });
- }
-
- $(".jTagSaveBtn",container).click(function(){
-
- label = $("#jTagLabel",container).val();
-
- if(label==''){
- alert('The label cannot be empty');
- return;
- }
-
- height = $(this).parent().parent().height();
- width = $(this).parent().parent().width();
- top_pos = $(this).parent().parent().attr('offsetTop');
- left = $(this).parent().parent().attr('offsetLeft');
-
- tagobj = obj.addTag(width,height,top_pos,left,label);
-
- if(options.save){
- options.save(width,height,top_pos,left,label,tagobj);
- }
-
- });
-
- $(".jTagSaveClose",container).click(function(){
- obj.hideDrag();
- });
-
- if(options.resizable){
-
- jtagdrag.resizable({
- containment: obj.parent(),
- minWidth: options.minWidth,
- minHeight: options.minHeight,
- maxWidth: options.maxWidth,
- maxHeight: options.maxHeight,
- resize: function(){
- jtagdrag.css({backgroundPosition: position(overlay)});
- },
- stop: function(){
- jtagdrag.css({backgroundPosition: position(overlay)});
- }
- });
-
- }
-
- if(options.draggable){
-
- jtagdrag.draggable({
- containment: obj.parent(),
- drag: function(){
- jtagdrag.css({backgroundPosition: position(overlay)});
- },
- stop: function(){
- jtagdrag.css({backgroundPosition: position(overlay)});
- }
- });
-
- }
-
- jtagdrag.css({backgroundPosition: position(overlay)});
- },
- addTag: function(width,height,top_pos,left,label,id){
-
- var obj = $(this);
-
- var options = obj.data('options');
- var count = $(".jTagTag").length+1;
-
- tag = $('<div class="jTagTag" id="tag'+count+'"style="width:'+width+'px;height:'+height+'px;top:'+top_pos+'px;left:'+left+'px;"><div style="width:100%;height:100%"><div class="jTagDeleteTag"></div><span>'+label+'</span></div></div>')
- .appendTo(obj.prev());
-
- if(id){
- tag.setId(id);
- }
-
- if(options.canDelete){
- obj.parent().find(".jTagDeleteTag").show();
- }
-
- if(options.showTag == "always"){
- $(".jTagTag").css("opacity",1);
- }
-
- if(options.showLabels){
- $("<label rel='tag"+count+"'>"+label+"</label>").insertBefore($(".jTagLabels div:last"));
- }
-
- obj.hideDrag();
-
- return tag;
-
- },
- setId: function(id){
- if($(this).hasClass("jTagTag")){
- $(this).data("tagid",id);
- } else {
- alert('Wrong object');
- }
- },
- getId: function(id){
- if($(this).hasClass("jTagTag")){
- return $(this).data("tagid");
- } else {
- alert('Wrong object');
- }
- },
- enableClickToTag: function(){
-
- var obj = $(this);
- var options = obj.data('options');
-
- if(options.clickToTag){
+ });
- obj.parent().mousedown(function(e){
- obj.showDrag(e);
- obj.parent().unbind('mousedown');
- });
- }
- },
- disableClickToTag: function(){
- var obj = $(this);
- var options = obj.data('options');
-
- if(options.clickToTag){
- obj.parent().unbind('mousedown');
- }
}
+
});
})(jQuery);

Showing you all comments on commits in this comparison.

@jgsogo

Nice to see you are going forward with this! ;D

I started using your plugin a couple of months ago for a project of mine and did some development to tightly couple this code to my app, I'll keep track of your development and, if I can (and know how, and you want) I'll try to contribute... ;D

@djpate
Owner

Thanks for the support, that's awesome. Basicly I'm trying in this v2 to get rid of the dependency with jquery ui and to cleanup the code a lot.

@jgsogo

Why getting rid of jquery?

@djpate
Owner

not jquery only jqueryui, it makes the script require about 40kb of js which we mostly don't use

@jgsogo

ouch! Didn't realize about the ''small'' difference in your first answer... jeje

Something went wrong with that request. Please try again.