Merge branch 'featuer/image-on-diff' of https://github.com/team-lab/gitbucket into team-lab-featuer/image-on-diff

# Conflicts:
#	src/main/webapp/assets/common/js/gitbucket.js
This commit is contained in:
Naoki Takezoe
2015-05-25 02:06:14 +09:00
6 changed files with 391 additions and 13 deletions

View File

@@ -474,12 +474,12 @@ function string_score_sort(word, strings, limit){
return ret;
}
/**
* hilight by result.
* highlight by result.
* @param score {string:"string target string", matchingPositions:"Array[Interger] matchng positions"}
* @param hilight tag ex: '<b>'
* @return array of hilighted html elements.
* @param highlight tag ex: '<b>'
* @return array of highlighted html elements.
*/
function string_score_hilight(result, tag){
function string_score_highlight(result, tag){
var str = result.string, msp=0;
return hilight([], 0, result.matchingPositions[msp]);
function hilight(html, c, mpos){
@@ -493,3 +493,213 @@ function string_score_hilight(result, tag){
}
}
}
/****************************************************************************/
/* Diff */
/****************************************************************************/
// add naturalWidth and naturalHeight for ie 8
function setNatural(img) {
if(typeof img.naturalWidth == 'undefined'){
var tmp = new Image();
tmp.src = img.src;
img.naturalWidth = tmp.width;
img.naturalHeight = tmp.height;
}
}
/**
* onload handler
* @param img <img>
*/
function onLoadedDiffImages(img){
setNatural(img);
img = $(img);
img.show();
var tb = img.parents(".diff-image-render");
// Find images. If the image has not loaded yet, value is undefined.
var old = tb.find(".diff-old img.diff-image:visible")[0];
var neo = tb.find(".diff-new img.diff-image:visible")[0];
imageDiff.appendImageMeta(tb, old, neo);
if(old && neo){
imageDiff.createToolSelector(old, neo).appendTo(tb.parent());
}
}
var imageDiff ={
/** append image meta div after image nodes.
* @param tb <div class="diff-image-2up">
* @param old <img>||undefined
* @param neo <img>||undefined
*/
appendImageMeta:function(tb, old, neo){
old = old || {};
neo = neo || {};
tb.find(".diff-meta").remove();
// before loaded, image is not visible.
tb.find("img.diff-image:visible").each(function(){
var div = $('<p class="diff-meta"><b>W:</b><span class="w"></span> | <b>W:</b><span class="h"></span></p>');
div.find('.w').text(this.naturalWidth+"px").toggleClass("diff", old.naturalWidth != neo.naturalWidth);
div.find('.h').text(this.naturalHeight+"px").toggleClass("diff", old.naturalHeight != neo.naturalHeight);
div.appendTo(this.parentNode);
});
},
/** check this browser can use canvas tag.
*/
hasCanvasSupport:function(){
if(!this.hasCanvasSupport.hasOwnProperty('resultCache')){
this.hasCanvasSupport.resultCache = (typeof $('<canvas>')[0].getContext)=='function';
}
return this.hasCanvasSupport.resultCache;
},
/** create toolbar
* @param old <img>
* @param neo <img>
* @return jQuery(<ul class="image-diff-tools">)
*/
createToolSelector:function(old, neo){
var self = this;
return $('<ul class="image-diff-tools">'+
'<li data-mode="diff2up" class="active">2-up</li>'+
'<li data-mode="swipe">Swipe</li>'+
'<li data-mode="onion">Onion Skin</li>'+
'<li data-mode="difference" class="need-canvas">Difference</li>'+
'<li data-mode="blink">Blink</li>'+
'</ul>')
.toggleClass('no-canvas', !this.hasCanvasSupport())
.on('click', 'li', function(e){
var td = $(this).parents("td");
$(e.delegateTarget).find('li').each(function(){ $(this).toggleClass('active',this == e.target); });
var mode = $(e.target).data('mode');
td.find(".diff-image-render").hide();
// create div if not created yet
if(td.find(".diff-image-render."+mode).show().length===0){
self[mode](old, neo).insertBefore(e.delegateTarget).addClass("diff-image-render");
}
return false;
});
},
/** (private) calc size from images and css (const)
* @param old <img>
* @param neo <img>
*/
calcSizes:function(old, neo){
var maxWidth = 869 - 20 - 20 - 4; // set by css
var h = Math.min(Math.max(old.naturalHeight, neo.naturalHeight),maxWidth);
var w = Math.min(Math.max(old.naturalWidth, neo.naturalWidth),maxWidth);
var oldRate = Math.min(h/old.naturalHeight, w/old.naturalWidth);
var neoRate = Math.min(h/neo.naturalHeight, w/neo.naturalWidth);
var neoW = neo.naturalWidth*neoRate;
var neoH = neo.naturalHeight*neoRate;
var oldW = old.naturalWidth*oldRate;
var oldH = old.naturalHeight*oldRate;
var paddingLeft = (maxWidth/2)-Math.max(neoW,oldW)/2;
return {
height:Math.max(oldH, neoH),
width:w,
padding:paddingLeft,
paddingTop:20, // set by css
barWidth:200, // set by css
old:{ rate:oldRate, width:oldW, height:oldH },
neo:{ rate:neoRate, width:neoW, height:neoH }
};
},
/** (private) create div
* @param old <img>
* @param neo <img>
*/
stack:function(old, neo){
var size = this.calcSizes(old, neo);
var diffNew = $('<div class="diff-new">')
.append($("<img>").attr('src',neo.src).css({width:size.neo.width, height:size.neo.height}));
var diffOld = $('<div class="diff-old">')
.append($("<img>").attr('src',old.src).css({width:size.old.width, height:size.old.height}));
var handle = $('<span class="diff-swipe-handle icon icon-resize-horizontal"></span>')
.css({marginTop:size.height-5});
var bar = $('<hr class="diff-silde-bar">').css({top:size.height+size.paddingTop});
var div = $('<div class="diff-image-stack">')
.css({height:size.height+size.paddingTop, paddingLeft:size.padding})
.append(diffOld, diffNew, bar, handle);
return {
neo:diffNew,
old:diffOld,
size:size,
handle:handle,
bar:bar,
div:div,
/* add event listener 'on mousemove' */
onMoveHandleOnBar:function(callback){
div.on('mousemove',function(e){
var x = Math.max(Math.min((e.pageX - bar.offset().left), size.barWidth), 0);
handle.css({left:x});
callback(x, e);
});
}
};
},
/** create swipe box
* @param old <img>
* @param neo <img>
* @return jQuery(<div class="diff-image-stack swipe">)
*/
swipe:function(old, neo){
var stack = this.stack(old, neo);
function setX(x){
stack.neo.css({width:x});
stack.handle.css({left:x+stack.size.padding});
}
setX(stack.size.neo.width/2);
stack.div.on('mousemove',function(e){
setX(Math.max(Math.min(e.pageX - stack.neo.offset().left, stack.size.neo.width),0));
});
return stack.div.addClass('swipe');
},
/** create blink box
* @param old <img>
* @param neo <img>
* @return jQuery(<div class="diff-image-stack blink">)
*/
blink:function(old, neo){
var stack = this.stack(old, neo);
stack.onMoveHandleOnBar(function(x){
stack.neo.toggle(Math.floor(x) % 2 === 0);
});
return stack.div.addClass('blink');
},
/** create onion skin box
* @param old <img>
* @param neo <img>
* @return jQuery(<div class="diff-image-stack onion">)
*/
onion:function(old, neo){
var stack = this.stack(old, neo);
stack.neo.css({opacity:0.5});
stack.onMoveHandleOnBar(function(x){
stack.neo.css({opacity:x/stack.size.barWidth});
});
return stack.div.addClass('onion');
},
/** create difference box
* @param old <img>
* @param neo <img>
* @return jQuery(<div class="diff-image-stack difference">)
*/
difference:function(old, neo){
var size = this.calcSizes(old,neo);
var canvas = $('<canvas>').attr({width:size.width, height:size.height})[0];
var context = canvas.getContext('2d');
context.clearRect(0, 0, size.width, size.height);
context.drawImage(neo, 0, 0, size.neo.width, size.neo.height);
var neoData = context.getImageData(0, 0, size.neo.width, size.neo.height).data;
context.clearRect(0, 0, size.width, size.height);
context.drawImage(old, 0, 0, size.old.width, size.old.height);
var c = context.getImageData(0, 0, size.neo.width, size.neo.height);
var cData = c.data;
for (var i = cData.length -1; i>0; i --){
cData[i] = (i%4===3) ? Math.max(cData[i], neoData[i]) : Math.abs(cData[i] - neoData[i]);
}
context.putImageData(c, 0, 0);
return $('<div class="diff-image-stack difference">').append(canvas);
}
};