Expand/Collapse Files and Blob Excerpt while Reviewing/Comparing code (#8924)

* update #8659 fold/unfold code diffs

* add fold button style

* update #8659 implement expand up/down codes (blob excerpt)

* fix golint errors

* fix expand direction

* remove debug message

* update css style for blob exceprt

* fix typo in comment

* update style sheet with less

* update expect diff (add SectionInfo)

* update #8942 accept suggested change (fix typo)

* close reader and check file type before get tail section

* adjust button position and check file type before insert fold button

* move index js to web_src

* merge index.js with master

* generate index.js

* update js coding style
This commit is contained in:
Benno authored and Lunny Xiao committed 2019-11-15 10:52:59 +08:00
1 parent 42ada741e3
commit 149a9df9e8
16 files changed
+460 -36

No files matched your search

+23
View File
@@ -6,6 +6,7 @@
package git package git
import ( import (
"bytes"
"encoding/base64" "encoding/base64"
"io" "io"
"io/ioutil" "io/ioutil"
@@ -50,6 +51,28 @@ func (b *Blob) GetBlobContent() (string, error) {
return string(buf), nil return string(buf), nil
} }
// GetBlobLineCount gets line count of lob as raw text
func (b *Blob) GetBlobLineCount() (int, error) {
reader, err := b.DataAsync()
if err != nil {
return 0, err
}
defer reader.Close()
buf := make([]byte, 32*1024)
count := 0
lineSep := []byte{'\n'}
for {
c, err := reader.Read(buf)
count += bytes.Count(buf[:c], lineSep)
switch {
case err == io.EOF:
return count, nil
case err != nil:
return count, err
}
}
}
// GetBlobContentBase64 Reads the content of the blob with a base64 encode and returns the encoded string // GetBlobContentBase64 Reads the content of the blob with a base64 encode and returns the encoded string
func (b *Blob) GetBlobContentBase64() (string, error) { func (b *Blob) GetBlobContentBase64() (string, error) {
dataRc, err := b.DataAsync() dataRc, err := b.DataAsync()
+9
View File
@@ -55,6 +55,15 @@ func TestGetDiffPreview(t *testing.T) {
Type: 4, Type: 4,
Content: "@@ -1,3 +1,4 @@", Content: "@@ -1,3 +1,4 @@",
Comments: nil, Comments: nil,
SectionInfo: &gitdiff.DiffLineSectionInfo{
Path: "README.md",
LastLeftIdx: 0,
LastRightIdx: 0,
LeftIdx: 1,
RightIdx: 1,
LeftHunkSize: 3,
RightHunkSize: 4,
},
}, },
{ {
LeftIdx: 1, LeftIdx: 1,
+6 -1
View File
@@ -898,6 +898,7 @@ tbody.commit-list{vertical-align:baseline}
.repo-buttons .disabled-repo-button a.button:hover{background:0 0!important;color:rgba(0,0,0,.6)!important;box-shadow:0 0 0 1px rgba(34,36,38,.15) inset!important} .repo-buttons .disabled-repo-button a.button:hover{background:0 0!important;color:rgba(0,0,0,.6)!important;box-shadow:0 0 0 1px rgba(34,36,38,.15) inset!important}
.repo-buttons .ui.labeled.button>.label{border-left:0!important;margin:0!important} .repo-buttons .ui.labeled.button>.label{border-left:0!important;margin:0!important}
.tag-code,.tag-code td{background-color:#f0f0f0!important;border-color:#d3cfcf!important;padding-top:8px;padding-bottom:8px} .tag-code,.tag-code td{background-color:#f0f0f0!important;border-color:#d3cfcf!important;padding-top:8px;padding-bottom:8px}
td.blob-excerpt{background-color:#fafafa}
.issue-keyword{border-bottom:1px dotted #959da5;display:inline-block} .issue-keyword{border-bottom:1px dotted #959da5;display:inline-block}
.file-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px!important} .file-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px!important}
.file-info{display:flex;align-items:center} .file-info{display:flex;align-items:center}
@@ -1068,4 +1069,8 @@ tbody.commit-list{vertical-align:baseline}
.comment-code-cloud .footer:after{clear:both;content:"";display:block} .comment-code-cloud .footer:after{clear:both;content:"";display:block}
.comment-code-cloud button.comment-form-reply{margin:.5em .5em .5em 4.5em} .comment-code-cloud button.comment-form-reply{margin:.5em .5em .5em 4.5em}
.comment-code-cloud form.comment-form-reply{margin:0 0 0 4em} .comment-code-cloud form.comment-form-reply{margin:0 0 0 4em}
.file-comment{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;color:rgba(0,0,0,.87)} .file-comment{font:12px 'SF Mono',Consolas,Menlo,'Liberation Mono',Monaco,'Lucida Console',monospace;color:rgba(0,0,0,.87)}
.ui.fold-code{margin-right:1em;padding-left:5px;cursor:pointer;width:22px;font-size:12px}
.ui.fold-code:hover{color:#428bca}
.ui.blob-excerpt{display:block;line-height:20px;font-size:16px;cursor:pointer}
.ui.blob-excerpt:hover{color:#428bca}
+1 -1
View File
@@ -1,2 +1,2 @@
!function(e){var t={};function a(i){if(t[i])return t[i].exports;var n=t[i]={i:i,l:!1,exports:{}};return e[i].call(n.exports,n,n.exports,a),n.l=!0,n.exports}a.m=e,a.c=t,a.d=function(e,t,i){a.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,t){if(1&t&&(e=a(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(a.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)a.d(i,n,function(t){return e[t]}.bind(null,n));return i},a.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(t,"a",t),t},a.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},a.p="",a(a.s=0)}([function(e,t,a){a(1),e.exports=a(2)},function(e,t){function a(e){return jQuery("<div />").text(e).html()}var i,n,o,r,s;function c(e){var t=e.find(".tabular.menu");t.find(".item").tab(),t.find('.item[data-tab="'.concat(t.data("preview"),'"]')).click((function(){var a=$(this);$.post(a.data("url"),{_csrf:i,mode:"gfm",context:a.data("context"),text:e.find('.tab.segment[data-tab="'.concat(t.data("write"),'"] textarea')).val()},(function(a){var i=e.find('.tab.segment[data-tab="'.concat(t.data("preview"),'"]'));i.html(a),emojify.run(i[0]),$("pre code",i[0]).each((function(){hljs.highlightBlock(this)}))}))})),w()}function l(){var e,t;0!==$(".edit.form").length&&(!function(e){var t=e.find(".tabular.menu");t.find(".item").tab();var a=t.find('.item[data-tab="'.concat(t.data("preview"),'"]'));a.length&&(o=a.data("preview-file-modes").split(","),a.click((function(){var a=$(this);$.post(a.data("url"),{_csrf:i,mode:"gfm",context:a.data("context"),text:e.find('.tab.segment[data-tab="'.concat(t.data("write"),'"] textarea')).val()},(function(a){var i=e.find('.tab.segment[data-tab="'.concat(t.data("preview"),'"]'));i.html(a),emojify.run(i[0]),$("pre code",i[0]).each((function(){hljs.highlightBlock(this)}))}))})))}($(".edit.form")),e=$(".edit.form"),(t=e.find(".tabular.menu")).find(".item").tab(),t.find('.item[data-tab="'.concat(t.data("diff"),'"]')).click((function(){var a=$(this);$.post(a.data("url"),{_csrf:i,context:a.data("context"),content:e.find('.tab.segment[data-tab="'.concat(t.data("write"),'"] textarea')).val()},(function(a){var i=e.find('.tab.segment[data-tab="'.concat(t.data("diff"),'"]'));i.html(a),emojify.run(i[0])}))})))}function d(e,t,a,n){return new Promise((function(o){$.ajax({type:"POST",url:e,data:{_csrf:i,action:t,issue_ids:a,id:n},success:o})}))}function u(){window.location.reload()}function h(e){e.each((function(){var e=this;e.addEventListener("paste",(function(t){!function(e,t){if(e.clipboardData){var a=e.clipboardData.items;if(void 0!==a)for(var i=0;i<a.length;i++)if(-1!==a[i].type.indexOf("image")){var n=a[i].getAsFile();"function"==typeof t&&(e.preventDefault(),e.stopPropagation(),t(n))}}}(t,(function(t){var a=t.name.substr(0,t.name.lastIndexOf("."));!function(e,t){if(e.selectionStart||0===e.selectionStart){var a=e.selectionStart,i=e.selectionEnd;e.value=e.value.substring(0,a)+t+e.value.substring(i,e.value.length),e.selectionStart=a+t.length,e.selectionEnd=a+t.length}else e.value+=t}(e,"![".concat(a,"]()")),function(e,t){var a=new XMLHttpRequest;a.onload=function(){200===a.status&&t(a.responseText)},a.open("post","".concat(n,"/attachments"),!0),a.setRequestHeader("X-Csrf-Token",i);var o=new FormData;o.append("file",e,e.name),a.send(o)}(t,(function(t){var i=JSON.parse(t);!function(e,t,a){if(e.selectionStart||0===e.selectionStart){var i=e.selectionStart,n=e.selectionEnd;e.value=e.value.replace(t,a),e.selectionStart=i+a.length-t.length,e.selectionEnd=n+a.length-t.length}else e.value=e.value.replace(t,a)}(e,"![".concat(a,"]()"),"![".concat(a,"](").concat(n,"/attachments/").concat(i.uuid,")"));var o=$('<input id="'.concat(i.uuid,'" name="files" type="hidden">')).val(i.uuid);$(".files").append(o)}))}))}),!1)}))}function f(){var e;0!==$(".comment.form").length&&((e=$(".ui.select-branch")).find(".reference-list-menu").find(".item:not(.no-select)").click((function(){var t=$(this).data("id");$($(this).data("id-selector")).val(t),e.find(".ui .branch-name").text(t)})),e.find(".reference.column").click((function(){return e.find(".scrolling.reference-list-menu").css("display","none"),e.find(".reference .text").removeClass("black"),$($(this).data("target")).css("display","block"),$(this).find(".text").addClass("black"),!1})),c($(".comment.form")),h($(".comment.form textarea")),t("select-label","labels"),t("select-assignees","assignees"),t("select-assignees-modify","assignees"),i(".select-milestone","#milestone_id"),i(".select-assignee","#assignee_id"));function t(e,t){var a=$(".ui.".concat(t,".list")),i=a.find(".no-select"),n=$(".".concat(e," .menu")),o="update"===n.data("action"),r={};$(".".concat(e)).dropdown("settingLine truncated !function(e){var t={};function a(i){if(t[i])return t[i].exports;var n=t[i]={i:i,l:!1,exports:{}};return e[i].call(n.exports,n,n.exports,a),n.l=!0,n.exports}a.m=e,a.c=t,a.d=function(e,t,i){a.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},a.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.t=function(e,t){if(1&t&&(e=a(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(a.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)a.d(i,n,function(t){return e[t]}.bind(null,n));return i},a.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return a.d(t,"a",t),t},a.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},a.p="",a(a.s=0)}([function(e,t,a){a(1),e.exports=a(2)},function(e,t){function a(e){return jQuery("<div />").text(e).html()}var i,n,o,r,s;function c(e){var t=e.find(".tabular.menu");t.find(".item").tab(),t.find('.item[data-tab="'.concat(t.data("preview"),'"]')).click((function(){var a=$(this);$.post(a.data("url"),{_csrf:i,mode:"gfm",context:a.data("context"),text:e.find('.tab.segment[data-tab="'.concat(t.data("write"),'"] textarea')).val()},(function(a){var i=e.find('.tab.segment[data-tab="'.concat(t.data("preview"),'"]'));i.html(a),emojify.run(i[0]),$("pre code",i[0]).each((function(){hljs.highlightBlock(this)}))}))})),w()}function l(){var e,t;0!==$(".edit.form").length&&(!function(e){var t=e.find(".tabular.menu");t.find(".item").tab();var a=t.find('.item[data-tab="'.concat(t.data("preview"),'"]'));a.length&&(o=a.data("preview-file-modes").split(","),a.click((function(){var a=$(this);$.post(a.data("url"),{_csrf:i,mode:"gfm",context:a.data("context"),text:e.find('.tab.segment[data-tab="'.concat(t.data("write"),'"] textarea')).val()},(function(a){var i=e.find('.tab.segment[data-tab="'.concat(t.data("preview"),'"]'));i.html(a),emojify.run(i[0]),$("pre code",i[0]).each((function(){hljs.highlightBlock(this)}))}))})))}($(".edit.form")),e=$(".edit.form"),(t=e.find(".tabular.menu")).find(".item").tab(),t.find('.item[data-tab="'.concat(t.data("diff"),'"]')).click((function(){var a=$(this);$.post(a.data("url"),{_csrf:i,context:a.data("context"),content:e.find('.tab.segment[data-tab="'.concat(t.data("write"),'"] textarea')).val()},(function(a){var i=e.find('.tab.segment[data-tab="'.concat(t.data("diff"),'"]'));i.html(a),emojify.run(i[0])}))})))}function d(e,t,a,n){return new Promise((function(o){$.ajax({type:"POST",url:e,data:{_csrf:i,action:t,issue_ids:a,id:n},success:o})}))}function u(){window.location.reload()}function h(e){e.each((function(){var e=this;e.addEventListener("paste",(function(t){!function(e,t){if(e.clipboardData){var a=e.clipboardData.items;if(void 0!==a)for(var i=0;i<a.length;i++)if(-1!==a[i].type.indexOf("image")){var n=a[i].getAsFile();"function"==typeof t&&(e.preventDefault(),e.stopPropagation(),t(n))}}}(t,(function(t){var a=t.name.substr(0,t.name.lastIndexOf("."));!function(e,t){if(e.selectionStart||0===e.selectionStart){var a=e.selectionStart,i=e.selectionEnd;e.value=e.value.substring(0,a)+t+e.value.substring(i,e.value.length),e.selectionStart=a+t.length,e.selectionEnd=a+t.length}else e.value+=t}(e,"![".concat(a,"]()")),function(e,t){var a=new XMLHttpRequest;a.onload=function(){200===a.status&&t(a.responseText)},a.open("post","".concat(n,"/attachments"),!0),a.setRequestHeader("X-Csrf-Token",i);var o=new FormData;o.append("file",e,e.name),a.send(o)}(t,(function(t){var i=JSON.parse(t);!function(e,t,a){if(e.selectionStart||0===e.selectionStart){var i=e.selectionStart,n=e.selectionEnd;e.value=e.value.replace(t,a),e.selectionStart=i+a.length-t.length,e.selectionEnd=n+a.length-t.length}else e.value=e.value.replace(t,a)}(e,"![".concat(a,"]()"),"![".concat(a,"](").concat(n,"/attachments/").concat(i.uuid,")"));var o=$('<input id="'.concat(i.uuid,'" name="files" type="hidden">')).val(i.uuid);$(".files").append(o)}))}))}),!1)}))}function f(){var e;0!==$(".comment.form").length&&((e=$(".ui.select-branch")).find(".reference-list-menu").find(".item:not(.no-select)").click((function(){var t=$(this).data("id");$($(this).data("id-selector")).val(t),e.find(".ui .branch-name").text(t)})),e.find(".reference.column").click((function(){return e.find(".scrolling.reference-list-menu").css("display","none"),e.find(".reference .text").removeClass("black"),$($(this).data("target")).css("display","block"),$(this).find(".text").addClass("black"),!1})),c($(".comment.form")),h($(".comment.form textarea")),t("select-label","labels"),t("select-assignees","assignees"),t("select-assignees-modify","assignees"),i(".select-milestone","#milestone_id"),i(".select-assignee","#assignee_id"));function t(e,t){var a=$(".ui.".concat(t,".list")),i=a.find(".no-select"),n=$(".".concat(e," .menu")),o="update"===n.data("action"),r={};$(".".concat(e)).dropdown("settingLine truncated
//# sourceMappingURL=index.js.map //# sourceMappingURL=index.js.map
+1 -1
View File
@@ -1 +1 @@
{"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./web_src/js/index.js","webpack:///./web_src/js/draw.js"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","htmlEncode","text","jQuery","html","csrf","suburl","previewFileModes","simpleMDEditor","codeMirrorEditor","initCommentPreviewTab","$form","$tabMenu","find","tab","data","click","$this","$","this","post","_csrf","context","val","$previewPanel","emojify","run","each","hljs","highlightBlock","buttonsClickOnEnter","initEditForm","length","$previewTab","split","initEditPreviewTab","content","$diffPreviewPanel","updateIssuesMeta","url","action","issueIds","elementId","Promise","resolve","ajax","type","issue_ids","id","success","reload","window","location","initImagePaste","target","field","addEventListener","event","pasteEvent","callback","clipboardData","items","indexOf","blob","getAsFile","preventDefault","stopPropagation","retrieveImageFromClipboardAsBlob","img","substr","lastIndexOf","selectionStart","startPos","endPos","selectionEnd","substring","insertAtCursor","file","xhr","XMLHttpRequest","onload","status","responseText","open","setRequestHeader","formData","FormData","append","send","uploadFile","res","JSON","parse","oldval","newval","replace","replaceAndKeepCursor","uuid","input","initCommentForm","$selectBranch","selectedValue","css","removeClass","addClass","initListSubmits","selectItem","selector","outerSelector","$list","$noSelect","$listMenu","hasLabelUpdateAction","labels","dropdown","promises","keys","forEach","label","promise","push","all","then","hasClass","listIds","parent","join","select_id","input_id","$menu","hasUpdateAction","initRepository","$data","searchTerm","noResults","canCreateBranch","menuVisible","active","branch","tag","selected","remove","Vue","delimiters","el","beforeMount","vm","$el","getAttribute","document","body","contains","set","watch","visible","focusSearchField","computed","filteredItems","filter","item","toLowerCase","showCreateNewBranch","showNoResults","methods","prev","getSelected","href","createNewBranch","$refs","newBranchForm","submit","nextTick","searchField","focus","j","getSelectedIndexInFiltered","scrollToActive","Array","isArray","cont","scrollContainer","offsetTop","scrollTop","clientHeight","keydown","keyCode","initFilterSearchDropdown","keyup","$prompt","toString","show","hide","change","checked","$newLabelPanel","minicolors","color_hex","modal","onApprove","$datepicker","datetimepicker","lang","inline","timepicker","startDate","formatDate","onSelectDate","ct","dateFormat","$issueTitle","$editInput","editTitleToggle","toggle","title","$textarea","$segment","next","$editContentZone","$renderContent","$rawContent","issuesTribute","attach","emojiTribute","$dropzone","$files","filenameDict","dropzone","headers","maxFiles","maxFilesize","acceptedFiles","addRemoveLinks","dictDefaultMessage","dictInvalidFileType","dictFileTooBig","dictRemoveFile","init","on","submitted","getJSON","drop","removeAllFiles","empty","imgSrc","emit","files","$editContentForm","attr","$attachments","map","$content","attachments","confirm","$statusButton","$mergeButton","e","onChange","_text","_value","$choice","closest","initReactionSelector","reactions","popup","position","metadata","actionURL","done","resp","react","insertBefore","appendTo","hasEmoji","$item","addLine","delLine","addPercent","parseFloat","localStorage","setItem","select","$repoComparePull","$dropdown","fullTextSearch","selectOnKeydown","message","assingMenuAttributes","menu","Math","floor","random","initRepositoryCollaboration","uid","initEditor","prop","$editFilename","parts","$section","$divider","getCursorPosition","last","setSelectionRange","element","trigger","$editArea","markdownFileExts","lineWrapExtensions","spec","extension","extWithDot","dataUrl","apiCall","exec","info","CodeMirror","findModeByExtension","previewLink","mime","toTextArea","SimpleMDE","autoDownloadFontAwesome","forceSync","renderingConfig","singleLineBreaks","indentWithTabs","tabSize","spellChecker","previewRender","plainText","preview","setTimeout","innerHTML","toolbar","setSimpleMDE","fromTextArea","lineNumbers","cm","_change","getValue","setCodeMirror","setOption","autoLoadMode","editorconfig","indent_style","Tab","spaces","parseInt","getOption","replaceSelection","indent_size","tab_width","$commitButton","$editForm","areYouSure","silent","dirtyClass","fieldSelector","dirty","initUserSettings","keypress","initCodeView","$select","siblings","selectRange","shiftKey","eq","getSelection","removeAllRanges","selection","$first","hash","match","offset","top","u2fSigned","stringify","contentType","fail","u2fError","u2fRegistered","errorCode","checkError","errorType","u2fErrors","browser","1","2","3",Line truncated {"version":3,"sources":["webpack:///webpack/bootstrap","webpack:///./web_src/js/index.js","webpack:///./web_src/js/draw.js"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","htmlEncode","text","jQuery","html","csrf","suburl","previewFileModes","simpleMDEditor","codeMirrorEditor","initCommentPreviewTab","$form","$tabMenu","find","tab","data","click","$this","$","this","post","_csrf","context","val","$previewPanel","emojify","run","each","hljs","highlightBlock","buttonsClickOnEnter","initEditForm","length","$previewTab","split","initEditPreviewTab","content","$diffPreviewPanel","updateIssuesMeta","url","action","issueIds","elementId","Promise","resolve","ajax","type","issue_ids","id","success","reload","window","location","initImagePaste","target","field","addEventListener","event","pasteEvent","callback","clipboardData","items","indexOf","blob","getAsFile","preventDefault","stopPropagation","retrieveImageFromClipboardAsBlob","img","substr","lastIndexOf","selectionStart","startPos","endPos","selectionEnd","substring","insertAtCursor","file","xhr","XMLHttpRequest","onload","status","responseText","open","setRequestHeader","formData","FormData","append","send","uploadFile","res","JSON","parse","oldval","newval","replace","replaceAndKeepCursor","uuid","input","initCommentForm","$selectBranch","selectedValue","css","removeClass","addClass","initListSubmits","selectItem","selector","outerSelector","$list","$noSelect","$listMenu","hasLabelUpdateAction","labels","dropdown","promises","keys","forEach","label","promise","push","all","then","hasClass","listIds","parent","join","select_id","input_id","$menu","hasUpdateAction","initRepository","$data","searchTerm","noResults","canCreateBranch","menuVisible","active","branch","tag","selected","remove","Vue","delimiters","el","beforeMount","vm","$el","getAttribute","document","body","contains","set","watch","visible","focusSearchField","computed","filteredItems","filter","item","toLowerCase","showCreateNewBranch","showNoResults","methods","prev","getSelected","href","createNewBranch","$refs","newBranchForm","submit","nextTick","searchField","focus","j","getSelectedIndexInFiltered","scrollToActive","Array","isArray","cont","scrollContainer","offsetTop","scrollTop","clientHeight","keydown","keyCode","initFilterSearchDropdown","keyup","$prompt","toString","show","hide","change","checked","$newLabelPanel","minicolors","color_hex","modal","onApprove","$datepicker","datetimepicker","lang","inline","timepicker","startDate","formatDate","onSelectDate","ct","dateFormat","$issueTitle","$editInput","editTitleToggle","toggle","title","$textarea","$segment","next","$editContentZone","$renderContent","$rawContent","issuesTribute","attach","emojiTribute","$dropzone","$files","filenameDict","dropzone","headers","maxFiles","maxFilesize","acceptedFiles","addRemoveLinks","dictDefaultMessage","dictInvalidFileType","dictFileTooBig","dictRemoveFile","init","on","submitted","getJSON","drop","removeAllFiles","empty","imgSrc","emit","files","$editContentForm","attr","$attachments","map","$content","attachments","confirm","$statusButton","$mergeButton","e","onChange","_text","_value","$choice","closest","initReactionSelector","reactions","popup","position","metadata","actionURL","done","resp","react","insertBefore","appendTo","hasEmoji","$item","addLine","delLine","addPercent","parseFloat","localStorage","setItem","select","$repoComparePull","$dropdown","fullTextSearch","selectOnKeydown","message","assingMenuAttributes","menu","Math","floor","random","initRepositoryCollaboration","uid","initEditor","prop","$editFilename","parts","$section","$divider","getCursorPosition","last","setSelectionRange","element","trigger","$editArea","markdownFileExts","lineWrapExtensions","spec","extension","extWithDot","dataUrl","apiCall","exec","info","CodeMirror","findModeByExtension","previewLink","mime","toTextArea","SimpleMDE","autoDownloadFontAwesome","forceSync","renderingConfig","singleLineBreaks","indentWithTabs","tabSize","spellChecker","previewRender","plainText","preview","setTimeout","innerHTML","toolbar","setSimpleMDE","fromTextArea","lineNumbers","cm","_change","getValue","setCodeMirror","setOption","autoLoadMode","editorconfig","indent_style","Tab","spaces","parseInt","getOption","replaceSelection","indent_size","tab_width","$commitButton","$editForm","areYouSure","silent","dirtyClass","fieldSelector","dirty","initUserSettings","keypress","initCodeView","$select","siblings","selectRange","shiftKey","eq","getSelection","removeAllRanges","selection","$first","hash","match","offset","top","$foldButton","slideUp","slideDown","insertBlobExcerpt","$blob","$row","replaceWith","u2fSigned","stringify","contentType","fail","u2fError","uLine truncated
+1
View File
@@ -245,6 +245,7 @@ func Diff(ctx *context.Context) {
} }
ctx.Data["CommitID"] = commitID ctx.Data["CommitID"] = commitID
ctx.Data["AfterCommitID"] = commitID
ctx.Data["Username"] = userName ctx.Data["Username"] = userName
ctx.Data["Reponame"] = repoName ctx.Data["Reponame"] = repoName
+112 -1
View File
@@ -5,21 +5,26 @@
package repo package repo
import ( import (
"bufio"
"fmt" "fmt"
"html"
"path" "path"
"path/filepath"
"strings" "strings"
"code.gitea.io/gitea/models" "code.gitea.io/gitea/models"
"code.gitea.io/gitea/modules/base" "code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/context" "code.gitea.io/gitea/modules/context"
"code.gitea.io/gitea/modules/git" "code.gitea.io/gitea/modules/git"
"code.gitea.io/gitea/modules/highlight"
"code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/gitdiff" "code.gitea.io/gitea/services/gitdiff"
) )
const ( const (
tplCompare base.TplName = "repo/diff/compare" tplCompare base.TplName = "repo/diff/compare"
tplBlobExcerpt base.TplName = "repo/diff/blob_excerpt"
) )
// setPathsCompareContext sets context data for source and raw paths // setPathsCompareContext sets context data for source and raw paths
@@ -434,3 +439,109 @@ func CompareDiff(ctx *context.Context) {
ctx.HTML(200, tplCompare) ctx.HTML(200, tplCompare)
} }
// ExcerptBlob render blob excerpt contents
func ExcerptBlob(ctx *context.Context) {
commitID := ctx.Params("sha")
lastLeft := ctx.QueryInt("last_left")
lastRight := ctx.QueryInt("last_right")
idxLeft := ctx.QueryInt("left")
idxRight := ctx.QueryInt("right")
leftHunkSize := ctx.QueryInt("left_hunk_size")
rightHunkSize := ctx.QueryInt("right_hunk_size")
anchor := ctx.Query("anchor")
direction := ctx.Query("direction")
filePath := ctx.Query("path")
gitRepo := ctx.Repo.GitRepo
chunkSize := gitdiff.BlobExceprtChunkSize
commit, err := gitRepo.GetCommit(commitID)
if err != nil {
ctx.Error(500, "GetCommit")
return
}
section := &gitdiff.DiffSection{
Name: filePath,
}
if direction == "up" && (idxLeft-lastLeft) > chunkSize {
idxLeft -= chunkSize
idxRight -= chunkSize
leftHunkSize += chunkSize
rightHunkSize += chunkSize
section.Lines, err = getExcerptLines(commit, filePath, idxLeft-1, idxRight-1, chunkSize)
} else if direction == "down" && (idxLeft-lastLeft) > chunkSize {
section.Lines, err = getExcerptLines(commit, filePath, lastLeft, lastRight, chunkSize)
lastLeft += chunkSize
lastRight += chunkSize
} else {
section.Lines, err = getExcerptLines(commit, filePath, lastLeft, lastRight, idxRight-lastRight-1)
leftHunkSize = 0
rightHunkSize = 0
idxLeft = lastLeft
idxRight = lastRight
}
if err != nil {
ctx.Error(500, "getExcerptLines")
return
}
if idxRight > lastRight {
lineText := " "
if rightHunkSize > 0 || leftHunkSize > 0 {
lineText = fmt.Sprintf("@@ -%d,%d +%d,%d @@\n", idxLeft, leftHunkSize, idxRight, rightHunkSize)
}
lineText = html.EscapeString(lineText)
lineSection := &gitdiff.DiffLine{
Type: gitdiff.DiffLineSection,
Content: lineText,
SectionInfo: &gitdiff.DiffLineSectionInfo{
Path: filePath,
LastLeftIdx: lastLeft,
LastRightIdx: lastRight,
LeftIdx: idxLeft,
RightIdx: idxRight,
LeftHunkSize: leftHunkSize,
RightHunkSize: rightHunkSize,
}}
if direction == "up" {
section.Lines = append([]*gitdiff.DiffLine{lineSection}, section.Lines...)
} else if direction == "down" {
section.Lines = append(section.Lines, lineSection)
}
}
ctx.Data["section"] = section
ctx.Data["fileName"] = filePath
ctx.Data["highlightClass"] = highlight.FileNameToHighlightClass(filepath.Base(filePath))
ctx.Data["AfterCommitID"] = commitID
ctx.Data["Anchor"] = anchor
ctx.HTML(200, tplBlobExcerpt)
}
func getExcerptLines(commit *git.Commit, filePath string, idxLeft int, idxRight int, chunkSize int) ([]*gitdiff.DiffLine, error) {
blob, err := commit.Tree.GetBlobByPath(filePath)
if err != nil {
return nil, err
}
reader, err := blob.DataAsync()
if err != nil {
return nil, err
}
defer reader.Close()
scanner := bufio.NewScanner(reader)
var diffLines []*gitdiff.DiffLine
for line := 0; line < idxRight+chunkSize; line++ {
if ok := scanner.Scan(); !ok {
break
}
if line < idxRight {
continue
}
lineText := scanner.Text()
diffLine := &gitdiff.DiffLine{
LeftIdx: idxLeft + (line - idxRight) + 1,
RightIdx: line + 1,
Type: gitdiff.DiffLinePlain,
Content: " " + lineText,
}
diffLines = append(diffLines, diffLine)
}
return diffLines, nil
}
+1
View File
@@ -552,6 +552,7 @@ func ViewPullFiles(ctx *context.Context) {
ctx.Data["Username"] = pull.MustHeadUserName() ctx.Data["Username"] = pull.MustHeadUserName()
ctx.Data["Reponame"] = pull.HeadRepo.Name ctx.Data["Reponame"] = pull.HeadRepo.Name
} }
ctx.Data["AfterCommitID"] = endCommitID
diff, err := gitdiff.GetDiffRangeWithWhitespaceBehavior(diffRepoPath, diff, err := gitdiff.GetDiffRangeWithWhitespaceBehavior(diffRepoPath,
startCommitID, endCommitID, setting.Git.MaxGitDiffLines, startCommitID, endCommitID, setting.Git.MaxGitDiffLines,
+4
View File
@@ -864,6 +864,10 @@ func RegisterRoutes(m *macaron.Macaron) {
m.Get("", repo.Branches) m.Get("", repo.Branches)
}, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader) }, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader)
m.Group("/blob_excerpt", func() {
m.Get("/:sha", repo.SetEditorconfigIfExists, repo.SetDiffViewStyle, repo.ExcerptBlob)
}, repo.MustBeNotEmpty, context.RepoRef(), reqRepoCodeReader)
m.Group("/pulls/:index", func() { m.Group("/pulls/:index", func() {
m.Get(".diff", repo.DownloadPullDiff) m.Get(".diff", repo.DownloadPullDiff)
m.Get(".patch", repo.DownloadPullPatch) m.Get(".patch", repo.DownloadPullPatch)
+163 -17
View File
@@ -13,6 +13,7 @@ import (
"html/template" "html/template"
"io" "io"
"io/ioutil" "io/ioutil"
"net/url"
"os" "os"
"os/exec" "os/exec"
"regexp" "regexp"
@@ -56,15 +57,42 @@ const (
DiffFileRename DiffFileRename
) )
// DiffLineExpandDirection represents the DiffLineSection expand direction
type DiffLineExpandDirection uint8
// DiffLineExpandDirection possible values.
const (
DiffLineExpandNone DiffLineExpandDirection = iota + 1
DiffLineExpandSingle
DiffLineExpandUpDown
DiffLineExpandUp
DiffLineExpandDown
)
// DiffLine represents a line difference in a DiffSection. // DiffLine represents a line difference in a DiffSection.
type DiffLine struct { type DiffLine struct {
LeftIdx int LeftIdx int
RightIdx int RightIdx int
Type DiffLineType Type DiffLineType
Content string Content string
Comments []*models.Comment Comments []*models.Comment
SectionInfo *DiffLineSectionInfo
} }
// DiffLineSectionInfo represents diff line section meta data
type DiffLineSectionInfo struct {
Path string
LastLeftIdx int
LastRightIdx int
LeftIdx int
RightIdx int
LeftHunkSize int
RightHunkSize int
}
// BlobExceprtChunkSize represent max lines of excerpt
const BlobExceprtChunkSize = 20
// GetType returns the type of a DiffLine. // GetType returns the type of a DiffLine.
func (d *DiffLine) GetType() int { func (d *DiffLine) GetType() int {
return int(d.Type) return int(d.Type)
@@ -91,6 +119,71 @@ func (d *DiffLine) GetLineTypeMarker() string {
return "" return ""
} }
// GetBlobExcerptQuery builds query string to get blob excerpt
func (d *DiffLine) GetBlobExcerptQuery() string {
query := fmt.Sprintf(
"last_left=%d&last_right=%d&"+
"left=%d&right=%d&"+
"left_hunk_size=%d&right_hunk_size=%d&"+
"path=%s",
d.SectionInfo.LastLeftIdx, d.SectionInfo.LastRightIdx,
d.SectionInfo.LeftIdx, d.SectionInfo.RightIdx,
d.SectionInfo.LeftHunkSize, d.SectionInfo.RightHunkSize,
url.QueryEscape(d.SectionInfo.Path))
return query
}
// GetExpandDirection gets DiffLineExpandDirection
func (d *DiffLine) GetExpandDirection() DiffLineExpandDirection {
if d.Type != DiffLineSection || d.SectionInfo == nil || d.SectionInfo.RightIdx-d.SectionInfo.LastRightIdx <= 1 {
return DiffLineExpandNone
}
if d.SectionInfo.LastLeftIdx <= 0 && d.SectionInfo.LastRightIdx <= 0 {
return DiffLineExpandUp
} else if d.SectionInfo.RightIdx-d.SectionInfo.LastRightIdx > BlobExceprtChunkSize && d.SectionInfo.RightHunkSize > 0 {
return DiffLineExpandUpDown
} else if d.SectionInfo.LeftHunkSize <= 0 && d.SectionInfo.RightHunkSize <= 0 {
return DiffLineExpandDown
}
return DiffLineExpandSingle
}
func getDiffLineSectionInfo(curFile *DiffFile, line string, lastLeftIdx, lastRightIdx int) *DiffLineSectionInfo {
var (
leftLine int
leftHunk int
rightLine int
righHunk int
)
ss := strings.Split(line, "@@")
ranges := strings.Split(ss[1][1:], " ")
leftRange := strings.Split(ranges[0], ",")
leftLine, _ = com.StrTo(leftRange[0][1:]).Int()
if len(leftRange) > 1 {
leftHunk, _ = com.StrTo(leftRange[1]).Int()
}
if len(ranges) > 1 {
rightRange := strings.Split(ranges[1], ",")
rightLine, _ = com.StrTo(rightRange[0]).Int()
if len(rightRange) > 1 {
righHunk, _ = com.StrTo(rightRange[1]).Int()
}
} else {
log.Warn("Parse line number failed: %v", line)
rightLine = leftLine
righHunk = leftHunk
}
return &DiffLineSectionInfo{
Path: curFile.Name,
LastLeftIdx: lastLeftIdx,
LastRightIdx: lastRightIdx,
LeftIdx: leftLine,
RightIdx: rightLine,
LeftHunkSize: leftHunk,
RightHunkSize: righHunk,
}
}
// escape a line's content or return <br> needed for copy/paste purposes // escape a line's content or return <br> needed for copy/paste purposes
func getLineContent(content string) string { func getLineContent(content string) string {
if len(content) > 0 { if len(content) > 0 {
@@ -248,6 +341,53 @@ func (diffFile *DiffFile) GetHighlightClass() string {
return highlight.FileNameToHighlightClass(diffFile.Name) return highlight.FileNameToHighlightClass(diffFile.Name)
} }
// GetTailSection creates a fake DiffLineSection if the last section is not the end of the file
func (diffFile *DiffFile) GetTailSection(gitRepo *git.Repository, leftCommitID, rightCommitID string) *DiffSection {
if diffFile.Type != DiffFileChange || diffFile.IsBin || diffFile.IsLFSFile {
return nil
}
leftCommit, err := gitRepo.GetCommit(leftCommitID)
if err != nil {
return nil
}
rightCommit, err := gitRepo.GetCommit(rightCommitID)
if err != nil {
return nil
}
lastSection := diffFile.Sections[len(diffFile.Sections)-1]
lastLine := lastSection.Lines[len(lastSection.Lines)-1]
leftLineCount := getCommitFileLineCount(leftCommit, diffFile.Name)
rightLineCount := getCommitFileLineCount(rightCommit, diffFile.Name)
if leftLineCount <= lastLine.LeftIdx || rightLineCount <= lastLine.RightIdx {
return nil
}
tailDiffLine := &DiffLine{
Type: DiffLineSection,
Content: " ",
SectionInfo: &DiffLineSectionInfo{
Path: diffFile.Name,
LastLeftIdx: lastLine.LeftIdx,
LastRightIdx: lastLine.RightIdx,
LeftIdx: leftLineCount,
RightIdx: rightLineCount,
}}
tailSection := &DiffSection{Lines: []*DiffLine{tailDiffLine}}
return tailSection
}
func getCommitFileLineCount(commit *git.Commit, filePath string) int {
blob, err := commit.GetBlobByPath(filePath)
if err != nil {
return 0
}
lineCount, err := blob.GetBlobLineCount()
if err != nil {
return 0
}
return lineCount
}
// Diff represents a difference between two git trees. // Diff represents a difference between two git trees.
type Diff struct { type Diff struct {
TotalAddition, TotalDeletion int TotalAddition, TotalDeletion int
@@ -510,19 +650,16 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
case line[0] == '@': case line[0] == '@':
curSection = &DiffSection{} curSection = &DiffSection{}
curFile.Sections = append(curFile.Sections, curSection) curFile.Sections = append(curFile.Sections, curSection)
ss := strings.Split(line, "@@") lineSectionInfo := getDiffLineSectionInfo(curFile, line, leftLine-1, rightLine-1)
diffLine := &DiffLine{Type: DiffLineSection, Content: line} diffLine := &DiffLine{
curSection.Lines = append(curSection.Lines, diffLine) Type: DiffLineSection,
Content: line,
// Parse line number. SectionInfo: lineSectionInfo,
ranges := strings.Split(ss[1][1:], " ")
leftLine, _ = com.StrTo(strings.Split(ranges[0], ",")[0][1:]).Int()
if len(ranges) > 1 {
rightLine, _ = com.StrTo(strings.Split(ranges[1], ",")[0]).Int()
} else {
log.Warn("Parse line number failed: %v", line)
rightLine = leftLine
} }
curSection.Lines = append(curSection.Lines, diffLine)
// update line number.
leftLine = lineSectionInfo.LeftIdx
rightLine = lineSectionInfo.RightIdx
continue continue
case line[0] == '+': case line[0] == '+':
curFile.Addition++ curFile.Addition++
@@ -599,6 +736,8 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D
break break
} }
curFileLinesCount = 0 curFileLinesCount = 0
leftLine = 1
rightLine = 1
curFileLFSPrefix = false curFileLFSPrefix = false
// Check file diff type and is submodule. // Check file diff type and is submodule.
@@ -701,6 +840,7 @@ func GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID
diffArgs = append(diffArgs, actualBeforeCommitID) diffArgs = append(diffArgs, actualBeforeCommitID)
diffArgs = append(diffArgs, afterCommitID) diffArgs = append(diffArgs, afterCommitID)
cmd = exec.Command(git.GitExecutable, diffArgs...) cmd = exec.Command(git.GitExecutable, diffArgs...)
beforeCommitID = actualBeforeCommitID
} }
cmd.Dir = repoPath cmd.Dir = repoPath
cmd.Stderr = os.Stderr cmd.Stderr = os.Stderr
@@ -721,6 +861,12 @@ func GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID
if err != nil { if err != nil {
return nil, fmt.Errorf("ParsePatch: %v", err) return nil, fmt.Errorf("ParsePatch: %v", err)
} }
for _, diffFile := range diff.Files {
tailSection := diffFile.GetTailSection(gitRepo, beforeCommitID, afterCommitID)
if tailSection != nil {
diffFile.Sections = append(diffFile.Sections, tailSection)
}
}
if err = cmd.Wait(); err != nil { if err = cmd.Wait(); err != nil {
return nil, fmt.Errorf("Wait: %v", err) return nil, fmt.Errorf("Wait: %v", err)
+50
View File
@@ -0,0 +1,50 @@
{{if $.IsSplitStyle}}
{{range $k, $line := $.section.Lines}}
<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}">
{{if eq .GetType 4}}
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}">
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5) }}
<i class="ui blob-excerpt fa fa-caret-down" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=down" data-anchor="{{$.Anchor}}"></i>
{{end}}
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4) }}
<i class="ui blob-excerpt fa fa-caret-up" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=up" data-anchor="{{$.Anchor}}"></i>
{{end}}
{{if or (eq $line.GetExpandDirection 2)}}
<i class="ui blob-excerpt octicon octicon-fold" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=" data-anchor="{{$.Anchor}}"></i>
{{end}}
</td>
<td colspan="5" class="lines-code lines-code-old "><span class="mono wrap{{if $.highlightClass}} language-{{$.highlightClass}}{{else}} nohighlight{{end}}">{{$.section.GetComputedInlineDiffFor $line}}</span></td>
{{else}}
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{Sha1 $.fileName}}L{{$line.LeftIdx}}{{end}}"></span></td>
<td class="blob-excerpt lines-type-marker lines-type-marker-old">{{if $line.LeftIdx}}<span class="mono" data-type-marker=""></span>{{end}}</td>
<td class="blob-excerpt lines-code lines-code-old halfwidth"><span class="mono wrap{{if $.highlightClass}} language-{{$.highlightClass}}{{else}} nohighlight{{end}}">{{if $line.LeftIdx}}{{$.section.GetComputedInlineDiffFor $line}}{{end}}</span></td>
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $.fileName}}R{{$line.RightIdx}}{{end}}"></span></td>
<td class="blob-excerpt lines-type-marker lines-type-marker-new">{{if $line.RightIdx}}<span class="mono" data-type-marker=""></span>{{end}}</td>
<td class="blob-excerpt lines-code lines-code-new halfwidth"><span class="mono wrap{{if $.highlightClass}} language-{{$.highlightClass}}{{else}} nohighlight{{end}}">{{if $line.RightIdx}}{{$.section.GetComputedInlineDiffFor $line}}{{end}}</span></td>
{{end}}
</tr>
{{end}}
{{else}}
{{range $k, $line := $.section.Lines}}
<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}">
{{if eq .GetType 4}}
<td colspan="2" class="lines-num">
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4) }}
<i class="ui blob-excerpt fa fa-caret-up" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=up" data-anchor="{{$.Anchor}}"></i>
{{end}}
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5) }}
<i class="ui blob-excerpt fa fa-caret-down" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=down" data-anchor="{{$.Anchor}}"></i>
{{end}}
{{if or (eq $line.GetExpandDirection 2)}}
<i class="ui blob-excerpt octicon octicon-fold" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=" data-anchor="{{$.Anchor}}"></i>
{{end}}
</td>
{{else}}
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{Sha1 $.fileName}}L{{$line.LeftIdx}}{{end}}"></span></td>
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $.fileName}}R{{$line.RightIdx}}{{end}}"></span></td>
{{end}}
<td class="blob-excerpt lines-type-marker"><span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span></td>
<td class="blob-excerpt lines-code{{if (not $line.RightIdx)}} lines-code-old{{end}}"><span class="mono wrap{{if $.highlightClass}} language-{{$.highlightClass}}{{else}} nohighlight{{end}}">{{$.section.GetComputedInlineDiffFor $line}}</span></td>
</tr>
{{end}}
{{end}}
+30 -12
View File
@@ -81,6 +81,15 @@
{{else}} {{else}}
<div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}}" id="diff-{{.Index}}"> <div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}}" id="diff-{{.Index}}">
<h4 class="ui top attached normal header"> <h4 class="ui top attached normal header">
{{$isImage := false}}
{{if $file.IsDeleted}}
{{$isImage = (call $.IsImageFileInBase $file.Name)}}
{{else}}
{{$isImage = (call $.IsImageFileInHead $file.Name)}}
{{end}}
{{if or (not $file.IsBin) $isImage}}
<i class="ui fold-code grey fa fa-chevron-down"></i>
{{end}}
<div class="diff-counter count"> <div class="diff-counter count">
{{if $file.IsBin}} {{if $file.IsBin}}
{{$.i18n.Tr "repo.diff.bin"}} {{$.i18n.Tr "repo.diff.bin"}}
@@ -104,12 +113,6 @@
</h4> </h4>
<div class="ui attached unstackable table segment"> <div class="ui attached unstackable table segment">
{{if ne $file.Type 4}} {{if ne $file.Type 4}}
{{$isImage := false}}
{{if $file.IsDeleted}}
{{$isImage = (call $.IsImageFileInBase $file.Name)}}
{{else}}
{{$isImage = (call $.IsImageFileInHead $file.Name)}}
{{end}}
<div class="file-body file-code code-view code-diff {{if $.IsSplitStyle}}code-diff-split{{else}}code-diff-unified{{end}}"> <div class="file-body file-code code-view code-diff {{if $.IsSplitStyle}}code-diff-split{{else}}code-diff-unified{{end}}">
<table> <table>
<tbody> <tbody>
@@ -121,12 +124,27 @@
{{range $j, $section := $file.Sections}} {{range $j, $section := $file.Sections}}
{{range $k, $line := $section.Lines}} {{range $k, $line := $section.Lines}}
<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}"> <tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}">
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{Sha1 $file.Name}}L{{$line.LeftIdx}}{{end}}"></span></td> {{if eq .GetType 4}}
<td class="lines-type-marker lines-type-marker-old">{{if $line.LeftIdx}}<span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span>{{end}}</td> <td class="lines-num lines-num-old">
<td class="lines-code lines-code-old halfwidth">{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 2))}}<a class="ui green button add-code-comment add-code-comment-left" data-path="{{$file.Name}}" data-side="left" data-idx="{{$line.LeftIdx}}">+</a>{{end}}<span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}} nohighlight{{end}}">{{if $line.LeftIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}</span></td> {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5) }}
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}"></span></td> <i class="ui blob-excerpt fa fa-caret-down" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=down" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"></i>
<td class="lines-type-marker lines-type-marker-new">{{if $line.RightIdx}}<span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span>{{end}}</td> {{end}}
<td class="lines-code lines-code-new halfwidth">{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 3))}}<a class="ui green button add-code-comment add-code-comment-right" data-path="{{$file.Name}}" data-side="right" data-idx="{{$line.RightIdx}}">+</a>{{end}}<span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}} nohighlight{{end}}">{{if $line.RightIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}</span></td> {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4) }}
<i class="ui blob-excerpt fa fa-caret-up" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=up" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"></i>
{{end}}
{{if or (eq $line.GetExpandDirection 2)}}
<i class="ui blob-excerpt octicon octicon-fold" data-url="{{$.RepoLink}}/blob_excerpt/{{$.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=split&direction=" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"></i>
{{end}}
</td>
<td colspan="5" class="lines-code lines-code-old "><span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}} nohighlight{{end}}">{{$section.GetComputedInlineDiffFor $line}}</span></td>
{{else}}
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{Sha1 $file.Name}}L{{$line.LeftIdx}}{{end}}"></span></td>
<td class="lines-type-marker lines-type-marker-old">{{if $line.LeftIdx}}<span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span>{{end}}</td>
<td class="lines-code lines-code-old halfwidth">{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 2))}}<a class="ui green button add-code-comment add-code-comment-left" data-path="{{$file.Name}}" data-side="left" data-idx="{{$line.LeftIdx}}">+</a>{{end}}<span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}} nohighlight{{end}}">{{if $line.LeftIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}</span></td>
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}"></span></td>
<td class="lines-type-marker lines-type-marker-new">{{if $line.RightIdx}}<span class="mono" data-type-marker="{{$line.GetLineTypeMarker}}"></span>{{end}}</td>
<td class="lines-code lines-code-new halfwidth">{{if and $.SignedUserID $line.CanComment $.PageIsPullFiles (not (eq .GetType 3))}}<a class="ui green button add-code-comment add-code-comment-right" data-path="{{$file.Name}}" data-side="right" data-idx="{{$line.RightIdx}}">+</a>{{end}}<span class="mono wrap{{if $highlightClass}} language-{{$highlightClass}}{{else}} nohighlight{{end}}">{{if $line.RightIdx}}{{$section.GetComputedInlineDiffFor $line}}{{end}}</span></td>
{{end}}
</tr> </tr>
{{if gt (len $line.Comments) 0}} {{if gt (len $line.Comments) 0}}
<tr class="add-code-comment"> <tr class="add-code-comment">
+11 -3
View File
@@ -4,9 +4,17 @@
{{range $k, $line := $section.Lines}} {{range $k, $line := $section.Lines}}
<tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}"> <tr class="{{DiffLineTypeToStr .GetType}}-code nl-{{$k}} ol-{{$k}}">
{{if eq .GetType 4}} {{if eq .GetType 4}}
<td colspan="2" class="lines-num"> <td colspan="2" class="lines-num">
{{/* {{if gt $j 0}}<span class="fold octicon octicon-fold"></span>{{end}} */}} {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5) }}
</td> <i class="ui blob-excerpt fa fa-caret-down" data-url="{{$.root.RepoLink}}/blob_excerpt/{{$.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=down" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"></i>
{{end}}
{{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 4) }}
<i class="ui blob-excerpt fa fa-caret-up" data-url="{{$.root.RepoLink}}/blob_excerpt/{{$.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=up" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"></i>
{{end}}
{{if or (eq $line.GetExpandDirection 2)}}
<i class="ui blob-excerpt octicon octicon-fold" data-url="{{$.root.RepoLink}}/blob_excerpt/{{$.root.AfterCommitID}}" data-query="{{$line.GetBlobExcerptQuery}}&style=unified&direction=" data-anchor="diff-{{Sha1 $file.Name}}K{{$line.SectionInfo.RightIdx}}"></i>
{{end}}
</td>
{{else}} {{else}}
<td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{Sha1 $file.Name}}L{{$line.LeftIdx}}{{end}}"></span></td> <td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{Sha1 $file.Name}}L{{$line.LeftIdx}}{{end}}"></span></td>
<td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}"></span></td> <td class="lines-num lines-num-new" data-line-num="{{if $line.RightIdx}}{{$line.RightIdx}}{{end}}"><span rel="{{if $line.RightIdx}}diff-{{Sha1 $file.Name}}R{{$line.RightIdx}}{{end}}"></span></td>
+21
View File
@@ -1852,6 +1852,27 @@ function initCodeView() {
} }
}).trigger('hashchange'); }).trigger('hashchange');
} }
$('.ui.fold-code').on('click', (e) => {
const $foldButton = $(e.target);
if ($foldButton.hasClass('fa-chevron-down')) {
$(e.target).parent().next().slideUp('fast', () => {
$foldButton.removeClass('fa-chevron-down').addClass('fa-chevron-right');
});
} else {
$(e.target).parent().next().slideDown('fast', () => {
$foldButton.removeClass('fa-chevron-right').addClass('fa-chevron-down');
});
}
});
function insertBlobExcerpt(e) {
const $blob = $(e.target);
const $row = $blob.parent().parent();
$.get(`${$blob.data('url')}?${$blob.data('query')}&anchor=${$blob.data('anchor')}`, (blob) => {
$row.replaceWith(blob);
$(`[data-anchor="${$blob.data('anchor')}"]`).on('click', (e) => { insertBlobExcerpt(e); });
});
}
$('.ui.blob-excerpt').on('click', (e) => { insertBlobExcerpt(e); });
} }
function initU2FAuth() { function initU2FAuth() {
+4
View File
@@ -2438,6 +2438,10 @@ tbody.commit-list {
padding-bottom: 8px; padding-bottom: 8px;
} }
td.blob-excerpt {
background-color: #fafafa;
}
.issue-keyword { .issue-keyword {
border-bottom: 1px dotted #959da5; border-bottom: 1px dotted #959da5;
display: inline-block; display: inline-block;
+23
View File
@@ -108,3 +108,26 @@
font: 12px @monospaced-fonts, monospace; font: 12px @monospaced-fonts, monospace;
color: rgba(0, 0, 0, 0.87); color: rgba(0, 0, 0, 0.87);
} }
.ui.fold-code {
margin-right: 1em;
padding-left: 5px;
cursor: pointer;
width: 22px;
font-size: 12px;
}
.ui.fold-code:hover {
color: #428bca;
}
.ui.blob-excerpt {
display: block;
line-height: 20px;
font-size: 16px;
cursor: pointer;
}
.ui.blob-excerpt:hover {
color: #428bca;
}