├── .gitattributes ├── .github ├── label-gun.yml └── workflows │ └── release.yml ├── .gitignore ├── README.md ├── bootstrap.ts ├── dprint.json ├── esbuild.js ├── package-lock.json ├── package.json ├── tsconfig.json └── zotero-plugin.ini /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.github/label-gun.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ignore: 3 | - chatter 4 | - deferred 5 | reopen: 6 | - "*" 7 | - "-question" 8 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: release 2 | 3 | on: 4 | push: 5 | 6 | jobs: 7 | release: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - name: install node 12 | uses: actions/setup-node@v1 13 | with: 14 | node-version: 14.x 15 | - name: Cache node dependencies 16 | uses: actions/cache@v2 17 | env: 18 | cache-name: cache-dependencies 19 | with: 20 | path: | 21 | ~/.npm 22 | key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('package-lock.json') }} 23 | restore-keys: | 24 | ${{ runner.os }}-build-${{ env.cache-name }}- 25 | ${{ runner.os }}-build- 26 | ${{ runner.os }}- 27 | - name: install node dependencies 28 | run: npm install 29 | - name: build 30 | run: npm run build 31 | - name: release 32 | run: npm run release 33 | env: 34 | GITHUB_TOKEN: ${{ github.token }} 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .eslintcache 2 | .DS_Store 3 | wiki 4 | gen 5 | build 6 | *~ 7 | *.swp 8 | *.debug 9 | *.cache 10 | *.status 11 | *.js.map 12 | *.tmp 13 | *.xpi 14 | node_modules 15 | .env 16 | pages/*.js 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Report Customizer for Zotero 2 | 3 | Install by downloading the [latest version](https://github.com/retorquere/zotero-report-customizer/releases), and then 4 | 5 | 1. In the main menu go to Tools > Add-ons 6 | 2. Select 'Extensions' 7 | 3. Click on the gear in the top-right corner and choose 'Install Add-on From File...' 8 | 4. Choose .xpi that you've just downloaded, click 'Install' 9 | 5. Restart Zotero 10 | 11 | Does what [Jason Priem's "Report Cleaner"](http://jasonpriem.org/projects/report_cleaner.php), but 12 | without the copy-paste-into-website bit. You can live-edit the report to pick the elements to remove 13 | from the report, and they will simple not show up from that point on. 14 | 15 | ## Integration with [Zotero: Better BibTeX](https://retorquere.github.io/zotero-report-customizer/better-bibtex/) 16 | 17 | This plugin integrates with (but does not require) [Zotero: Better BibTeX](https://retorquere.github.io/zotero-report-customizer/better-bibtex/), to display the bibtex key plus any conflicts between them. 18 | 19 | ## Customizing the fields to display 20 | 21 | In the generated report, click the pencil to remove fields and change the order and sort. The back arrow reset all current edits, the erase-all (three lines) resets all to default. If the save icon appears that means there are unsaved changes. 22 | 23 | ## Showing a bibliography rendering instead of the item title 24 | 25 | You can replace the title with a bibliography line in the report. The customizer offers a [hidden preference](https://www.zotero.org/support/preferences/hidden_preferences) called `extensions.zotero.report-customizer.bibliography`. If you toggle that to `true`, the title in the report will be replaced with a bibliography rendering according to the default quick-copy format (Prefs - Export - Default Format). 26 | 27 | If you want a custom MathJax config, you can add it as a JSON-encoded [configuration block](https://docs.mathjax.org/en/latest/options/input/tex.html?highlight=inlinemath#the-configuration-block) (anything you want, sans the leading `MathJax =` and trailing `;`, in a string preference named `extensions.zotero.report-customizer.MathJax`. 28 | 29 | If you want select-links to go to the Zotero website, create a boolean preference named `extensions.zotero.report-customizer.link.web` and set it to `true`. 30 | 31 | ## Includes indexing status of attachments 32 | 33 | (not ported yet to 5.0) 34 | 35 | Shows indexing status of attachments, plus links to select attachment 36 | 37 | If you experience any problems, or are unclear on how to use it, I'll be glad to [help](https://retorquere.github.io/zotero-report-customizer/support.html). 38 | 39 | ## **NOTE** 40 | 41 | The report customizations must be saved by clicking the Save icon before the report can be saved to disk. I'm looking into this. 42 | -------------------------------------------------------------------------------- /bootstrap.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable prefer-arrow/prefer-arrow-functions, no-var, @typescript-eslint/no-unused-vars, no-caller, @typescript-eslint/explicit-module-boundary-types */ 2 | 3 | declare namespace Zotero { 4 | let ReportCustomizer: ReportCustomizer 5 | } 6 | 7 | import { MenuManager } from 'zotero-plugin-toolkit' 8 | import { DebugLog } from 'zotero-plugin/debug-log' 9 | const Menu = new MenuManager() 10 | 11 | declare const dump: (msg: string) => void 12 | declare const Components: any 13 | declare const ChromeUtils: any 14 | declare var Services: any 15 | 16 | /* 17 | const { 18 | interfaces: Ci, 19 | results: Cr, 20 | utils: Cu, 21 | Constructor: Cc, 22 | } = Components 23 | */ 24 | 25 | class ReportCustomizer { 26 | public alert(text: string, title?: string): void { 27 | Services.prompt.alert(null, title || 'Alert', text) 28 | } 29 | 30 | public launchDesigner(): void { 31 | // @ts-expect-error TS2339 32 | const window = Zotero.getMainWindow() 33 | window.openDialog('chrome://report-customizer/content/designer.xhtml', '_blank', 'chrome,centerscreen,modal', {}) 34 | } 35 | 36 | public log(msg: string): void { 37 | // @ts-expect-error TS2339 38 | Zotero.debug(`report-customizer: ${msg}`) 39 | } 40 | 41 | public dataSource 42 | } 43 | 44 | export function install() { 45 | // nothing to do 46 | } 47 | 48 | let chromeHandle 49 | export async function startup({ id, version, resourceURI, rootURI = resourceURI.spec }) { 50 | const aomStartup = Cc['@mozilla.org/addons/addon-manager-startup;1'].getService(Ci.amIAddonManagerStartup) 51 | const manifestURI = Services.io.newURI(`${rootURI}manifest.json`) 52 | chromeHandle = aomStartup.registerChrome(manifestURI, [ 53 | ['content', 'report-customizer', 'content/'], 54 | ['locale', 'report-customizer', 'en-US', 'locale/en-US/'], 55 | ]) 56 | 57 | Zotero.ReportCustomizer = new ReportCustomizer() 58 | Zotero.ReportCustomizer.log('startup') 59 | 60 | // @ts-expect-error TS2339 61 | const doc = Zotero.getMainWindow().document 62 | if (!doc.querySelector('#better-bibtex-menuHelp')) { 63 | Menu.register('menuTools', { 64 | id: 'report-customizer-menuTools', 65 | tag: 'menuitem', 66 | label: 'Report customizer', 67 | oncommand: 'Zotero.ReportCustomizer.launchDesigner()', 68 | }) 69 | } 70 | 71 | DebugLog.register('Report customizer') 72 | } 73 | 74 | export function shutdown() { 75 | delete Zotero.ReportCustomizer 76 | DebugLog.unregister('Report customizer') 77 | if (typeof chromeHandle !== 'undefined') { 78 | chromeHandle.destruct() 79 | chromeHandle = undefined 80 | } 81 | } 82 | 83 | export function uninstall() { 84 | // nothing to do 85 | } 86 | -------------------------------------------------------------------------------- /dprint.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript": { 3 | "arrowFunction.useParentheses": "preferNone", 4 | "trailingCommas": "onlyMultiLine", 5 | "bracePosition": "sameLine", 6 | "nextControlFlowPosition": "nextLine", 7 | "useBraces": "maintain", 8 | "quoteProps": "asNeeded", 9 | "useTabs": false, 10 | "quoteStyle": "preferSingle", 11 | "semiColons": "asi", 12 | "lineWidth": 1024 13 | }, 14 | "json": { 15 | }, 16 | "markdown": { 17 | }, 18 | "excludes": [ 19 | "**/node_modules", 20 | "**/*-lock.json" 21 | ], 22 | "plugins": [ 23 | "https://plugins.dprint.dev/typescript-0.93.0.wasm", 24 | "https://plugins.dprint.dev/json-0.19.3.wasm", 25 | "https://plugins.dprint.dev/markdown-0.17.8.wasm" 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /esbuild.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const fs = require('fs') 3 | const esbuild = require('esbuild') 4 | const rmrf = require('rimraf') 5 | rmrf.sync('gen') 6 | 7 | require('zotero-plugin/copy-assets') 8 | require('zotero-plugin/rdf') 9 | require('zotero-plugin/version') 10 | 11 | function js(src) { 12 | return src.replace(/[.]ts$/, '.js') 13 | } 14 | 15 | async function bundle(config) { 16 | config = { 17 | bundle: true, 18 | format: 'iife', 19 | target: ['firefox60'], 20 | inject: [], 21 | treeShaking: true, 22 | keepNames: true, 23 | ...config, 24 | } 25 | 26 | let target 27 | if (config.outfile) { 28 | target = config.outfile 29 | } 30 | else if (config.entryPoints.length === 1 && config.outdir) { 31 | target = path.join(config.outdir, js(path.basename(config.entryPoints[0]))) 32 | } 33 | else { 34 | target = `${config.outdir} [${config.entryPoints.map(js).join(', ')}]` 35 | } 36 | 37 | const exportGlobals = config.exportGlobals 38 | delete config.exportGlobals 39 | if (exportGlobals) { 40 | const esm = await esbuild.build({ ...config, logLevel: 'silent', format: 'esm', metafile: true, write: false }) 41 | if (Object.values(esm.metafile.outputs).length !== 1) throw new Error('exportGlobals not supported for multiple outputs') 42 | 43 | for (const output of Object.values(esm.metafile.outputs)) { 44 | if (output.entryPoint) { 45 | config.globalName = escape(`{ ${output.exports.sort().join(', ')} }`).replace(/%/g, '$') 46 | // make these var, not const, so they get hoisted and are available in the global scope. 47 | } 48 | } 49 | } 50 | 51 | console.log('* bundling', target) 52 | await esbuild.build(config) 53 | if (exportGlobals) { 54 | await fs.promises.writeFile( 55 | target, 56 | (await fs.promises.readFile(target, 'utf-8')).replace(config.globalName, unescape(config.globalName.replace(/[$]/g, '%'))) 57 | ) 58 | } 59 | } 60 | 61 | async function build() { 62 | await bundle({ 63 | exportGlobals: true, 64 | entryPoints: [ 'bootstrap.ts' ], 65 | outdir: 'build', 66 | banner: { js: 'var Zotero;\n' }, 67 | }) 68 | } 69 | 70 | build().catch(err => { 71 | console.log(err) 72 | process.exit(1) 73 | }) 74 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "zotero-report-customizer", 3 | "version": "5.0.38", 4 | "description": "Zotero Report Customizer", 5 | "scripts": { 6 | "lint": "dprint fmt *.ts && dprint check *.ts", 7 | "tsc": "tsc -noEmit", 8 | "esbuild": "node esbuild.js", 9 | "prebuild": "rm -rf build && mkdir build && cp -r content build && cp node_modules/ankareport/dist/* build/content", 10 | "build": "npm-run-all -p --aggregate-output lint esbuild tsc", 11 | "postbuild": "zotero-plugin-zipup build zotero-report-customizer", 12 | "release": "zotero-plugin-release", 13 | "postversion": "git push --follow-tags", 14 | "prestart": "npm run build && rm -f ~/.BBTTEST/extensions.json && rm -f ~/.BBTTEST/extensions/*report-customizer*xpi && echo `pwd`/build/ > ~/.BBTTEST/extensions/report-customizer@iris-advies.com", 15 | "start": "zotero-start" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/retorquere/zotero-report-customizer.git" 20 | }, 21 | "author": { 22 | "name": "Emiliano Heyns", 23 | "email": "emiliano.heyns@iris-advies.com" 24 | }, 25 | "bugs": { 26 | "url": "https://github.com/retorquere/zotero-report-customizer/issues" 27 | }, 28 | "homepage": "https://github.com/retorquere/zotero-report-customizer", 29 | "xpi": { 30 | "name": "Zotero Report Customizer", 31 | "updateLink": "https://github.com/retorquere/zotero-report-customizer/releases/download/v{version}/zotero-report-customizer-{version}.xpi", 32 | "releaseURL": "https://github.com/retorquere/zotero-report-customizer/releases/download/release/" 33 | }, 34 | "devDependencies": { 35 | "dprint": "^0.49.1", 36 | "esbuild": "^0.25.2", 37 | "npm-run-all": "^4.1.5", 38 | "rimraf": "^6.0.1", 39 | "typescript": "^5.8.2", 40 | "zotero-plugin": "^5.0.14", 41 | "zotero-types": "^4.0.0-beta.6" 42 | }, 43 | "dependencies": { 44 | "ankareport": "^0.1.0-beta.17", 45 | "zotero-plugin-toolkit": "^5.0.0-1" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowUnreachableCode": false, 4 | "noUnusedLocals": true, 5 | "isolatedModules": true, 6 | "esModuleInterop": true, 7 | "noUnusedParameters": false, 8 | "importHelpers": true, 9 | "target": "es2017", 10 | "disableSizeLimit": true, 11 | "module": "commonjs", 12 | "noImplicitAny": false, 13 | "removeComments": false, 14 | "preserveConstEnums": true, 15 | "sourceMap": false, 16 | "downlevelIteration": true, 17 | "resolveJsonModule": true, 18 | "moduleResolution": "node", 19 | "typeRoots": [ 20 | "./node_modules", 21 | "./node_modules/@types" 22 | ], 23 | "skipDefaultLibCheck": true, 24 | "types": ["zotero-types"], 25 | "lib": [ "es2017", "dom", "dom.iterable", "webworker", "ES2021.WeakRef" ] 26 | }, 27 | "include": [ 28 | "*.ts" 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /zotero-plugin.ini: -------------------------------------------------------------------------------- 1 | [profile] 2 | name = BBTTEST 3 | path = ~/.BBTTEST 4 | 5 | [zotero] 6 | log = ~/.BBTTEST.log 7 | # db = zotero.sqlite 8 | 9 | [preferences] 10 | # extensions.zotero.better-bibtex.scrubDatabase = true 11 | # extensions.zotero.prosec-linker.doi.url.1 = http://doi-orl/DOI 12 | # extensions.zotero.prosec-linker.doi.name.1 = doi-url 13 | # extensions.zotero.prosec-linker.doi.delete.1 = true 14 | # # extensions.zotero.prosec-linker.doi.url.2 15 | # # extensions.zotero.prosec-linker.doi.name.2 16 | # # extensions.zotero.prosec-linker.doi.delete.2 17 | # 18 | # extensions.zotero.prosec-linker.title = true 19 | # extensions.zotero.prosec-linker.title.url.1 http://title-url/TITLE 20 | # extensions.zotero.prosec-linker.title.name.1 = title-url 21 | # extensions.zotero.prosec-linker.title.delete.1 = false 22 | # # extensions.zotero.prosec-linker.title.url.2 23 | # # extensions.zotero.prosec-linker.title.name.2 24 | # # extensions.zotero.prosec-linker.title.delete.2 25 | # 26 | # extensions.zotero.prosec-linker.pdf = false 27 | # # extensions.zotero.prosec-linker.pdf.url.1 28 | # # extensions.zotero.prosec-linker.pdf.name.1 29 | # # extensions.zotero.prosec-linker.pdf.delete.1 30 | --------------------------------------------------------------------------------