* 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 styletags/v1.11.0-rc1
| @@ -6,6 +6,7 @@ | |||
| package git | |||
| import ( | |||
| "bytes" | |||
| "encoding/base64" | |||
| "io" | |||
| "io/ioutil" | |||
| @@ -50,6 +51,28 @@ func (b *Blob) GetBlobContent() (string, error) { | |||
| 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 | |||
| func (b *Blob) GetBlobContentBase64() (string, error) { | |||
| dataRc, err := b.DataAsync() | |||
| @@ -55,6 +55,15 @@ func TestGetDiffPreview(t *testing.T) { | |||
| Type: 4, | |||
| Content: "@@ -1,3 +1,4 @@", | |||
| Comments: nil, | |||
| SectionInfo: &gitdiff.DiffLineSectionInfo{ | |||
| Path: "README.md", | |||
| LastLeftIdx: 0, | |||
| LastRightIdx: 0, | |||
| LeftIdx: 1, | |||
| RightIdx: 1, | |||
| LeftHunkSize: 3, | |||
| RightHunkSize: 4, | |||
| }, | |||
| }, | |||
| { | |||
| LeftIdx: 1, | |||
| @@ -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 .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} | |||
| td.blob-excerpt{background-color:#fafafa} | |||
| .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-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 button.comment-form-reply{margin:.5em .5em .5em 4.5em} | |||
| .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} | |||
| @@ -245,6 +245,7 @@ func Diff(ctx *context.Context) { | |||
| } | |||
| ctx.Data["CommitID"] = commitID | |||
| ctx.Data["AfterCommitID"] = commitID | |||
| ctx.Data["Username"] = userName | |||
| ctx.Data["Reponame"] = repoName | |||
| @@ -5,21 +5,26 @@ | |||
| package repo | |||
| import ( | |||
| "bufio" | |||
| "fmt" | |||
| "html" | |||
| "path" | |||
| "path/filepath" | |||
| "strings" | |||
| "code.gitea.io/gitea/models" | |||
| "code.gitea.io/gitea/modules/base" | |||
| "code.gitea.io/gitea/modules/context" | |||
| "code.gitea.io/gitea/modules/git" | |||
| "code.gitea.io/gitea/modules/highlight" | |||
| "code.gitea.io/gitea/modules/log" | |||
| "code.gitea.io/gitea/modules/setting" | |||
| "code.gitea.io/gitea/services/gitdiff" | |||
| ) | |||
| 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 | |||
| @@ -434,3 +439,109 @@ func CompareDiff(ctx *context.Context) { | |||
| 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 | |||
| } | |||
| @@ -552,6 +552,7 @@ func ViewPullFiles(ctx *context.Context) { | |||
| ctx.Data["Username"] = pull.MustHeadUserName() | |||
| ctx.Data["Reponame"] = pull.HeadRepo.Name | |||
| } | |||
| ctx.Data["AfterCommitID"] = endCommitID | |||
| diff, err := gitdiff.GetDiffRangeWithWhitespaceBehavior(diffRepoPath, | |||
| startCommitID, endCommitID, setting.Git.MaxGitDiffLines, | |||
| @@ -864,6 +864,10 @@ func RegisterRoutes(m *macaron.Macaron) { | |||
| m.Get("", repo.Branches) | |||
| }, 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.Get(".diff", repo.DownloadPullDiff) | |||
| m.Get(".patch", repo.DownloadPullPatch) | |||
| @@ -13,6 +13,7 @@ import ( | |||
| "html/template" | |||
| "io" | |||
| "io/ioutil" | |||
| "net/url" | |||
| "os" | |||
| "os/exec" | |||
| "regexp" | |||
| @@ -56,15 +57,42 @@ const ( | |||
| 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. | |||
| type DiffLine struct { | |||
| LeftIdx int | |||
| RightIdx int | |||
| Type DiffLineType | |||
| Content string | |||
| Comments []*models.Comment | |||
| LeftIdx int | |||
| RightIdx int | |||
| Type DiffLineType | |||
| Content string | |||
| 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. | |||
| func (d *DiffLine) GetType() int { | |||
| return int(d.Type) | |||
| @@ -91,6 +119,71 @@ func (d *DiffLine) GetLineTypeMarker() string { | |||
| 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 | |||
| func getLineContent(content string) string { | |||
| if len(content) > 0 { | |||
| @@ -248,6 +341,53 @@ func (diffFile *DiffFile) GetHighlightClass() string { | |||
| 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. | |||
| type Diff struct { | |||
| TotalAddition, TotalDeletion int | |||
| @@ -510,19 +650,16 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D | |||
| case line[0] == '@': | |||
| curSection = &DiffSection{} | |||
| curFile.Sections = append(curFile.Sections, curSection) | |||
| ss := strings.Split(line, "@@") | |||
| diffLine := &DiffLine{Type: DiffLineSection, Content: line} | |||
| curSection.Lines = append(curSection.Lines, diffLine) | |||
| // Parse line number. | |||
| 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 | |||
| lineSectionInfo := getDiffLineSectionInfo(curFile, line, leftLine-1, rightLine-1) | |||
| diffLine := &DiffLine{ | |||
| Type: DiffLineSection, | |||
| Content: line, | |||
| SectionInfo: lineSectionInfo, | |||
| } | |||
| curSection.Lines = append(curSection.Lines, diffLine) | |||
| // update line number. | |||
| leftLine = lineSectionInfo.LeftIdx | |||
| rightLine = lineSectionInfo.RightIdx | |||
| continue | |||
| case line[0] == '+': | |||
| curFile.Addition++ | |||
| @@ -599,6 +736,8 @@ func ParsePatch(maxLines, maxLineCharacters, maxFiles int, reader io.Reader) (*D | |||
| break | |||
| } | |||
| curFileLinesCount = 0 | |||
| leftLine = 1 | |||
| rightLine = 1 | |||
| curFileLFSPrefix = false | |||
| // Check file diff type and is submodule. | |||
| @@ -701,6 +840,7 @@ func GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID | |||
| diffArgs = append(diffArgs, actualBeforeCommitID) | |||
| diffArgs = append(diffArgs, afterCommitID) | |||
| cmd = exec.Command(git.GitExecutable, diffArgs...) | |||
| beforeCommitID = actualBeforeCommitID | |||
| } | |||
| cmd.Dir = repoPath | |||
| cmd.Stderr = os.Stderr | |||
| @@ -721,6 +861,12 @@ func GetDiffRangeWithWhitespaceBehavior(repoPath, beforeCommitID, afterCommitID | |||
| if err != nil { | |||
| 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 { | |||
| return nil, fmt.Errorf("Wait: %v", err) | |||
| @@ -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}} | |||
| @@ -81,6 +81,15 @@ | |||
| {{else}} | |||
| <div class="diff-file-box diff-box file-content {{TabSizeClass $.Editorconfig $file.Name}}" id="diff-{{.Index}}"> | |||
| <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"> | |||
| {{if $file.IsBin}} | |||
| {{$.i18n.Tr "repo.diff.bin"}} | |||
| @@ -104,12 +113,6 @@ | |||
| </h4> | |||
| <div class="ui attached unstackable table segment"> | |||
| {{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}}"> | |||
| <table> | |||
| <tbody> | |||
| @@ -121,12 +124,27 @@ | |||
| {{range $j, $section := $file.Sections}} | |||
| {{range $k, $line := $section.Lines}} | |||
| <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> | |||
| <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> | |||
| {{if eq .GetType 4}} | |||
| <td class="lines-num lines-num-old"> | |||
| {{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="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="{{$.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> | |||
| {{if gt (len $line.Comments) 0}} | |||
| <tr class="add-code-comment"> | |||
| @@ -4,9 +4,17 @@ | |||
| {{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 gt $j 0}}<span class="fold octicon octicon-fold"></span>{{end}} */}} | |||
| </td> | |||
| <td colspan="2" class="lines-num"> | |||
| {{if or (eq $line.GetExpandDirection 3) (eq $line.GetExpandDirection 5) }} | |||
| <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}} | |||
| <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> | |||
| @@ -1852,6 +1852,27 @@ function initCodeView() { | |||
| } | |||
| }).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() { | |||
| @@ -2438,6 +2438,10 @@ tbody.commit-list { | |||
| padding-bottom: 8px; | |||
| } | |||
| td.blob-excerpt { | |||
| background-color: #fafafa; | |||
| } | |||
| .issue-keyword { | |||
| border-bottom: 1px dotted #959da5; | |||
| display: inline-block; | |||
| @@ -108,3 +108,26 @@ | |||
| font: 12px @monospaced-fonts, monospace; | |||
| 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; | |||
| } | |||