17 |
18 | # Supporting
19 |
20 |
21 |
22 | # Contrasting
23 |
24 |
25 |
26 | # Mentioning
27 |
28 |
29 |
30 | # Citing Publications
31 |
32 |
33 |
34 | View Scite Report
35 |
36 |
37 | `,
38 | onRender: ({ body, item }) => {
39 | const tallies = fetchTalliesZotero7(item)
40 | if (!tallies) {
41 | body.textContent = "No tallies loaded"
42 | } else {
43 | const doi = getDOI(item.getField('DOI'), item.getField('extra'));
44 |
45 | const fields = ['supporting', 'contrasting', 'mentioning', 'citingPublications'];
46 | fields.forEach(field => {
47 | const spanElement = body.querySelector(`#scite-plugin-item-pane-${field}-key`);
48 | if (spanElement) {
49 | spanElement.textContent = tallies[field]?.toLocaleString() || '-';
50 | spanElement.dataset.itemid = item ? `${item.id}-${field}-${tallies[field]}` : '';
51 | }
52 | });
53 |
54 | // Handle the report link
55 | const linkContainer = body.querySelector('#scite-plugin-item-pane-report-link-container');
56 | const linkElement = body.querySelector('#scite-plugin-item-pane-report-link');
57 | if (doi && linkContainer && linkElement) {
58 | linkContainer.style.display = 'block';
59 | linkElement.onclick = (event) => {
60 | event.preventDefault();
61 | const url = `https://scite.ai/reports/${encodeURIComponent(doi)}?utm_source=zotero&utm_medium=scite-zotero-plugin&utm_campaign=scite`;
62 | Zotero.launchURL(url);
63 | };
64 | } else if (linkContainer) {
65 | linkContainer.style.display = 'none';
66 | }
67 | }
68 | }
69 | }
--------------------------------------------------------------------------------
/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 | declare const ChromeUtils: any
3 | declare const Cc: any
4 | declare const Ci: any
5 |
6 | if (typeof Zotero == 'undefined') {
7 | var Zotero
8 | }
9 |
10 | function log(msg) {
11 | msg = `[Scite Zotero] bootstrap: ${msg}`
12 | Zotero.logError(msg)
13 | }
14 |
15 | export function onMainWindowLoad({ window }) {
16 | log('onMainWindowLoad')
17 | window.MozXULElement.insertFTLIfNeeded('scite-zotero-plugin.ftl')
18 | }
19 |
20 | async function waitForZotero() {
21 | if (typeof Zotero != 'undefined') {
22 | await Zotero.initializationPromise
23 | return
24 | }
25 |
26 | // eslint-disable-next-line @typescript-eslint/no-shadow
27 | var { Services } = ChromeUtils.import('resource://gre/modules/Services.jsm')
28 | var windows = Services.wm.getEnumerator('navigator:browser')
29 | var found = false
30 | while (windows.hasMoreElements()) {
31 | const win = windows.getNext()
32 | if (win.Zotero) {
33 | Zotero = win.Zotero
34 | found = true
35 | break
36 | }
37 | }
38 | if (!found) {
39 | await new Promise(resolve => {
40 | var listener = {
41 | onOpenWindow(aWindow) {
42 | // Wait for the window to finish loading
43 | const domWindow = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
44 | .getInterface(Ci.nsIDOMWindowInternal || Ci.nsIDOMWindow)
45 | domWindow.addEventListener('load', function() {
46 | domWindow.removeEventListener('load', arguments.callee, false)
47 | if (domWindow.Zotero) {
48 | Services.wm.removeListener(listener)
49 | Zotero = domWindow.Zotero
50 | resolve(undefined)
51 | }
52 | }, false)
53 | },
54 | }
55 | Services.wm.addListener(listener)
56 | })
57 | }
58 | await Zotero.initializationPromise
59 | }
60 |
61 | async function install() {
62 | await waitForZotero()
63 | log('Installed Scite Plugin')
64 | }
65 |
66 | let chromeHandle
67 | async function startup({ id, version, resourceURI, rootURI = resourceURI?.spec }) {
68 | try {
69 | await waitForZotero()
70 | if (typeof Services == 'undefined') {
71 | var { Services } = ChromeUtils.import('resource://gre/modules/Services.jsm')
72 | }
73 |
74 | var aomStartup = Cc['@mozilla.org/addons/addon-manager-startup;1'].getService(Ci.amIAddonManagerStartup)
75 | var manifestURI = Services.io.newURI(rootURI + 'client/manifest.json')
76 |
77 | // Register chrome resources
78 | chromeHandle = aomStartup.registerChrome(manifestURI, [
79 | [ 'content', 'scite-zotero-plugin', rootURI + 'content/' ],
80 | [ 'locale', 'scite-zotero-plugin', 'en-US', rootURI + 'locale/en-US/' ],
81 | ])
82 |
83 | Services.scriptloader.loadSubScript(`${rootURI}lib.js`)
84 | Zotero.Scite.start(rootURI).catch(err => Zotero.logError(err))
85 | log('Started Zotero Scite')
86 | const $window = Zotero.getMainWindow()
87 | onMainWindowLoad({ window: $window })
88 | }
89 | catch (err) {
90 | Zotero.logError('[Scite Zotero] Error during startup')
91 | Zotero.logError(err)
92 | }
93 | }
94 |
95 | function shutdown() {
96 | log('Shutting down')
97 |
98 | // Remove stylesheet
99 | var zp = Zotero.getActiveZoteroPane()
100 |
101 | Zotero.Scite.unload().catch(err => Zotero.logError(err))
102 |
103 | // Deregister chrome
104 | if (chromeHandle) {
105 | chromeHandle.destruct()
106 | chromeHandle = null
107 | }
108 |
109 | Zotero.Scite = undefined
110 | }
111 |
112 | function uninstall() {
113 | log('Uninstalled')
114 | }
115 |
116 | export { install, startup, shutdown, uninstall }
117 |
--------------------------------------------------------------------------------
/lib.ts:
--------------------------------------------------------------------------------
1 | import { IZotero } from './typings/global'
2 |
3 | Components.utils.import('resource://gre/modules/AddonManager.jsm')
4 |
5 | declare const Zotero: IZotero
6 | declare const Components: any
7 |
8 | import { debug } from './client/content/debug'
9 | import { htmlencode, plaintext, getField, getDOI, isShortDoi, isZotero7 } from './client/content/util'
10 | import { PLUGIN_ENABLED } from './client/content/config'
11 | import { sciteColumnsZotero7 } from './client/content/columns'
12 | import { sciteItemPaneZotero7 } from './client/content/itemPane'
13 |
14 | interface Tallies {
15 | doi: string
16 | contrasting: number // NOTE: The API returns contradicting, we map this manually
17 | mentioning: number
18 | supporting: number
19 | total: number
20 | unclassified: number
21 | citingPublications: number
22 | }
23 |
24 | const shortToLongDOIMap = {}
25 | const longToShortDOIMap = {}
26 | const MAX_DOI_BATCH_SIZE = 500 // tslint:disable-line:no-magic-numbers
27 |
28 | async function getLongDoi(shortDoi) {
29 | try {
30 | if (!shortDoi) {
31 | return ''
32 | }
33 | // If it starts with 10/, it is short
34 | // otherwise, treat it as long and just return
35 | shortDoi = shortDoi.toLowerCase().trim()
36 | if (!isShortDoi(shortDoi)) {
37 | // This is probably a long DOI then!
38 | return shortDoi
39 | }
40 | if (shortDoi in shortToLongDOIMap) {
41 | debug(`shortToLongDOIMap cache hit ${shortDoi}`)
42 | return shortToLongDOIMap[shortDoi]
43 | }
44 |
45 | const res = await Zotero.HTTP.request('GET', `https://doi.org/api/handles/${shortDoi}`)
46 | const doiRes = res?.response ? JSON.parse(res.response).values : []
47 | const longDoi = (doiRes && doiRes.length && doiRes.length > 1) ? doiRes[1].data.value.toLowerCase().trim() : ''
48 | if (!longDoi) {
49 | debug(`Unable to resolve shortDoi ${shortDoi} to longDoi`)
50 | // I guess just return the shortDoi for now...?
51 | return shortDoi
52 | }
53 |
54 | // Use these to minimize API calls and easily go back and forth
55 | shortToLongDOIMap[shortDoi] = longDoi
56 | longToShortDOIMap[longDoi] = shortDoi
57 |
58 | debug(`Converted shortDoi (${shortDoi}) to longDoi (${longDoi})`)
59 | return longDoi
60 | }
61 | catch (err) {
62 | Zotero.logError(`ERR_getLongDoi(${shortDoi}): ${err}`)
63 | return shortDoi
64 | }
65 | }
66 |
67 | const ready = Zotero.Promise.defer()
68 |
69 | export class CScite {
70 | public ready: any = ready.promise
71 | public tallies: { [DOI: string]: Tallies } = {}
72 | public uninstalled: boolean = false
73 |
74 | private bundle: any
75 | private started = false
76 |
77 | constructor() {
78 | this.bundle = Components.classes['@mozilla.org/intl/stringbundle;1'].getService(Components.interfaces.nsIStringBundleService).createBundle('chrome://zotero-scite/locale/zotero-scite.properties')
79 | }
80 |
81 | public async start(rootURI: string = '') {
82 | if (!PLUGIN_ENABLED) {
83 | Zotero.logError('Scite Zotero plugin is disabled. Aborting!')
84 | return
85 | }
86 |
87 | if (!isZotero7) {
88 | Zotero.logError('This version of the scite plugin only supports Zotero 7 and after, please upgrade or use an older XPI')
89 | return
90 | }
91 |
92 | if (this.started) return
93 | this.started = true
94 |
95 | const columns = sciteColumnsZotero7.map(column => {
96 | const iconPath = column.iconPath ? rootURI + column.iconPath : null
97 | return {
98 | ...column,
99 | iconPath,
100 | htmlLabel: iconPath
101 | ? `