From 9f8e7789187013ab6752c2635b24c9dd1d70cd90 Mon Sep 17 00:00:00 2001 From: Nolann <62215577+Nolann71@users.noreply.github.com> Date: Fri, 11 Nov 2022 18:02:50 +0100 Subject: [PATCH] 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. --- options/locale/locale_en-US.ini | 2 + package-lock.json | 289 ++++++++++++++++++++++++-- package.json | 4 + routers/web/repo/view.go | 45 ++++ templates/repo/cite/cite_buttons.tmpl | 11 + templates/repo/cite/cite_modal.tmpl | 22 ++ templates/repo/home.tmpl | 8 +- web_src/js/features/citation.js | 60 ++++++ web_src/js/features/repo-legacy.js | 2 + web_src/less/_repository.less | 52 ++++- 10 files changed, 474 insertions(+), 21 deletions(-) create mode 100644 templates/repo/cite/cite_buttons.tmpl create mode 100644 templates/repo/cite/cite_modal.tmpl create mode 100644 web_src/js/features/citation.js diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 1d7086ed1d..eb2a1c86db 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1013,10 +1013,12 @@ unstar = Unstar star = Star fork = Fork download_archive = Download Repository +more_actions = More Actions no_desc = No Description quick_guide = Quick Guide clone_this_repo = Clone this repository +cite_this_repo = Cite this repository create_new_repo_command = Creating a new repository on the command line push_exist_repo = Pushing an existing repository from the command line empty_message = This repository does not contain any content. diff --git a/package-lock.json b/package-lock.json index cd11a43e4f..bf8d4b05e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,10 @@ "name": "gitea", "license": "MIT", "dependencies": { + "@citation-js/core": "0.6.1", + "@citation-js/plugin-bibtex": "0.6.1", + "@citation-js/plugin-csl": "0.6.3", + "@citation-js/plugin-software-formats": "0.6.0", "@claviska/jquery-minicolors": "2.3.6", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", "@primer/octicons": "17.7.0", @@ -197,6 +201,80 @@ "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.1.tgz", "integrity": "sha512-zr9Qs9KFQiEvMWdZesjcmRJlUck5NR+eKGS1uyKk+oYTWwlYrsoPEi6VmG6/TzBD1hKCGEimrhTgGS6hvn/xIQ==" }, + "node_modules/@citation-js/core": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@citation-js/core/-/core-0.6.1.tgz", + "integrity": "sha512-zvVxsAP4ciVHiZ60TmKTfjui4m6xeISSp/rtIhOcvZxZ70bBfkt83+kGnuI4xRlhB/oUrZN2fC9BSRKdivSobQ==", + "dependencies": { + "@citation-js/date": "^0.5.0", + "@citation-js/name": "^0.4.2", + "fetch-ponyfill": "^7.1.0", + "sync-fetch": "^0.4.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@citation-js/date": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@citation-js/date/-/date-0.5.1.tgz", + "integrity": "sha512-1iDKAZ4ie48PVhovsOXQ+C6o55dWJloXqtznnnKy6CltJBQLIuLLuUqa8zlIvma0ZigjVjgDUhnVaNU1MErtZw==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@citation-js/name": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@citation-js/name/-/name-0.4.2.tgz", + "integrity": "sha512-brSPsjs2fOVzSnARLKu0qncn6suWjHVQtrqSUrnqyaRH95r/Ad4wPF5EsoWr+Dx8HzkCGb/ogmoAzfCsqlTwTQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@citation-js/plugin-bibtex": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-bibtex/-/plugin-bibtex-0.6.1.tgz", + "integrity": "sha512-JMw9h9MUXH7YWvgN0j+A5xI4Fw3cHYcDMzpweeAcXBfjfnC6q30Dyvs2YxfUxNEKvWDgRQjAiNNIzgWXs9uK1Q==", + "dependencies": { + "@citation-js/date": "^0.5.0", + "@citation-js/name": "^0.4.2", + "moo": "^0.5.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@citation-js/core": "^0.6.0" + } + }, + "node_modules/@citation-js/plugin-csl": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-csl/-/plugin-csl-0.6.3.tgz", + "integrity": "sha512-SP1/QyHfhcNufQ6VTJUM04Ti0XEWSWYMUhkDGG2lQtnDJU7pSDeAwtsE1kYUIJ9Np0Gm8IEZAfJ3CslMfsbimg==", + "dependencies": { + "@citation-js/date": "^0.5.0", + "citeproc": "^2.4.6" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "@citation-js/core": "^0.6.0" + } + }, + "node_modules/@citation-js/plugin-software-formats": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-software-formats/-/plugin-software-formats-0.6.0.tgz", + "integrity": "sha512-l0Vp2h9UNlqsGMgrJulA92csgu8l3WhhBC0F2nFl76aTMOrMzC9/DX1G2Ob5tUQvPfuy4B5ZZsYPJNTJdtPVhw==", + "dependencies": { + "@citation-js/date": "^0.5.0", + "@citation-js/name": "^0.4.2", + "js-yaml": "^4.0.0" + }, + "peerDependencies": { + "@citation-js/core": "^0.6.0" + } + }, "node_modules/@claviska/jquery-minicolors": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/@claviska/jquery-minicolors/-/jquery-minicolors-2.3.6.tgz", @@ -1783,8 +1861,7 @@ "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/array-find-index": { "version": "1.0.2", @@ -1908,6 +1985,25 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", @@ -1975,6 +2071,29 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -2126,6 +2245,11 @@ "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==", "dev": true }, + "node_modules/citeproc": { + "version": "2.4.62", + "resolved": "https://registry.npmjs.org/citeproc/-/citeproc-2.4.62.tgz", + "integrity": "sha512-l3uFfSEwNZp/jlz/TpgyBs85kOww6VlQHbAth0cpbgOn6iulZd+QlFY43LrRelzcYt3FZHTZ3soDyd8lNmkqdw==" + }, "node_modules/clean-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", @@ -4616,6 +4740,14 @@ "reusify": "^1.0.4" } }, + "node_modules/fetch-ponyfill": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/fetch-ponyfill/-/fetch-ponyfill-7.1.0.tgz", + "integrity": "sha512-FhbbL55dj/qdVO3YNK7ZEkshvj3eQ7EuIGV2I6ic/2YiocvyWv+7jg2s4AyS0wdRU75s3tA8ZxI/xPigb0v5Aw==", + "dependencies": { + "node-fetch": "~2.6.1" + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -5221,6 +5353,25 @@ "postcss": "^8.1.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -5724,7 +5875,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -6575,6 +6725,11 @@ "webpack": "^4.5.0 || 5.x" } }, + "node_modules/moo": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz", + "integrity": "sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==" + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -6671,7 +6826,6 @@ "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dev": true, "dependencies": { "whatwg-url": "^5.0.0" }, @@ -6690,20 +6844,17 @@ "node_modules/node-fetch/node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "node_modules/node-fetch/node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "node_modules/node-fetch/node_modules/whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, "dependencies": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -8498,6 +8649,18 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, + "node_modules/sync-fetch": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/sync-fetch/-/sync-fetch-0.4.2.tgz", + "integrity": "sha512-vilDD6yTGwyUjm7/W5WUUOCw1GH1aV591zC21XhbV6MJNZqfZcNMs9DVPHzy1UAmQ2GAg6S03F5TQ3paegKSdg==", + "dependencies": { + "buffer": "^5.7.1", + "node-fetch": "^2.6.1" + }, + "engines": { + "node": ">=14" + } + }, "node_modules/table": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", @@ -9845,6 +10008,56 @@ "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.1.tgz", "integrity": "sha512-zr9Qs9KFQiEvMWdZesjcmRJlUck5NR+eKGS1uyKk+oYTWwlYrsoPEi6VmG6/TzBD1hKCGEimrhTgGS6hvn/xIQ==" }, + "@citation-js/core": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@citation-js/core/-/core-0.6.1.tgz", + "integrity": "sha512-zvVxsAP4ciVHiZ60TmKTfjui4m6xeISSp/rtIhOcvZxZ70bBfkt83+kGnuI4xRlhB/oUrZN2fC9BSRKdivSobQ==", + "requires": { + "@citation-js/date": "^0.5.0", + "@citation-js/name": "^0.4.2", + "fetch-ponyfill": "^7.1.0", + "sync-fetch": "^0.4.1" + } + }, + "@citation-js/date": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/@citation-js/date/-/date-0.5.1.tgz", + "integrity": "sha512-1iDKAZ4ie48PVhovsOXQ+C6o55dWJloXqtznnnKy6CltJBQLIuLLuUqa8zlIvma0ZigjVjgDUhnVaNU1MErtZw==" + }, + "@citation-js/name": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@citation-js/name/-/name-0.4.2.tgz", + "integrity": "sha512-brSPsjs2fOVzSnARLKu0qncn6suWjHVQtrqSUrnqyaRH95r/Ad4wPF5EsoWr+Dx8HzkCGb/ogmoAzfCsqlTwTQ==" + }, + "@citation-js/plugin-bibtex": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-bibtex/-/plugin-bibtex-0.6.1.tgz", + "integrity": "sha512-JMw9h9MUXH7YWvgN0j+A5xI4Fw3cHYcDMzpweeAcXBfjfnC6q30Dyvs2YxfUxNEKvWDgRQjAiNNIzgWXs9uK1Q==", + "requires": { + "@citation-js/date": "^0.5.0", + "@citation-js/name": "^0.4.2", + "moo": "^0.5.1" + } + }, + "@citation-js/plugin-csl": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-csl/-/plugin-csl-0.6.3.tgz", + "integrity": "sha512-SP1/QyHfhcNufQ6VTJUM04Ti0XEWSWYMUhkDGG2lQtnDJU7pSDeAwtsE1kYUIJ9Np0Gm8IEZAfJ3CslMfsbimg==", + "requires": { + "@citation-js/date": "^0.5.0", + "citeproc": "^2.4.6" + } + }, + "@citation-js/plugin-software-formats": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@citation-js/plugin-software-formats/-/plugin-software-formats-0.6.0.tgz", + "integrity": "sha512-l0Vp2h9UNlqsGMgrJulA92csgu8l3WhhBC0F2nFl76aTMOrMzC9/DX1G2Ob5tUQvPfuy4B5ZZsYPJNTJdtPVhw==", + "requires": { + "@citation-js/date": "^0.5.0", + "@citation-js/name": "^0.4.2", + "js-yaml": "^4.0.0" + } + }, "@claviska/jquery-minicolors": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/@claviska/jquery-minicolors/-/jquery-minicolors-2.3.6.tgz", @@ -11114,8 +11327,7 @@ "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "array-find-index": { "version": "1.0.2", @@ -11206,6 +11418,11 @@ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, "big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", @@ -11251,6 +11468,15 @@ "update-browserslist-db": "^1.0.9" } }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, "buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -11353,6 +11579,11 @@ "integrity": "sha512-yH4RezKOGlOhxkmhbeNuC4eYZKAUsEaGtBuBzDDP1eFUKiccDWzBABxBfOx31IDwDIXMTxWuwAxUGModvkbuVw==", "dev": true }, + "citeproc": { + "version": "2.4.62", + "resolved": "https://registry.npmjs.org/citeproc/-/citeproc-2.4.62.tgz", + "integrity": "sha512-l3uFfSEwNZp/jlz/TpgyBs85kOww6VlQHbAth0cpbgOn6iulZd+QlFY43LrRelzcYt3FZHTZ3soDyd8lNmkqdw==" + }, "clean-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/clean-regexp/-/clean-regexp-1.0.0.tgz", @@ -13191,6 +13422,14 @@ "reusify": "^1.0.4" } }, + "fetch-ponyfill": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/fetch-ponyfill/-/fetch-ponyfill-7.1.0.tgz", + "integrity": "sha512-FhbbL55dj/qdVO3YNK7ZEkshvj3eQ7EuIGV2I6ic/2YiocvyWv+7jg2s4AyS0wdRU75s3tA8ZxI/xPigb0v5Aw==", + "requires": { + "node-fetch": "~2.6.1" + } + }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -13640,6 +13879,11 @@ "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", "requires": {} }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, "ignore": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", @@ -13991,7 +14235,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "requires": { "argparse": "^2.0.1" } @@ -14642,6 +14885,11 @@ "loader-utils": "^2.0.2" } }, + "moo": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz", + "integrity": "sha512-I1mnb5xn4fO80BH9BLcF0yLypy2UKl+Cb01Fu0hJRkJjlCRtxZMWkTdAtDd5ZqCOxtCkhmRwyI57vWT+1iZ67w==" + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -14719,7 +14967,6 @@ "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", - "dev": true, "requires": { "whatwg-url": "^5.0.0" }, @@ -14727,20 +14974,17 @@ "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" }, "whatwg-url": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, "requires": { "tr46": "~0.0.3", "webidl-conversions": "^3.0.0" @@ -16067,6 +16311,15 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, + "sync-fetch": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/sync-fetch/-/sync-fetch-0.4.2.tgz", + "integrity": "sha512-vilDD6yTGwyUjm7/W5WUUOCw1GH1aV591zC21XhbV6MJNZqfZcNMs9DVPHzy1UAmQ2GAg6S03F5TQ3paegKSdg==", + "requires": { + "buffer": "^5.7.1", + "node-fetch": "^2.6.1" + } + }, "table": { "version": "6.8.0", "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", diff --git a/package.json b/package.json index 035f3fd0b0..d221a1379a 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,10 @@ "node": ">= 14.0.0" }, "dependencies": { + "@citation-js/core": "0.6.1", + "@citation-js/plugin-bibtex": "0.6.1", + "@citation-js/plugin-csl": "0.6.3", + "@citation-js/plugin-software-formats": "0.6.0", "@claviska/jquery-minicolors": "2.3.6", "@mcaptcha/vanilla-glue": "0.1.0-alpha-3", "@primer/octicons": "17.7.0", diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go index d35ec48df0..e7aca04819 100644 --- a/routers/web/repo/view.go +++ b/routers/web/repo/view.go @@ -730,6 +730,44 @@ func checkHomeCodeViewable(ctx *context.Context) { ctx.NotFound("Home", fmt.Errorf(ctx.Tr("units.error.no_unit_allowed_repo"))) } +func checkCitationFile(ctx *context.Context, entry *git.TreeEntry) { + if entry.Name() != "" { + return + } + tree, err := ctx.Repo.Commit.SubTree(ctx.Repo.TreePath) + if err != nil { + ctx.NotFoundOrServerError("Repo.Commit.SubTree", git.IsErrNotExist, err) + return + } + allEntries, err := tree.ListEntries() + if err != nil { + ctx.ServerError("ListEntries", err) + return + } + for _, entry := range allEntries { + if entry.Name() == "CITATION.cff" || entry.Name() == "CITATION.bib" { + ctx.Data["CitiationExist"] = true + // Read Citation file contents + blob := entry.Blob() + dataRc, err := blob.DataAsync() + if err != nil { + ctx.ServerError("DataAsync", err) + return + } + defer dataRc.Close() + buf := make([]byte, 1024) + n, err := util.ReadAtMost(dataRc, buf) + if err != nil { + ctx.ServerError("ReadAtMost", err) + return + } + buf = buf[:n] + ctx.PageData["citationFileContent"] = string(buf) + break + } + } +} + // Home render repository home page func Home(ctx *context.Context) { isFeed, _, showFeedType := feed.GetFeedType(ctx.Params(":reponame"), ctx.Req) @@ -954,6 +992,13 @@ func renderCode(ctx *context.Context) { return } + if !ctx.Repo.Repository.IsEmpty { + checkCitationFile(ctx, entry) + if ctx.Written() { + return + } + } + renderLanguageStats(ctx) if ctx.Written() { return diff --git a/templates/repo/cite/cite_buttons.tmpl b/templates/repo/cite/cite_buttons.tmpl new file mode 100644 index 0000000000..0f4fb43484 --- /dev/null +++ b/templates/repo/cite/cite_buttons.tmpl @@ -0,0 +1,11 @@ + + + + + diff --git a/templates/repo/cite/cite_modal.tmpl b/templates/repo/cite/cite_modal.tmpl new file mode 100644 index 0000000000..185b34173d --- /dev/null +++ b/templates/repo/cite/cite_modal.tmpl @@ -0,0 +1,22 @@ + diff --git a/templates/repo/home.tmpl b/templates/repo/home.tmpl index 69eaf17429..6b4a0008d6 100644 --- a/templates/repo/home.tmpl +++ b/templates/repo/home.tmpl @@ -117,19 +117,23 @@ {{if eq $n 0}}
{{template "repo/clone_buttons" .}} - {{template "repo/clone_script" .}}{{/* the script will update `.js-clone-url` and related elements */}}
+ {{template "repo/cite/cite_modal" .}} {{end}} {{if and (ne $n 0) (not .IsViewFile) (not .IsBlame)}} diff --git a/web_src/js/features/citation.js b/web_src/js/features/citation.js new file mode 100644 index 0000000000..01fcd95a1c --- /dev/null +++ b/web_src/js/features/citation.js @@ -0,0 +1,60 @@ +import $ from 'jquery'; + +const {pageData} = window.config; + +const initInputCitationValue = async ($citationCopyBibtex, $citationCopyApa) => { + const [{Cite, plugins}] = await Promise.all([ + import(/* webpackChunkName: "citation-js-core" */'@citation-js/core'), + import(/* webpackChunkName: "citation-js-formats" */'@citation-js/plugin-software-formats'), + import(/* webpackChunkName: "citation-js-bibtex" */'@citation-js/plugin-bibtex'), + import(/* webpackChunkName: "citation-js-bibtex" */'@citation-js/plugin-csl'), + ]); + const {citationFileContent} = pageData; + const config = plugins.config.get('@bibtex'); + config.constants.fieldTypes.doi = ['field', 'literal']; + config.constants.fieldTypes.version = ['field', 'literal']; + const citationFormatter = new Cite(citationFileContent); + const lang = document.documentElement.lang || 'en-US'; + const apaOutput = citationFormatter.format('bibliography', {template: 'apa', lang}); + const bibtexOutput = citationFormatter.format('bibtex', {lang}); + $citationCopyBibtex.attr('data-text', bibtexOutput); + $citationCopyApa.attr('data-text', apaOutput); +}; + +export function initCitationFileCopyContent() { + const defaultCitationFormat = 'apa'; // apa or bibtex + + if (!pageData.citationFileContent) return; + + const $citationCopyApa = $('#citation-copy-apa'); + const $citationCopyBibtex = $('#citation-copy-bibtex'); + const $inputContent = $('#citation-copy-content'); + + if ((!$citationCopyApa.length && !$citationCopyBibtex.length) || !$inputContent.length) return; + const updateUi = () => { + const isBibtex = (localStorage.getItem('citation-copy-format') || defaultCitationFormat) === 'bibtex'; + const copyContent = (isBibtex ? $citationCopyBibtex : $citationCopyApa).attr('data-text'); + + $inputContent.val(copyContent); + $citationCopyBibtex.toggleClass('primary', isBibtex); + $citationCopyApa.toggleClass('primary', !isBibtex); + }; + initInputCitationValue($citationCopyApa, $citationCopyBibtex).then(updateUi); + + $citationCopyApa.on('click', () => { + localStorage.setItem('citation-copy-format', 'apa'); + updateUi(); + }); + $citationCopyBibtex.on('click', () => { + localStorage.setItem('citation-copy-format', 'bibtex'); + updateUi(); + }); + + $inputContent.on('click', () => { + $inputContent.select(); + }); + + $('#cite-repo-button').on('click', () => { + $('#cite-repo-modal').modal('show'); + }); +} diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index 2c93ca0342..e6a7c6dcd1 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -21,6 +21,7 @@ import { initRepoCommonFilterSearchDropdown, initRepoCommonLanguageStats, } from './repo-common.js'; +import {initCitationFileCopyContent} from './citation.js'; import {initCompLabelEdit} from './comp/LabelEdit.js'; import {initRepoDiffConversationNav} from './repo-diff.js'; import attachTribute from './tribute.js'; @@ -505,6 +506,7 @@ export function initRepository() { } initRepoCloneLink(); + initCitationFileCopyContent(); initRepoCommonLanguageStats(); initRepoSettingBranches(); diff --git a/web_src/less/_repository.less b/web_src/less/_repository.less index 193a73c706..bf1fb53e2b 100644 --- a/web_src/less/_repository.less +++ b/web_src/less/_repository.less @@ -227,7 +227,7 @@ border-right: none; } - #download-btn { + #more-btn { border-left: none; } @@ -2468,6 +2468,56 @@ // End of .repository +#cite-repo-modal { + #citation-panel { + width: 500px; + + @media @mediaSm { + width: 100%; + } + + input { + border-radius: 0; + padding: 5px 10px; + width: 50%; + line-height: 1.4; + } + + .citation.button { + font-size: 13px; + padding: 7.5px 5px; + } + + #citation-copy-content { + border-radius: 0; + padding: 5px 10px; + font-size: 1.2em; + line-height: 1.4; + } + + #citation-copy-apa, + #citation-copy-bibtex { + border-right: none; + } + + #goto-citation-btn { + border-left: none; + } + + >:first-child { + border-radius: var(--border-radius) 0 0 var(--border-radius) !important; + } + + >:last-child { + border-radius: 0 var(--border-radius) var(--border-radius) 0 !important; + } + + .icon.button { + padding: 0 10px; + } + } +} + &.user-cards { .list { padding: 0;