diff --git a/src/main/scala/gitbucket/core/util/JGitUtil.scala b/src/main/scala/gitbucket/core/util/JGitUtil.scala
index 69b8c6f..096db1e 100644
--- a/src/main/scala/gitbucket/core/util/JGitUtil.scala
+++ b/src/main/scala/gitbucket/core/util/JGitUtil.scala
@@ -100,7 +100,8 @@
def isDifferentFromAuthor: Boolean = authorName != committerName || authorEmailAddress != committerEmailAddress
}
- case class DiffInfo(changeType: ChangeType, oldPath: String, newPath: String, oldContent: Option[String], newContent: Option[String])
+ case class DiffInfo(changeType: ChangeType, oldPath: String, newPath: String, oldContent: Option[String], newContent: Option[String],
+ oldIsImage: Boolean, newIsImage: Boolean, oldObjectId: Option[String], newObjectId: Option[String])
/**
* The file content data for the file content view of the repository viewer.
@@ -459,11 +460,13 @@
treeWalk.addTree(revCommit.getTree)
val buffer = new scala.collection.mutable.ListBuffer[DiffInfo]()
while(treeWalk.next){
+ val newIsImage = FileUtil.isImage(treeWalk.getPathString)
buffer.append((if(!fetchContent){
- DiffInfo(ChangeType.ADD, null, treeWalk.getPathString, None, None)
+ DiffInfo(ChangeType.ADD, null, treeWalk.getPathString, None, None, false, newIsImage, None, Option(treeWalk.getObjectId(0)).map(_.name))
} else {
DiffInfo(ChangeType.ADD, null, treeWalk.getPathString, None,
- JGitUtil.getContentFromId(git, treeWalk.getObjectId(0), false).filter(FileUtil.isText).map(convertFromByteArray))
+ JGitUtil.getContentFromId(git, treeWalk.getObjectId(0), false).filter(FileUtil.isText).map(convertFromByteArray),
+ false, newIsImage, None, Option(treeWalk.getObjectId(0)).map(_.name))
}))
}
(buffer.toList, None)
@@ -483,12 +486,15 @@
import scala.collection.JavaConverters._
git.getRepository.getConfig.setString("diff", null, "renames", "copies")
git.diff.setNewTree(newTreeIter).setOldTree(oldTreeIter).call.asScala.map { diff =>
- if(!fetchContent || FileUtil.isImage(diff.getOldPath) || FileUtil.isImage(diff.getNewPath)){
- DiffInfo(diff.getChangeType, diff.getOldPath, diff.getNewPath, None, None)
+ val oldIsImage = FileUtil.isImage(diff.getOldPath)
+ val newIsImage = FileUtil.isImage(diff.getNewPath)
+ if(!fetchContent || oldIsImage || newIsImage){
+ DiffInfo(diff.getChangeType, diff.getOldPath, diff.getNewPath, None, None, oldIsImage, newIsImage, Option(diff.getOldId).map(_.name), Option(diff.getNewId).map(_.name))
} else {
DiffInfo(diff.getChangeType, diff.getOldPath, diff.getNewPath,
JGitUtil.getContentFromId(git, diff.getOldId.toObjectId, false).filter(FileUtil.isText).map(convertFromByteArray),
- JGitUtil.getContentFromId(git, diff.getNewId.toObjectId, false).filter(FileUtil.isText).map(convertFromByteArray))
+ JGitUtil.getContentFromId(git, diff.getNewId.toObjectId, false).filter(FileUtil.isText).map(convertFromByteArray),
+ oldIsImage, newIsImage, Option(diff.getOldId).map(_.name), Option(diff.getNewId).map(_.name))
}
}.toList
}
diff --git a/src/main/twirl/gitbucket/core/helper/diff.scala.html b/src/main/twirl/gitbucket/core/helper/diff.scala.html
index 441884e..42b87c0 100644
--- a/src/main/twirl/gitbucket/core/helper/diff.scala.html
+++ b/src/main/twirl/gitbucket/core/helper/diff.scala.html
@@ -90,13 +90,32 @@
- @if(diff.newContent != None || diff.oldContent != None){
+ @if(diff.oldObjectId == diff.newObjectId){
+ File renamed without changes
+ } else { @if(diff.newContent != None || diff.oldContent != None){
+ } else { @if(diff.newIsImage || diff.oldIsImage){
+
+ @if(oldCommitId.isDefined && diff.oldIsImage){
+
+ } else {
+ @if(diff.changeType != ChangeType.ADD){
+ Not supported
+ }
+ }
+ @if(newCommitId.isDefined && diff.newIsImage){
+
+ } else {
+ @if(diff.changeType != ChangeType.DELETE){
+ Not supported
+ }
+ }
+
} else {
Not supported
- }
+ } } }
|
diff --git a/src/main/webapp/assets/common/css/gitbucket.css b/src/main/webapp/assets/common/css/gitbucket.css
index 925897b..31ac5de 100644
--- a/src/main/webapp/assets/common/css/gitbucket.css
+++ b/src/main/webapp/assets/common/css/gitbucket.css
@@ -1151,6 +1151,149 @@
white-space: nowrap;
letter-spacing: 0px;
}
+.diff-same{
+ background: #DDD;
+ color: #BBB;
+ font-size: 16px;
+ padding: 20px;
+ font-weight: bold;
+ text-align: center;
+}
+/* ------- for imageDiff */
+.diff-image-frame{
+ display: table-cell;
+ *float: left; /* for ie7 */
+ vertical-align: middle;
+ padding: 20px;
+ background-color: #eee;
+}
+.diff-image-frame.diff-old{
+ padding-right: 2px;
+}
+.diff-image-frame.diff-new{
+ padding-left: 2px;
+}
+.diff-image-frame .diff-meta{
+ margin-top: 12px;
+ color: #999;
+ font-family: Helvetica,arial,freesans,clean,sans-serif;
+ font-size: 12px;
+}
+.diff-image-frame.diff-old .diff-meta .diff{
+ color: #bd2c00;
+}
+.diff-image-frame.diff-new .diff-meta .diff{
+ color: #55a532;
+}
+.diff-image-frame img{
+ max-height: 410px;
+ max-width: 410px;
+ background: url(../images/checker.png);
+}
+.diff-image-render.diff2up{
+ width:100%;
+ text-align: center;
+ display: table;
+}
+.diff-image-frame.diff-new img{
+ border: 1px solid #55a532;
+}
+.diff-image-frame.diff-old img{
+ border: 1px solid #bd2c00;
+}
+.diff-image-stack{
+ position: relative;
+ background: #EEE;
+ padding-top: 20px;
+}
+.diff-image-stack .diff-old,
+.diff-image-stack .diff-new{
+ position:absolute;
+ overflow: hidden;
+ margin:0 20px;
+}
+.diff-image-stack img {
+ max-width: none;
+ background: url(../images/checker.png);
+}
+.diff-image-stack .diff-new{
+ border: 1px solid #55a532;
+ background: #EEE;
+}
+.diff-image-stack .diff-old{
+ border: 1px solid #bd2c00;
+}
+.diff-swipe-handle{
+ position:absolute;
+ margin-left: 325px;
+ left: 100px;
+}
+.diff-silde-bar{
+ width: 200px;
+ position: absolute;
+ left: 325px;
+ margin: 6px 0 0 7px;
+ box-sizing: border-box;
+ border: 1px solid gray;
+ height: 8px;
+}
+.image-diff-tools{
+ text-align: center;
+ padding: 4px;
+ background: #f7f7f7;
+}
+.image-diff-tools{
+ font-family: 'Helvetica Neue', Helvetica, arial, freesans, clean, sans-serif;
+ font-size: 12px;
+ background: #f7f7f7;
+ margin: 0;
+ text-align: center;
+}
+.image-diff-tools li{
+ background: none;
+ display: inline;
+ cursor: pointer;
+ border-right: 1px solid #ccc;
+ padding: 0 5px;
+ position: relative;
+ color: #666;
+}
+.image-diff-tools li:last-child{
+ border-right: none;
+}
+.image-diff-tools li.active {
+ font-weight: bold;
+}
+.no-canvas .need-canvas{
+ display: none;
+}
+.diff-image-stack.swipe .diff-new{
+ border-right: 1px solid #888;
+}
+.diff-image-stack.swipe .diff-swipe-handle{
+ margin-left: 15px;
+ left: 410px;
+}
+.diff-image-stack.swipe .diff-silde-bar{
+ display: none;
+}
+
+.diff-image-stack.onion .diff-silde-bar{
+ background: -ms-linear-gradient(left, #bd2c00 0%,#55a532 100%); /* IE10+ */
+ background: linear-gradient(to right, #bd2c00 0%,#55a532 100%);
+ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#bd2c00', endColorstr='#55a532',GradientType=1 ); /* IE6-9 */
+}
+
+.diff-image-stack.blink .diff-silde-bar{
+ border-style: dotted;
+ background-image: linear-gradient(to right, #bd2c00, #bd2c00 50%, #55a532 50%, #55a532 100%);
+ background-size: 2px 2px;
+}
+
+.diff-image-stack.difference {
+ padding-bottom: 18px;
+ text-align: center;
+}
/****************************************************************************/
/* Repository Settings */
/****************************************************************************/
diff --git a/src/main/webapp/assets/common/images/checker.png b/src/main/webapp/assets/common/images/checker.png
new file mode 100644
index 0000000..07e2115
--- /dev/null
+++ b/src/main/webapp/assets/common/images/checker.png
Binary files differ
diff --git a/src/main/webapp/assets/common/js/gitbucket.js b/src/main/webapp/assets/common/js/gitbucket.js
index e10b2fb..47ec3a9 100644
--- a/src/main/webapp/assets/common/js/gitbucket.js
+++ b/src/main/webapp/assets/common/js/gitbucket.js
@@ -334,3 +334,211 @@
return ret;
}
});
+/****************************************************************************/
+/* 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
+ */
+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
+ * @param old
![]()
||undefined
+ * @param neo
![]()
||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 = $('
W: | W:
');
+ 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 $('