Skip to content

Commit 9f8e778

Browse files
authored
Copy citation file content, in APA and BibTex format, on repo home page (#19999)
Add feature to easily copy CITATION.cff content in APA and BibTex format.
1 parent 9db2217 commit 9f8e778

File tree

10 files changed

+474
-21
lines changed

10 files changed

+474
-21
lines changed

Diff for: options/locale/locale_en-US.ini

+2
Original file line numberDiff line numberDiff line change
@@ -1013,10 +1013,12 @@ unstar = Unstar
10131013
star = Star
10141014
fork = Fork
10151015
download_archive = Download Repository
1016+
more_actions = More Actions
10161017

10171018
no_desc = No Description
10181019
quick_guide = Quick Guide
10191020
clone_this_repo = Clone this repository
1021+
cite_this_repo = Cite this repository
10201022
create_new_repo_command = Creating a new repository on the command line
10211023
push_exist_repo = Pushing an existing repository from the command line
10221024
empty_message = This repository does not contain any content.

Diff for: package-lock.json

+271-18
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: package.json

+4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
"node": ">= 14.0.0"
88
},
99
"dependencies": {
10+
"@citation-js/core": "0.6.1",
11+
"@citation-js/plugin-bibtex": "0.6.1",
12+
"@citation-js/plugin-csl": "0.6.3",
13+
"@citation-js/plugin-software-formats": "0.6.0",
1014
"@claviska/jquery-minicolors": "2.3.6",
1115
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
1216
"@primer/octicons": "17.7.0",

Diff for: routers/web/repo/view.go

+45
Original file line numberDiff line numberDiff line change
@@ -730,6 +730,44 @@ func checkHomeCodeViewable(ctx *context.Context) {
730730
ctx.NotFound("Home", fmt.Errorf(ctx.Tr("units.error.no_unit_allowed_repo")))
731731
}
732732

733+
func checkCitationFile(ctx *context.Context, entry *git.TreeEntry) {
734+
if entry.Name() != "" {
735+
return
736+
}
737+
tree, err := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath)
738+
if err != nil {
739+
ctx.NotFoundOrServerError("Repo.Commit.SubTree", git.IsErrNotExist, err)
740+
return
741+
}
742+
allEntries, err := tree.ListEntries()
743+
if err != nil {
744+
ctx.ServerError("ListEntries", err)
745+
return
746+
}
747+
for _, entry := range allEntries {
748+
if entry.Name() == "CITATION.cff" || entry.Name() == "CITATION.bib" {
749+
ctx.Data["CitiationExist"] = true
750+
// Read Citation file contents
751+
blob := entry.Blob()
752+
dataRc, err := blob.DataAsync()
753+
if err != nil {
754+
ctx.ServerError("DataAsync", err)
755+
return
756+
}
757+
defer dataRc.Close()
758+
buf := make([]byte, 1024)
759+
n, err := util.ReadAtMost(dataRc, buf)
760+
if err != nil {
761+
ctx.ServerError("ReadAtMost", err)
762+
return
763+
}
764+
buf = buf[:n]
765+
ctx.PageData["citationFileContent"] = string(buf)
766+
break
767+
}
768+
}
769+
}
770+
733771
// Home render repository home page
734772
func Home(ctx *context.Context) {
735773
isFeed, _, showFeedType := feed.GetFeedType(ctx.Params(":reponame"), ctx.Req)
@@ -954,6 +992,13 @@ func renderCode(ctx *context.Context) {
954992
return
955993
}
956994

995+
if !ctx.Repo.Repository.IsEmpty {
996+
checkCitationFile(ctx, entry)
997+
if ctx.Written() {
998+
return
999+
}
1000+
}
1001+
9571002
renderLanguageStats(ctx)
9581003
if ctx.Written() {
9591004
return

Diff for: templates/repo/cite/cite_buttons.tmpl

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<button class="ui basic citation button" id="citation-copy-apa" data-text="">
2+
APA
3+
</button>
4+
<button class="ui basic citation button" id="citation-copy-bibtex" data-text="">
5+
BibTeX
6+
</button>
7+
<!-- the value will be updated by initCitationFileCopyContent, the code below is used to avoid UI flicking -->
8+
<input id="citation-copy-content" value="" size="1" readonly>
9+
<button class="ui basic icon button tooltip" id="citation-clipboard-btn" data-content="{{.locale.Tr "copy"}}" data-clipboard-text="" data-clipboard-target="#citation-copy-content">
10+
{{svg "octicon-copy"}}
11+
</button>

Diff for: templates/repo/cite/cite_modal.tmpl

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<div class="ui tiny modal" id="cite-repo-modal">
2+
<div class="header">
3+
{{.locale.Tr "repo.cite_this_repo"}}
4+
</div>
5+
<div class="content">
6+
<div class="ui stackable secondary menu mobile--margin-between-items mobile--no-negative-margins no-vertical-tabs">
7+
<div class="fitted item">
8+
<div class="ui action input" id="citation-panel">
9+
{{template "repo/cite/cite_buttons" .}}
10+
<a id="goto-citation-btn" class="ui basic jump icon button tooltip" href="{{$.RepoLink}}/src/{{$.BranchName}}/CITATION.cff" data-position="top right" data-content="{{.locale.Tr "repo.find_file.go_to_file"}}">
11+
{{svg "octicon-file-moved"}}
12+
</a>
13+
</div>
14+
</div>
15+
</div>
16+
</div>
17+
<div class="actions">
18+
<div class="ui black deny button">
19+
{{.locale.Tr "cancel"}}
20+
</div>
21+
</div>
22+
</div>

Diff for: templates/repo/home.tmpl

+6-2
Original file line numberDiff line numberDiff line change
@@ -117,19 +117,23 @@
117117
{{if eq $n 0}}
118118
<div class="ui action tiny input" id="clone-panel">
119119
{{template "repo/clone_buttons" .}}
120-
<button id="download-btn" class="ui basic small compact jump dropdown icon button tooltip" data-content="{{.locale.Tr "repo.download_archive"}}" data-position="top right">
121-
{{svg "octicon-download"}}
120+
<button id="more-btn" class="ui basic small compact jump dropdown icon button tooltip" data-content="{{.locale.Tr "repo.more_actions"}}" data-position="top right">
121+
{{svg "octicon-kebab-horizontal"}}
122122
<div class="menu">
123123
{{if not $.DisableDownloadSourceArchives}}
124124
<a class="item archive-link" href="{{$.RepoLink}}/archive/{{PathEscapeSegments $.RefName}}.zip" rel="nofollow">{{svg "octicon-file-zip" 16 "mr-3"}}{{.locale.Tr "repo.download_zip"}}</a>
125125
<a class="item archive-link" href="{{$.RepoLink}}/archive/{{PathEscapeSegments $.RefName}}.tar.gz" rel="nofollow">{{svg "octicon-file-zip" 16 "mr-3"}}{{.locale.Tr "repo.download_tar"}}</a>
126126
<a class="item archive-link" href="{{$.RepoLink}}/archive/{{PathEscapeSegments $.RefName}}.bundle" rel="nofollow">{{svg "octicon-package" 16 "mr-3"}}{{.locale.Tr "repo.download_bundle"}}</a>
127+
{{if .CitiationExist}}
128+
<a class="item" id="cite-repo-button">{{svg "octicon-cross-reference" 16 "mr-3"}}{{.locale.Tr "repo.cite_this_repo"}}</a>
129+
{{end}}
127130
{{end}}
128131
<a class="item js-clone-url-vsc" href="vscode://vscode.git/clone?url={{.CloneButtonOriginLink.HTTPS}}">{{svg "gitea-vscode" 16 "mr-3"}}{{.locale.Tr "repo.clone_in_vsc"}}</a>
129132
</div>
130133
</button>
131134
{{template "repo/clone_script" .}}{{/* the script will update `.js-clone-url` and related elements */}}
132135
</div>
136+
{{template "repo/cite/cite_modal" .}}
133137
{{end}}
134138
{{if and (ne $n 0) (not .IsViewFile) (not .IsBlame)}}
135139
<a class="ui button" href="{{.RepoLink}}/commits/{{.BranchNameSubURL}}/{{.TreePath | PathEscapeSegments}}">

Diff for: web_src/js/features/citation.js

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import $ from 'jquery';
2+
3+
const {pageData} = window.config;
4+
5+
const initInputCitationValue = async ($citationCopyBibtex, $citationCopyApa) => {
6+
const [{Cite, plugins}] = await Promise.all([
7+
import(/* webpackChunkName: "citation-js-core" */'@citation-js/core'),
8+
import(/* webpackChunkName: "citation-js-formats" */'@citation-js/plugin-software-formats'),
9+
import(/* webpackChunkName: "citation-js-bibtex" */'@citation-js/plugin-bibtex'),
10+
import(/* webpackChunkName: "citation-js-bibtex" */'@citation-js/plugin-csl'),
11+
]);
12+
const {citationFileContent} = pageData;
13+
const config = plugins.config.get('@bibtex');
14+
config.constants.fieldTypes.doi = ['field', 'literal'];
15+
config.constants.fieldTypes.version = ['field', 'literal'];
16+
const citationFormatter = new Cite(citationFileContent);
17+
const lang = document.documentElement.lang || 'en-US';
18+
const apaOutput = citationFormatter.format('bibliography', {template: 'apa', lang});
19+
const bibtexOutput = citationFormatter.format('bibtex', {lang});
20+
$citationCopyBibtex.attr('data-text', bibtexOutput);
21+
$citationCopyApa.attr('data-text', apaOutput);
22+
};
23+
24+
export function initCitationFileCopyContent() {
25+
const defaultCitationFormat = 'apa'; // apa or bibtex
26+
27+
if (!pageData.citationFileContent) return;
28+
29+
const $citationCopyApa = $('#citation-copy-apa');
30+
const $citationCopyBibtex = $('#citation-copy-bibtex');
31+
const $inputContent = $('#citation-copy-content');
32+
33+
if ((!$citationCopyApa.length && !$citationCopyBibtex.length) || !$inputContent.length) return;
34+
const updateUi = () => {
35+
const isBibtex = (localStorage.getItem('citation-copy-format') || defaultCitationFormat) === 'bibtex';
36+
const copyContent = (isBibtex ? $citationCopyBibtex : $citationCopyApa).attr('data-text');
37+
38+
$inputContent.val(copyContent);
39+
$citationCopyBibtex.toggleClass('primary', isBibtex);
40+
$citationCopyApa.toggleClass('primary', !isBibtex);
41+
};
42+
initInputCitationValue($citationCopyApa, $citationCopyBibtex).then(updateUi);
43+
44+
$citationCopyApa.on('click', () => {
45+
localStorage.setItem('citation-copy-format', 'apa');
46+
updateUi();
47+
});
48+
$citationCopyBibtex.on('click', () => {
49+
localStorage.setItem('citation-copy-format', 'bibtex');
50+
updateUi();
51+
});
52+
53+
$inputContent.on('click', () => {
54+
$inputContent.select();
55+
});
56+
57+
$('#cite-repo-button').on('click', () => {
58+
$('#cite-repo-modal').modal('show');
59+
});
60+
}

Diff for: web_src/js/features/repo-legacy.js

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
initRepoCommonFilterSearchDropdown,
2222
initRepoCommonLanguageStats,
2323
} from './repo-common.js';
24+
import {initCitationFileCopyContent} from './citation.js';
2425
import {initCompLabelEdit} from './comp/LabelEdit.js';
2526
import {initRepoDiffConversationNav} from './repo-diff.js';
2627
import attachTribute from './tribute.js';
@@ -505,6 +506,7 @@ export function initRepository() {
505506
}
506507

507508
initRepoCloneLink();
509+
initCitationFileCopyContent();
508510
initRepoCommonLanguageStats();
509511
initRepoSettingBranches();
510512

Diff for: web_src/less/_repository.less

+51-1
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@
227227
border-right: none;
228228
}
229229

230-
#download-btn {
230+
#more-btn {
231231
border-left: none;
232232
}
233233

@@ -2468,6 +2468,56 @@
24682468

24692469
// End of .repository
24702470

2471+
#cite-repo-modal {
2472+
#citation-panel {
2473+
width: 500px;
2474+
2475+
@media @mediaSm {
2476+
width: 100%;
2477+
}
2478+
2479+
input {
2480+
border-radius: 0;
2481+
padding: 5px 10px;
2482+
width: 50%;
2483+
line-height: 1.4;
2484+
}
2485+
2486+
.citation.button {
2487+
font-size: 13px;
2488+
padding: 7.5px 5px;
2489+
}
2490+
2491+
#citation-copy-content {
2492+
border-radius: 0;
2493+
padding: 5px 10px;
2494+
font-size: 1.2em;
2495+
line-height: 1.4;
2496+
}
2497+
2498+
#citation-copy-apa,
2499+
#citation-copy-bibtex {
2500+
border-right: none;
2501+
}
2502+
2503+
#goto-citation-btn {
2504+
border-left: none;
2505+
}
2506+
2507+
>:first-child {
2508+
border-radius: var(--border-radius) 0 0 var(--border-radius) !important;
2509+
}
2510+
2511+
>:last-child {
2512+
border-radius: 0 var(--border-radius) var(--border-radius) 0 !important;
2513+
}
2514+
2515+
.icon.button {
2516+
padding: 0 10px;
2517+
}
2518+
}
2519+
}
2520+
24712521
&.user-cards {
24722522
.list {
24732523
padding: 0;

0 commit comments

Comments
 (0)