Compare commits

...

390 Commits

Author SHA1 Message Date
xenia b1c986427b remove this horrid crap 2025-12-07 19:04:06 -05:00
abaevbog 2e13e9407d
ACM Queue Translator (#3529) 2025-12-04 15:06:55 -05:00
Hassan Afjnik ffa1be434c Add translator for Ined (#2826) 2025-12-04 13:36:02 -05:00
abaevbog 2f7fc8eb9b
Le Monde: fix authors and sections not being fetched (#3522) 2025-12-04 13:25:18 -05:00
Abe Jellinek 7f632f76bc ScienceDirect: Work around port in canonical link
https://forums.zotero.org/discussion/128356/sciencedirect-fails-to-import-pdf
2025-12-02 13:01:59 -05:00
Abe Jellinek ee1746de4d arXiv: Don't pull PDF URL from <link>
The PDF link no longer has title="pdf".

https://forums.zotero.org/discussion/128019/zotero-cannot-fetch-pdfs-from-arxiv-anymore
2025-11-12 10:43:13 -05:00
Abe Jellinek 36745ead6d PMC: Fix mismatched metadata when saving multiples
The API can return metadata out of order.

https://forums.zotero.org/discussion/127910/pubmed-central-issue-wrong-url-pmcid-information-wrong-catalog-page-and-article
2025-11-06 15:34:41 -05:00
Abe Jellinek 4fe143f5d0 The Met: Update for site changes, use API
https://forums.zotero.org/discussion/127908/unable-to-save-with-items-in-firefox-or-safari
2025-11-06 11:00:35 -05:00
Abe Jellinek 6365ccdf13 CI: Fix translator tests
By switching from Selenium to Playwright. It's honestly unbelievable
that Selenium's JS library still doesn't support loading unpacked
extensions on recent Chrome versions. Playwright handles it easily, and
it has a nicer API overall.
2025-10-31 15:08:37 -04:00
Abe Jellinek b44a279901 CI: Log title and URL when test page fails to load 2025-10-31 13:40:29 -04:00
Abe Jellinek 7e1b981f92 CI: Wait longer for test page to load 2025-10-31 12:52:10 -04:00
Abe Jellinek a79e3bea38 EUR-Lex: Update for site changes
Language is no longer in the URL.

Fixes #3447
2025-10-30 11:52:09 -04:00
swifterslb 93af89a882
Add translator for FAOLEX Database (#3498)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2025-10-30 11:40:41 -04:00
Dandelion Good 20b8729b80
Add translator for Anarchist Library (#3499) 2025-10-28 16:06:45 -04:00
Abe Jellinek 303ca7d64d OSF Preprints: Rewrite after site changes
We're only targeting osf.io now. Most other sites have been merged (and
redirected) into osf.io, and the few that haven't appear to be using
other software.

Fixes #3512
2025-10-28 10:53:31 -04:00
Abe Jellinek 59967fbfab
Add translator for Google Gemini (#3509) 2025-10-27 11:56:35 -04:00
Abe Jellinek d7d7426860 ChatGPT: Grab share URL when available
When saving a private conversation, enumerate shares and see if we have
one that matches and is up to date.
2025-10-27 11:39:28 -04:00
Abe Jellinek 7d12fd8f2d
Add translator for ChatGPT (#3507) 2025-10-27 11:14:21 -04:00
vanderwaalforces b56c554203
Prime 9ja Online: Exclude non-human authors, add Pidgin support (#3502)
And other miscellaneous tweaks.

Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2025-10-24 15:39:48 -04:00
Abe Jellinek bb41570843 Add AGENTS.md 2025-10-24 12:36:16 -04:00
Abe Jellinek 259ea55d73 HAL: Rename, update for current site
https://forums.zotero.org/discussion/127602/hal-translator-not-recognized
2025-10-23 13:04:13 -04:00
Jason Murphy ea900c2124
Papers Past: Enhanced metadata extraction for newspapers (#3497)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2025-10-21 12:36:32 -04:00
Alex T. 2eef9d03f9
ePrint: fix saving PostScript attachments (#3506) 2025-10-20 12:13:32 -04:00
swifterslb a095751f8a
FAO Publications → Knowledge Repository, rewrite for new site (#3504) 2025-10-16 12:06:41 -04:00
Ivo Pletikosić 352989d042
Add translator for Hrvatska enciklopedija (#3500) 2025-10-16 11:55:09 -04:00
Abe Jellinek 4ae717da83 EBSCO Locate: Get API base URL from JS
Instead of assuming based on the domain - that rule apparently doesn't
hold for all instances.

Fixes #3501
2025-10-16 11:04:31 -04:00
Corinna Baksik d0f2d15874
adding plural versions of some resource types for Primo XML (#3494) 2025-10-14 14:54:08 -04:00
Abe Jellinek df835b0e1d EM: Update tests for site changes 2025-10-14 13:30:03 -04:00
Abe Jellinek 8a9ef4a1de EM: Only extract a single canonical URL
Even when there are multiple <link rel="canonical">s. ZU.xpathText()
joins all matches, attr() uses the first match.
2025-10-14 13:28:44 -04:00
Pascal Quach 2da50c6a39
Embedded Metadata: deduplicate bylines when getting authors (#3493)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2025-10-14 13:24:33 -04:00
Abe Jellinek e9335d57c9 Toronto Star: Update for site changes
https://forums.zotero.org/discussion/127185/error-report-1509932172-toronto-star-translator-is-broken
2025-10-07 11:39:13 -04:00
Abe Jellinek 0855c33a6c WSJ: Update for site changes
https://forums.zotero.org/discussion/126893/wall-street-journal-not-recognized-as-a-newspaper
2025-10-07 09:31:49 -04:00
Abe Jellinek 085b8db857 InvenioRDM: Save DOIs on preprint items
And update tests.

DOIs disappeared from tests because the test runner doesn't currently
move unsupported fields to `extra`.

https://forums.zotero.org/discussion/126862/no-doi-or-pdf-saved-for-zenodo-preprint
2025-09-18 11:11:08 -04:00
Abe Jellinek 41f8149d88 PubMed Central: Update for site changes
- New domain
- New search page structure
- New, consistent URL for PDFs, so no need to trawl the XML for
  a filename
- Update attachment titles
- Update tests

Fixes #3491
2025-09-17 12:31:25 -04:00
Abe Jellinek f6d9cb90e5 ThesesFR: Get direct PDF link from page
https://forums.zotero.org/discussion/comment/499131/#Comment_499131
2025-09-11 11:44:29 -04:00
Abe Jellinek e343623dfe ThesesFR: Update for site changes, fix scraping URL with hash
https://forums.zotero.org/discussion/106637/broken-thesesfr-translator
2025-09-11 10:42:05 -04:00
Abe Jellinek c44f7f6489 Add translator for Ovid OCE
Fixes #3381
2025-09-03 12:42:55 -04:00
Abe Jellinek 52a114f843 LWN: Fix date selector
https://forums.zotero.org/discussion/126379/connector-not-importing-lwn-net-articles
2025-08-28 10:37:35 -04:00
Pascal Martinolli 727fd1cc63
Wikidata QuickStatements: Support more item types and permanent identifiers (#3468)
Co-authored-by: Alex T. <frozen.and.blue@gmail.com>
2025-08-28 10:28:08 -04:00
Sebastian Karcher f9ff5e2818
Add translator for EBSCO Locate catalogs (#3485)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2025-08-28 10:20:16 -04:00
Abe Jellinek d9f3bb8f77 PhilPapers: Exports are now auth-walled
So use the embedded BibTeX when it's there, and otherwise don't detect.

https://forums.zotero.org/discussion/126194/zotero-connector-for-philpapers-org-safari-on-mac
2025-08-19 11:22:24 -04:00
Abe Jellinek c30b7d743b WoS: Fix detection 2025-08-18 13:13:15 -04:00
Abe Jellinek ea61c7bc35 WoS: Update for site changes and improve cleaning
- Don't detect if unauthenticated
- Fix search QID extraction when URL contains two IDs
  (not sure what the second one is for)
- Don't detect multiples on single-item pages
- Get full metadata for patents
- Fix all-uppercase publication titles
- Don't try to resolve gateway for DOIs
- Update tests

https://forums.zotero.org/discussion/126134/errors-with-zotero-connector-and-web-of-science-next-gen
2025-08-18 13:10:56 -04:00
Abe Jellinek 83d1bae957 CI: Gripe about AI when translator is badly formatted
Instead of failing with a confusing error message ("TypeError: Cannot
read properties of null (reading '0')").
2025-08-15 15:49:52 -04:00
Abe Jellinek ff648a300c CI: Use a faster method to find dependent translators 2025-08-15 14:19:34 -04:00
Abe Jellinek 17b68b5ea4 CI: Use ES modules 2025-08-15 14:13:20 -04:00
vanderwaalforces 045d65428b
Add translator for Premium Times (#3460) 2025-08-14 12:54:46 -04:00
vanderwaalforces 063470ef1e
Add Prime 9ja Online (#3459) 2025-08-08 11:35:37 -06:00
Abe Jellinek ba32042c02 DOAJ: Get full abstract
https://forums.zotero.org/discussion/126000/zotero-connector-does-not-collect-full-abstract-from-doaj
2025-08-08 10:01:33 -06:00
Alex T. 04550f03ff
Fix Dagstuhl PDF saving (#3476) 2025-08-08 08:59:28 -06:00
Abe Jellinek fa5940aad8
RDF: Move issue to number (don't copy) if issue isn't valid (#3483) 2025-08-07 08:47:04 -06:00
Jennifer Chen a0de6dc471
Update NASA ADS translator to support new app scixplorer.org (#3479) 2025-08-06 07:19:14 -04:00
Abe Jellinek 746e8a71f0 MIT Press Books: Update for site changes
https://forums.zotero.org/discussion/125768/mit-press-books-translator-not-working
2025-08-05 16:50:45 -04:00
Dan Stillman fcab5e6679 Crossref REST: Fall back to article number if no page number
https://forums.zotero.org/discussion/comment/496681/#Comment_496681

Similar behavior in Crossref Unixref XML:

017fdf0f44/Crossref%20Unixref%20XML.js (L411-L420)
2025-08-03 01:39:59 -04:00
Abe Jellinek 70ee40d3e1 ProQuest: Fix saving from PDF tab
Element ID changed.

https://forums.zotero.org/discussion/125821/embedded-pdfs-do-not-download-with-find-full-text-feature
2025-07-31 13:15:27 -04:00
Andrew Dunning 4d2bfbd39d
IMDb: Improve CSL specification adherence (#3461)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2025-07-29 13:26:31 -04:00
timlst a12fe985be
Add USENIX translator (#3477) 2025-07-29 12:56:09 -04:00
Abe Jellinek e0398e97d2 Silverchair: Don't put full name in journal abbrev. field
And update tests, except for a couple that I keep getting rate-limited
on.

https://github.com/zotero/translators/issues/3394#issuecomment-2498657612

Closes #3394
2025-07-29 12:31:39 -04:00
Abe Jellinek 32b768595e
Scopus: Update for site changes (#3478) 2025-07-29 12:12:14 -04:00
Dan Stillman a1d40d2aa6 DOI Content Negotiation: Stop using REST API due to slow response times 2025-07-27 00:52:13 -04:00
Abe Jellinek c089bf10db CI: Fix failures due to Chrome removing --load-extension
We're apparently supposed to be using a new extension installation
function exposed by the "WebDriver BiDi" protocol, but Selenium's JS
binding doesn't support that yet.

So instead, we use a feature flag to un-remove --load-extension. That
workaround will eventually break, but hopefully by that point Selenium
will support BiDi extension installation.

BiDi installation issue: https://github.com/SeleniumHQ/selenium/issues/15585
Chrome announcement: https://groups.google.com/a/chromium.org/g/chromium-extensions/c/1-g8EFx2BBY/m/S0ET5wPjCAAJ
2025-07-25 12:15:58 -04:00
Abe Jellinek 38662755f4 mEDRA: Disable until fixed
zotero/zotero#5384, #3472
2025-07-14 13:56:11 -04:00
Abe Jellinek 8f3c5f73d0 eLife: Fix saving versioned article URLs
https://forums.zotero.org/discussion/comment/495162/#Comment_495162
2025-07-10 14:26:28 -04:00
Abe Jellinek 47bbe8f716 Open WorldCat: Use search.worldcat.org, remove Google Cache
May mitigate some issues like
https://forums.zotero.org/discussion/comment/495096/#Comment_495096.
That particular problem will probably still occur until the Wayback
Machine re-crawls WorldCat.
2025-07-09 15:24:10 -04:00
Abe Jellinek 3491570a60 beck-online: Add fallback URL
I'm not seeing a permalink anywhere anymore, but it's possible that it
doesn't show unless you're logged in? Either way, a fallback can't hurt.

https://forums.zotero.org/discussion/125262/problem-with-saving-snapshots-from-beck-online
zotero/zotero-connectors#554
2025-07-09 09:51:31 -04:00
Dan Stillman da3d32b5e3 DOI Content Negotiation: Always use REST API for Crossref DOIs for now 2025-07-07 01:56:48 -04:00
Abe Jellinek 6776c18568 Flickr: Fix saving JPEGs
Connector wants a valid MIME type.

https://forums.zotero.org/discussion/125083/inconsistant-photo-downloads-from-flickr-translator
2025-06-27 10:29:44 -04:00
Abe Jellinek 50113e5cf3 HeinOnline: Fix metadata issues after site changes
PDF downloads still seem to be broken.
2025-06-20 13:11:43 -04:00
Abe Jellinek 3e194622e7 Silverchair: Handle OUP book ToCs
- Add '[Full Book]' option (still need to localize these)
- Fix multiples titles including access info

https://forums.zotero.org/discussion/124835/problem-with-oup-academic-books
2025-06-13 10:38:46 -04:00
Abe Jellinek 3db53195f7 Nature Publishing Group: Update online-only publication logic
- Check for article number even if hardcoded list doesn't match
- Add more publications to list

https://forums.zotero.org/discussion/124450/wrong-pages-field-for-online-journals-with-nature-publishing-group-translator
https://forums.zotero.org/discussion/99725/zotero-connector-wrong-pages-for-communications-physics-journal

Fixes #3457
2025-06-12 12:23:18 -04:00
Abe Jellinek 29bf90b2e6 YouTube: Get description from #snippet
Fixes #3458
2025-06-12 12:10:37 -04:00
Abe Jellinek 45e839c3ef Wiley: Work around subdomain cookie issues
https://forums.zotero.org/discussion/124692/issue-with-saving-items-from-wires-climate-change
2025-06-11 11:32:31 -04:00
Abe Jellinek 0673614c60 EM: Get author from <a rel="author">
https://forums.zotero.org/discussion/124767/zotero-and-statista
2025-06-10 10:42:21 -04:00
Abe Jellinek 6a0659b90e CI: Fix get_translators_to_check() for push runs 2025-06-03 16:39:13 -04:00
Abe Jellinek 7224c4668d CI: Restore correct extension ID
https://github.com/zotero/translators/pull/3450#discussion_r2100442585
2025-06-03 16:11:42 -04:00
Abe Jellinek 9e4cae74d9 CI: Fix mistaken removal of JSON parsing dependency
Should fix linting.
2025-06-03 16:11:31 -04:00
Skye Im 66ab19e9e6
Library Catalog (TIND ILS): Improve detection (#3454) 2025-06-03 14:52:05 -04:00
Dan Stillman 1757ec73e0 DOI Content Negotiation: Update for current outage 2025-05-22 10:51:16 -04:00
Ilya Zonov 94e7ff02de
Add translator for Litres bookstore (#3430) 2025-05-21 10:39:10 -04:00
Abe Jellinek 19c8cc97d9 CI: Fail instead of timing out when tester page doesn't load 2025-05-21 10:35:56 -04:00
Ilya Zonov b4a6852cd1
Add translator for Habr (#3428) 2025-05-20 14:33:18 -04:00
Abe Jellinek 9ad46e744d
Fix CI (#3450) 2025-05-20 13:02:33 -04:00
Abe Jellinek d32bd3bb22 Primo 2018: Update target
New interface that will apparently have .urlToXmlPnx elements soon. We
can update tests when it's actually detectable.
2025-05-20 11:10:15 -04:00
morganfshirley 0b8f70904d
Added translator for CJTCS (#3445) 2025-05-20 10:56:54 -04:00
Dan Stillman c693a59fcd DOI Content Negotiation: Update for planned outage 2025-05-16 03:12:53 -04:00
Abe Jellinek d9a2688253 De Gruyter: Rename to De Gruyter Brill, update selector for issue page
Brill still has its own separate site, so no need to update that
translator.

https://forums.zotero.org/discussion/124219/zotero-connector-not-getting-pdfs-from-de-gruyter-brill
2025-05-13 09:36:49 -04:00
Abe Jellinek 9a7f28a04f EM: Detect some >2-particle Spanish family names
https://forums.zotero.org/discussion/comment/491943#Comment_491943
2025-05-09 14:26:02 -04:00
Abe Jellinek 54f4e65bf1 Delete Ab Imperio 2025-05-08 14:47:41 -04:00
Abe Jellinek 59a1de0470 Types: Fix monitorDOMChanges() signature 2025-05-08 13:56:22 -04:00
Abe Jellinek 207b7f72ee AEA Web: Add JEL codes when available 2025-05-08 13:43:23 -04:00
Abe Jellinek 6cff1f4c1d EM: Fix error when byline is non-HTML tag
And has no innerText.
2025-05-08 13:21:42 -04:00
Sharon Howard 3659936600
Update Old Bailey Online translator (#3357) 2025-05-08 12:42:03 -04:00
Bardi Harborow 4ef374389f
Add The Times of Israel (#3432)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2025-05-08 12:31:19 -04:00
Abe Jellinek 0bdc06b390 EM: Only abort on multiple bylines if different 2025-05-08 12:28:19 -04:00
Abe Jellinek 889e905800 EM: Remove bad tests, update old ones, add a new one
Not sure what happened to UMass ScholarWorks - metadata isn't very
complete anymore.

And bump lastUpdated.
2025-05-08 12:23:26 -04:00
Abe Jellinek 75352d087e EM: Remove more irrelevant byline children 2025-05-08 12:23:26 -04:00
Abe Jellinek d7a64e5842 EM: Look for byline indicators within class names
If we haven't found any .byline, .bylines, etc., then run a second pass
where we accept things like .article-byline and .byline__wrapper.
2025-05-08 12:23:26 -04:00
Abe Jellinek 48a0faa183 EM: Detect WordPress without generator <meta> tag 2025-05-08 12:23:26 -04:00
Skye Im 332bba842c
Library Catalog (TIND ILS): Fix record URL and add attachments (#3437)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2025-05-08 11:44:12 -04:00
Ilya Zonov 3ffcdba00a
Yandex Books: Fix item variable shadowing (#3444) 2025-05-06 14:41:29 -04:00
Abe Jellinek 18b44c8b1f Russian State Library: contentType -> mimeType 2025-05-01 10:52:09 -04:00
Abe Jellinek 77683d278a The Boston Globe: Fix mimeType, disable outside archive
(For now - the translator was silently failing on non-archive article pages.)
2025-05-01 10:49:17 -04:00
Abe Jellinek 44d83480a4 Reddit: Fix mimeType capitalization in tests 2025-05-01 10:44:33 -04:00
Dan Stillman 2b991e6e37 DOI Content Negotiation: Use rest API for the next couple days
Due to a Crossref outage still affecting Content Negotiation

https://status.crossref.org/
2025-04-30 16:47:33 -04:00
Dan Stillman edb3937b96 Bump lastUpdated on recent translators
GitHub changed their webhook payload on 4/7/2025, which caused the
translators repo not to get recent updates.
2025-04-28 23:07:44 -04:00
Abe Jellinek 00964a667d CourtListener: Bump lastUpdated
Seems like 8e06b8ccb2 may not have gotten
pushed out to clients.
2025-04-28 15:12:24 -04:00
aborel fa1a4c28fb
Add translator for Envidat (#3204)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2025-04-28 14:59:18 -04:00
Ilya Zonov 09b064e02c
Add Yandex Books translator (#3429)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2025-04-28 14:58:46 -04:00
Abe Jellinek 612ecfa0b7
MEDLINE/nbib: Asyncify (#3440) 2025-04-22 11:36:12 -04:00
Abe Jellinek 8e06b8ccb2 CourtListener: Attempt to update for site changes
https://forums.zotero.org/discussion/123539/connector-to-https-www-courtlistener-com-broken
2025-04-15 11:00:13 -05:00
Abe Jellinek f9081536ca HathiTrust: Update for site changes
- New Svelte-based frontend has a different search result structure and
  may not be rendered at load time, so we fall back to parsing from an
  init script if necessary
- Remove brackets from date

https://forums.zotero.org/discussion/123541/zotero-connector-not-working-on-hathitrust
2025-04-15 10:45:38 -05:00
Abe Jellinek 7b36f5a7e9 Newspapers.com: Update tests 2025-04-15 10:29:44 -05:00
Abe Jellinek d02ee39c70 Newspapers.com: Stop saving PDF attachments
PDFs are now built from images on the client side, so there's nothing we
can do.

https://forums.zotero.org/discussion/comment/490316/#Comment_490316
2025-04-15 10:27:40 -05:00
Zoë C. Ma 6abf235b7f
EconPapers: Remove FW code; multiple enhancements (#3134)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2025-04-08 11:01:22 -04:00
Zoë C. Ma 5aa84e297c
NASA ADS: Fix issues with detection and type-determination (#3170)
ADS: Better detection of multiple items & item types

NASA ADS (web translator):

- Detect item type more accurately
- Instead of returning "multiple" based solely on URL, try testing the
  presence of actual results ("checkOnly").
- Add elements to watch for in order to handle the
  appearance/disappearance of results by dynamic filtering.
- Detect multiple items in the "related" views (list of articles related
  to the current article in some way, including citation, similarity,
  and reader interest). If this fails (e.g. if no article cites the
  current one), fall back to identifying this page as a single article.
- Other minor fixes (prefer String#match to RegExp#exec; asyncify doWeb;
  add test case)
- Update tests

ADS Bibcode (search translator):

- More accurate logic for detecting the item type, often caused by
  invalid "TY" field in RIS or underlying data error (conference
  proceedings book identified as JOUR)
- Better detection of earlier arXiv preprints whose "bibstem" is not
  necessarily "arXiv"
- For theses, add thesis type
- Remove a test case for arXiv preprint because it has been replaced by
  the published version. Instead, add two tests for preprints that will
  never be "published" (therefore suitable as test cases in the longer
  term)
- Add test cases for conference paper, book section, and MSc thesis
- Use the "api.adsabs.harvard.edu" domain for the export API
- Don't sort the results; keep the input-order

---------

Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2025-04-08 10:50:36 -04:00
Abe Jellinek 0aeca28290 Datacite JSON: Don't throw when types.schemaOrg is missing 2025-04-08 10:35:23 -04:00
Abe Jellinek 437ca4d9af Reddit: Support sh.reddit.com
And:

- Asyncify
- Update target
- Remove no-op websiteTitle
- Add snapshot as document

Fixes #3439
2025-04-07 10:52:43 -04:00
Dan Stillman 66ebf4b697 Reddit: Strip trailing slash before adding .json
This might fix a 400 error on sh.reddit.com URLs (a new/future version
of the site?).

https://forums.zotero.org/discussion/123203/1645256881-zotero-connector-sh-reddit-com-json-failed-with-status-code-400
2025-04-05 04:33:53 -04:00
Dan Stillman 6e05103170 Reddit: Add missing scheme to saved URLs 2025-04-05 00:48:56 -04:00
Abe Jellinek 8eb08a3fe9 IEEE Xplore: Get cleaner data
- Clean conference titles
- Don't save snapshot when we have a PDF
- Update existing tests
2025-04-04 14:55:32 -04:00
Abe Jellinek 5b446a2066 Frontiers: Clean XML from abstract
Fixes #3433
2025-04-03 14:50:25 -04:00
ezellohar 0b2d2976dd
Primo Normalized XML: Strip authorship info after slash (#3438)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2025-04-03 11:48:37 -04:00
Dan Stillman 1d3f8e299c DOI Content Negotiation: Handle Crossref outage
Unplanned maintenance for March 29, 11:00 - 14:00 UTC

https://status.crossref.org/incidents/nxp3kkx4xxs3
2025-03-29 00:34:45 -04:00
Abe Jellinek 238a3df895 Types: Fix syntax errors 2025-03-28 12:24:46 -04:00
Abe Jellinek 3ff2d78a07 TIND ILS: Use 269 for date
- Convert to using the MARCXML utility function directly
- Use the new MARCXML utility to read date from 269, which is a
  non-standard MARC field
- Update tests
- Asyncify
2025-03-28 11:55:31 -04:00
Abe Jellinek 6446641421 MARCXML: Expose document -> records routine, update tests
Refactor MARCXML importer to expose a utility function, similar to
the MARC importer. This will allow consumers of the MARCXML translator
to instead decide to manually drive the process.
2025-03-28 11:55:31 -04:00
Abe Jellinek b4c2573997 MARC: Get contributor from field 720
720 is sometimes used e.g. in datasets to describe additional
contributors.
2025-03-28 11:55:31 -04:00
Abe Jellinek a11115e67b MARC: Allow caller to override item type 2025-03-28 11:55:31 -04:00
Tim Hollmann b3849ae21a
Added LWN.net translator (#3431)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2025-03-26 13:29:36 -04:00
Abe Jellinek a4e777f7ae Datacite JSON: Fall back to alternate titles
Fixes #3435
2025-03-26 11:27:47 -04:00
Abe Jellinek 64a54226e6 Bluesky: Fix error in detectWeb() 2025-03-26 10:26:39 -04:00
Abe Jellinek c3b8382f1d US National Archives Research Catalog: Handle URL w/ query string
https://forums.zotero.org/discussion/comment/488169/#Comment_488169
2025-03-20 11:45:05 -04:00
Abe Jellinek c39954fdd6 Amazon: Update for possible site changes
https://forums.zotero.org/discussion/comment/487747/#Comment_487747
2025-03-20 11:38:42 -04:00
Abe Jellinek 484110c925 APA PsycNET: Update for site changes
- Grab PDFs if user has access via IP
- Update item type detection
- Delete "No Pagination Specified" pages
- Update tests, remove broken search test
2025-03-10 15:49:00 -04:00
Abe Jellinek fd56161715 Web of Science Nextgen: Scrape all results from lazy-loaded pages
Export the whole search result set instead of scraping URLs from the
DOM.

Also:

- Asyncify
- Use dataset item type
2025-03-06 15:15:24 -05:00
Abe Jellinek 45e73116fd Web of Science: Fix error on single-name creator
https://forums.zotero.org/discussion/comment/487163/#Comment_487163
2025-03-06 13:43:14 -05:00
Abe Jellinek d658478af3 CI: Allow modern JS syntax 2025-03-03 16:56:59 -05:00
Abe Jellinek f7d4e977e4 Ovid: Update for site changes
- Work around stateful-only API, try not to mess up user's selection
- Fix PDF link selector
- Split semicolon-separated creators
- Save books from book database

No support for OCE yet.

https://forums.zotero.org/discussion/119214/problems-with-ovid-translator
2025-03-03 16:56:43 -05:00
Sebastian Karcher 1e263be310
Fix datacite editors (#3424) 2025-02-28 16:07:00 -05:00
Sebastian Karcher fcad450b95
Fix Scopus search (#3420)
Closes https://github.com/zotero/translators/issues/3419
2025-02-19 22:42:13 -05:00
Dan Stillman 60a7cb79e9 Update issue template and contact link description 2025-02-10 23:30:35 -05:00
Abe Jellinek 63b4ce23ab Substack: Support home URLs
No tests because these don't work unless you're logged in.

Closes #3415
2025-02-03 14:53:02 -05:00
Abe Jellinek 107cabd195 CI: Fix output parsing when translator name contains capital T
This is not ideal.

Fixes #3414
2025-01-29 14:16:05 -05:00
Tim Sherratt 248804fc82
Fix for missing attachments with Libraries Tasmania (#3412) 2025-01-29 13:59:05 -05:00
Thomas Rambø b59e11c7ba
Library Catalog (TIND ILS): Enrich item type from Schema.org (#3409)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2025-01-29 13:55:51 -05:00
infrahistory a93eaee137
Trove: Correct page number handling for newspapers (#3410)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2025-01-27 15:42:01 -05:00
Abe Jellinek bb9efc470b Washington Post: Don't scrape authors from related links
Fixes #3408
2025-01-27 15:23:59 -05:00
Wenzhi Ding d4e43e214d
Foreign Affairs: Update for site changes (#3407)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2025-01-21 11:28:12 -05:00
Stephan Hügel 8396616aa8
Add translator for Bluesky (#3400) 2025-01-15 13:00:14 -05:00
jiaojiaodubai 6497f56219
clinicaltrials.gov: fix #3403 (#3404) 2025-01-15 12:42:28 -05:00
Dan Stillman e5b6d98ea5 DOI Content Negotiation: Restore Crossref outage workaround
More planned maintenance for Jan 14, 06:00 - 11:00 UTC

https://status.crossref.org/incidents/nfjw3myvh981
2025-01-11 03:08:34 -05:00
Emiliano Heyns c84ee621e3
Citavi 5 XML: Add BibTeX Key import (#3405) 2025-01-04 01:31:51 -05:00
Abe Jellinek 368d01bb94 Open WorldCat: Handle updated response format 2024-12-17 10:41:06 -05:00
Dan Stillman 3226b5a963 CI: Update actions/cache to v4 2024-12-14 01:36:04 -05:00
Abe Jellinek 8607c377bf Goodreads: Update for site change
https://forums.zotero.org/discussion/120426/goodreads-translator-no-longer-detects-books
2024-12-11 13:50:13 -05:00
Abe Jellinek f2ddb99a63 SciELO: Use language-aware abstract and DOI
https://forums.zotero.org/discussion/120295/articles-with-versions-in-two-languages-and-two-dois
2024-12-06 13:29:41 -05:00
Bardi Harborow 5f6cf567c7
Fix Dagstuhl Research Online Publication Server translator (#3397) 2024-12-03 15:03:13 -05:00
Sebastian Karcher a2bd2f25e3
T&F: BibTeX hotfix (#3399) 2024-12-03 14:57:56 -05:00
Abe Jellinek f7f06c2538 arXiv: Parse Atom manually to work around Connector issue
https://forums.zotero.org/discussion/comment/480521/#Comment_480521

Was working fine in the client/Scaffold, but not in the browser due to
zotero/zotero-connectors#526. Easy enough to work around it for now.
2024-12-03 10:55:13 -05:00
Abe Jellinek 9f1d764903 PICA: Extract more page numbers, add missing localization, fix URL field
https://forums.zotero.org/discussion/119970/catalog-records-and-pagination-loss-in-zotero-recording
2024-11-26 10:26:33 -05:00
Abe Jellinek 4cadb3e145 PubMed Central: Throw when PMC returns error
Prevent silent failures when the backend is having issues (as it is
right now); this allows a fallback to EM, which works quite well.
2024-11-21 16:03:11 -05:00
Abe Jellinek daa4501bbe AustLII: Don't add Code to case items
https://github.com/zotero/translators/pull/2882#issuecomment-2488572263
2024-11-21 13:54:16 -05:00
Abe Jellinek 60cf886195 APS: Only pull text from abstract
https://forums.zotero.org/discussion/comment/479783/#Comment_479783
2024-11-21 13:50:45 -05:00
Abe Jellinek 6696be6cc2
arXiv: Always add DOI (#3390) 2024-11-21 12:51:46 -05:00
Abe Jellinek 21a45ca590 Wording 2024-11-21 11:53:49 -05:00
Abe Jellinek 6c34a311d0 Allow issues again? 2024-11-21 11:50:42 -05:00
Abe Jellinek 912c514fef Clarify issue reporting 2024-11-21 11:46:35 -05:00
Abe Jellinek 75b2eb9ad8 AustLII: Update tests 2024-11-20 11:03:59 -05:00
Abe Jellinek 5c77d6977d AustLII: Get court abbreviation from URL, support classic view
Fixes #3389
2024-11-20 11:01:36 -05:00
Abe Jellinek 552b3dc129 Cambridge Core: Fix book PDFs
Closes #3382
2024-11-20 10:43:17 -05:00
Abe Jellinek bdb36008ba APS: Update for site changes
Fixes #3388
2024-11-19 15:53:47 -05:00
Sebastian Karcher 43fce727d6
PMC Hotfix (#3380) 2024-11-19 13:08:45 -05:00
Abe Jellinek bc846072a5 Open WorldCat: Update ISBN ranges
https://forums.zotero.org/discussion/comment/479027/#Comment_479027
2024-11-12 11:48:21 -05:00
Abe Jellinek 7ca20decc6 OSF Preprints: Grab PDF link from page
https://forums.zotero.org/discussion/119492/pdfs-not-saved-from-psyarxiv-socarxiv-when-using-connector
2024-11-07 17:14:28 -05:00
Abe Jellinek d1bb75a7c2 CI: Update linter cache from stdin
Fixes lint errors when length of translator header is different in
memory and on disk.

Also replace cache object with Map.
2024-11-06 11:25:51 -05:00
Northword 874154ce49
Crossref Unixref XML: Remove space before sub and sup in title (#3374) 2024-10-30 11:08:15 -04:00
Abe Jellinek 51cf9bf665 Newspapers.com: Support /image/ pages as multiples
https://forums.zotero.org/discussion/comment/477807/#Comment_477807
2024-10-29 11:15:02 -04:00
Dan Stillman cdc1712be9 Lulu: Bail properly from detectSearch()
Fix to a90a241126
2024-10-24 15:26:10 -04:00
Abe Jellinek d247318f42 Frontiers: Fix getDOI() on /journals/* pages 2024-10-24 11:14:50 -04:00
Abe Jellinek 30eca8d6e4 Newspapers.com: Update for site changes
- Unify clipping and article scraper code
- Update target

https://forums.zotero.org/discussion/119049/newspapers-com-metadata
2024-10-24 10:55:39 -04:00
Dan Stillman a90a241126 Lulu: Fix `unreachable code after return statement` warnings
And fix inconsistent return
2024-10-24 00:02:27 -04:00
Abe Jellinek 76fab728fa arXiv: Fix ID extraction when URL has hash
https://forums.zotero.org/discussion/118985/zotero-connector-bug-failed-to-save-arxiv-page
2024-10-22 12:12:38 -04:00
Abe Jellinek 448baccad0 ProQuest: Update for site changes
- Support "Full Citation" view (inline metadata on viewer page)
- Parse "Degree date"
- Fix publicationTitle being set to place for some newspapers
- Pull Historical Newspapers dates and pages
- Remove session IDs from URLs
- Update tests where possible

https://forums.zotero.org/discussion/comment/477153/#Comment_477153
2024-10-22 12:07:06 -04:00
Abe Jellinek 017fdf0f44 Delete arXiv Vanity 2024-10-09 10:34:56 -04:00
Abe Jellinek 115162d2eb K10plus ISBN: Remove 'pica.mat' filter
Seems to be excluding valid results.

https://forums.zotero.org/discussion/comment/467454/#Comment_467454
2024-10-09 10:25:53 -04:00
Jonas Zaugg 30664cea8f
arXiv: Use Atom API instead of OAI (#3366)
Co-authored-by: zoe-translates <116055375+zoe-translates@users.noreply.github.com>
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2024-10-09 09:57:09 -04:00
Abe Jellinek e6f65ba72c clinicaltrials.gov: Use new API
- Old API removed
- Classic site is no longer available

https://forums.zotero.org/discussion/118562/persistent-issues-pulling-from-clinicaltrials-gov
2024-10-08 14:21:30 -04:00
Abe Jellinek 56c3b87d7d
ScienceDirect: Don't add `isDTMRedir` URL param (#3368) 2024-10-03 10:30:37 -04:00
Abe Jellinek e7d033c178 ACS Publications: Don't use Object.hasOwn()
Not supported on older browsers.
2024-09-30 09:50:25 -04:00
Abe Jellinek 518493acb9 IEEE Xplore: Use direct PDF URL as fallback
May address https://forums.zotero.org/discussion/118231/no-import-of-pdfs-from-ieee-explore-via-connector-firefox-possible
2024-09-30 09:42:02 -04:00
Abe Jellinek 60ab069092 DOI Content Negotiation: Update tests 2024-09-27 10:37:09 -04:00
Abe Jellinek f784fff615 DOI Content Negotiation: Remove CrossRef outage workaround
Outage is over.

Reverts 87bb5b2647
2024-09-27 10:36:04 -04:00
smachefert 22fa76e1fe
Primo: Grab callNumber in <bestlocation>, remove failing tests (#3360) 2024-09-26 10:37:40 -04:00
Sylvain Machefert ce30da9524
PICA: Fix Sudoc multiples (#3362) 2024-09-26 10:26:12 -04:00
aldente-hu 263546a74e
CiNii Articles -> CiNii Research, update for site changes (#3363)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2024-09-26 10:24:39 -04:00
Abe Jellinek 2c553e90a7 IEEE Xplore: Log PDF page contents when regex doesn't match
https://forums.zotero.org/discussion/118231/no-import-of-pdfs-from-ieee-explore-via-connector-firefox-possible
2024-09-26 09:31:16 -04:00
Dan Stillman 87bb5b2647 DOI Content Negotiation: Handle upcoming Crossref outage
Crossref is retrying their maintenance from last month on Sep. 16-17,
which means content negotiation for Crossref DOIs will be down for
another 24-hour period. (Last time they didn't actually realize it was
down -- I told them they were returning 200s with 503 error messages in
the body -- and this time they're doing it intentionally...) So during
that period, make an extra request to check the registration agency of
each DOI, and if it's Crossref, use their REST API, which is remaining
up.
2024-09-14 22:15:04 +02:00
Martynas Bagdonas 41673978cf
Update Crossref REST translator (#3359) 2024-09-14 15:53:51 -04:00
Tim Sherratt 3b4ec8298e
minor fix for Queensland State Archives (#3356) 2024-09-03 11:24:13 -04:00
Abe Jellinek 6c9d01f6a3 Emerald Insight: Use new API when possible
Closes #3332
2024-08-29 11:32:15 -04:00
Adam J Bravo b3dd8cfa6c
Adding translator for Library of Congress Digital Collections (#3354)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2024-08-22 10:23:45 -04:00
Abe Jellinek 9eb7cabbef
DOI: Recover when one DOI fails to resolve (#3312) 2024-08-21 18:09:03 -04:00
Tim Sherratt ca01e23e65
Add translator for Public Record Office Victoria (#3233) 2024-08-21 15:48:59 -04:00
Abe Jellinek b39ffb20c4 QSA: Anchor regex 2024-08-21 15:41:55 -04:00
Tim Sherratt e62d24350a
New translator - Queensland State Archives (#3355)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2024-08-21 15:41:12 -04:00
Abe Jellinek d515188ec4 Delete HLAS (historical) 2024-08-21 13:47:20 -04:00
Adam J Bravo 3439b09f9e
National Archives: Update API URL, add catalog, external links (#3353)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2024-08-21 13:44:07 -04:00
Abe Jellinek 1ca9f86eb5 De Gruyter: Book section improvements
- Get editors from RIS
- Get full book title, not just part before colon
2024-08-12 15:43:00 -06:00
yuchen-lea 1b7d772db0
Douban: support numeric userID for multiple (#3350) 2024-08-08 12:55:58 -06:00
Abe Jellinek f8bc01e48c TinREAD: Filter out dummy series items
https://forums.zotero.org/discussion/comment/469492/#Comment_469492
2024-08-01 10:15:57 -04:00
Franklin Pezzuti Dyer 1124865649
Add translator for TinREAD library catalogs (#3223)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2024-07-30 10:57:40 -04:00
Sebastian Karcher f8f3277788
Add OpenAlex web and JSON translator (#3269)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2024-07-30 10:48:21 -04:00
Dan Stillman 6aa0d2f3bf ACM: Fix PDF downloads
Closes #3348
2024-07-30 01:21:06 -04:00
Abe Jellinek d8006e0af2 RERO ILS: Handle authorized_access_point + edge cases
https://forums.zotero.org/discussion/116276/rero-ils-translator-broken
2024-07-24 16:02:07 -04:00
Abe Jellinek 5f03dc91ba
ProQuest: Support Archive Finder and site changes (#3341) 2024-07-24 09:53:25 -04:00
Alex T. 7baf5eb647
eLibrary.ru: Name parsing logic fixes, test updates (#3338) 2024-07-24 09:51:15 -04:00
Sebastian Karcher 21a40178c3
Fix JAMA (Silverchair) (#3335)
https://forums.zotero.org/discussion/115948/cannot-import-pdf-file-from-jama#latest
2024-07-24 00:24:28 -04:00
Abe Jellinek f5d465b7aa Merge Springer Books into Springer Link
Move tests (which are no longer very useful since they're all
multiples - need to figure that out!) to Springer Link. No other changes
necessary.

Closes #3304
2024-07-22 16:12:23 -04:00
Alex T. d02d3f7b6a
The Met: Update for site changes, asyncify, lint (#3345) 2024-07-22 15:04:06 -04:00
Alex T. 5908f0f6f8
ePrint: add support for non-PDF attachments (#3337) 2024-07-22 15:02:05 -04:00
Abe Jellinek c7199cc0bd CI: Group log lines 2024-07-22 14:58:55 -04:00
Sebastian Karcher aa67ced33e
On master: Update WaPoCover additional formats; asyncifySee https://forums.zotero.org/discussion/115760/problems-with-washington-post-translator/p1 (#3336) 2024-07-13 23:59:50 -04:00
Martynas Bagdonas 0fd931ab9b
Add underline annotation support to Markdown and HTML translators (#3334) 2024-07-11 04:59:56 -04:00
Abe Jellinek c528844c36 ERIC: Don't set duplicate pub title on reports
And update tests for other changes.
2024-07-05 07:59:21 -04:00
Abe Jellinek e368f7b784 ProQuest: Fix multiples on MV3
https://forums.zotero.org/discussion/115508/zotero-connector-not-working-for-proquest-databases-on-chrome
2024-07-05 07:56:52 -04:00
Dan Stillman 11d37c9c91 IEEE Xplore: Fix saving from PDF URLs and maybe some search pages
But search pages aren't detecting properly for me, so that might need to
be fixed separately

Fixes #3333
2024-07-05 03:21:38 -04:00
Abe Jellinek fdcdb127ac ProQuest Ebook Central: Monitor DOM changes for search results 2024-07-03 13:15:09 -04:00
Abe Jellinek 61cab7f51b ProQuest Ebook Central: Fix multiples
- New URL format (kept the old in case some instances still use it)
- Result links go to a redirect page, so rewrite the URLs to skip it
2024-07-03 13:12:32 -04:00
Abe Jellinek 64509648bb
T&F+NEJM: Refactoring, site changes, support reader pages (#3330)
- Asyncify
- Support new NEJM issue pages
- Get dates from HTML
- Use default ISSN for NEJM
- Clean up tags
- Don't grab broken creators from RIS
- Support PDF/EPUB reader pages and download EPUBs
2024-07-03 06:32:49 -04:00
Abe Jellinek 7dc9469a8b CI: Disallow document global 2024-06-27 12:12:30 -04:00
Sondre Bogen-Straume e2bcb03a15
Add translator for Brukerhåndboken (#3297)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2024-06-27 12:05:45 -04:00
Abe Jellinek 7d3a67b6ee SVT Nyheter: Rewrite and update for site changes
Fixes #3326
2024-06-27 11:32:09 -04:00
advoropaev 0374a06a47
eLibrary.ru: Update for site changes (#3289)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2024-06-24 15:36:35 -04:00
Dave Bunten dbe6fe123c
Add translator for CITATION.cff file references (#3274)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2024-06-24 15:06:54 -04:00
Adomas Ven 682cb285cd
IEEE Xplore: Remove detect web check for top-frame (#3322)
This was added in 2012 (2534bcdb) for Z4FX and is no longer relevant
in any place where we run translation
2024-06-19 03:55:56 -04:00
Abe Jellinek ee9ed8df2c Bangkok Post: More tweaks
- Remove getMetaTag(), just use attr()
- Fix opinion piece author extraction
2024-06-18 16:47:07 -04:00
Matt Mayer dda46ea9b5
Fix Bangkok Post translator (#3308) 2024-06-18 16:39:58 -04:00
Abe Jellinek 427d10c137
Brill: Update for site changes (#3319) 2024-06-14 11:38:12 -04:00
Abe Jellinek fa69cf7b65 ScienceDirect: Don't save snapshots on search results (#3320)
Closes #3316
2024-06-14 08:03:53 -04:00
Abe Jellinek 241a99cf72 ScienceDirect: Asyncify (#3320)
Closes #3315
2024-06-14 08:03:36 -04:00
Abe Jellinek 09e3751758 PubFactory Journals: Remove meta-in-body workaround (#3318) 2024-06-14 00:46:30 -04:00
Abe Jellinek 047cda3a84 EM: Always look for meta tags in head and body (#3318) 2024-06-14 00:46:24 -04:00
Brendan O'Connell b947ce66c9
Add PubFactory Journals (#3009)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2024-06-04 14:15:43 -04:00
Abe Jellinek 8f6c91b0d6 De Gruyter: Fix books being saved as sections
https://forums.zotero.org/discussion/105177/zotero-connector-saving-book-as-book-chapter-from-de-gruyter
2024-05-29 13:11:21 -04:00
Abe Jellinek 6a0d413b79 Twitter: Quick fix for translation error
We've lost URL unshortening on most versions of the site for now, but at
least it doesn't error. They seem to be A/B testing, or maybe just
randomizing, the way links are displayed.

Sometimes (and *always* with an ad blocker enabled) I'm actually seeing
links displayed in full on the page, without t.co shortening; without an
ad blocker, it varies between that layout and one where the full URLs
are nowhere in the page source, meaning there's likely no way for us to
unshorten them.

https://forums.zotero.org/discussion/114434/twitter-x-translator-extension-resorts-to-generic-embedded-metadata
2024-05-24 13:09:02 -04:00
Sebastian Karcher c140b80588
Update Datacite JSON (#3280) 2024-05-17 16:20:43 -04:00
Joey Takeda 650cbb8564
Rewrite of DHQ Translator (#3306)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2024-05-15 11:10:26 -04:00
Abe Jellinek c46011097e CI: Don't report lint error when testCases is empty 2024-05-10 13:08:23 -04:00
Sebastian Karcher d0e7827d06
Fix EBSCOhost Title & PDF download (#3300) 2024-05-09 12:56:03 -04:00
Abe Jellinek 3871bb2a11 Springer Link: Support new book chapter list structure
Fixes #3302
2024-05-09 12:41:20 -04:00
Abe Jellinek ffb252e58b
Note HTML & Note Markdown: Add annotation key to all reader links (#3298) 2024-04-24 11:00:03 -04:00
sebastian-berlin-wmse b3dd2b40c1
Add translator for LIBRIS ISBN (#3184) 2024-04-23 14:47:31 -04:00
Geoff Banh 82f28ce75a
YouTube: Fix missing fields when run from translation-server (#3293) 2024-04-11 12:25:04 -07:00
Dan Stillman 5af5f73c11 Twitter: Detect on x.com as well for mobile app
The iOS app uses x.com, while the website still uses twitter.com.
2024-04-05 04:17:28 -04:00
Georg Mayr-Duffner b04cfc962f
PNX: Remove $$0-prefixed authority information (#3295) 2024-04-04 13:59:09 -04:00
Abe Jellinek 3acc13a70d CI: Apply --diff-filter=d to all diff calls 2024-04-04 12:24:31 -04:00
Abe Jellinek 820b285549 CI: Don't try to lint deleted translators 2024-04-04 11:57:43 -04:00
jiaojiaodubai d6e325dc1d
Web of Science Nextgen: Support .cn top-level domain (#3294) 2024-04-03 02:03:12 -04:00
Alex T b6d1b858e8
Research Square: fix publication date retrieval (#3292) 2024-04-01 15:23:07 -04:00
wolf 7efeb1955c
Fix multi detect in JSTOR (#3291) 2024-04-01 14:55:50 -04:00
Geoff Banh ff73d0dcb8
Embedded Metadata: Exclude single "Condé Nast" W3 author (#3287) 2024-03-27 16:11:37 -04:00
Sebastian Karcher de439f74c3
Update TimesMachine (#3286)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2024-03-27 11:52:48 -04:00
Kun CHEN 97cd07f406
Fix APA PsycNET `fulltext` match issue (#3276) 2024-03-25 14:19:13 -04:00
Sebastian Karcher 0cd3df5ef7
Update CrossRef for Preprints et al. (#3278) 2024-03-25 11:30:17 -04:00
Sebastian Karcher e5d3420edf
Updates to use preprint item type (#3279) 2024-03-25 11:21:14 -04:00
Abe Jellinek b2c73c9638 .eslintrc: Don't add blank line before /** END TEST CASES **/ 2024-03-25 11:20:41 -04:00
Lars Willighagen a3591e1ef7
Exclude French plural definite article from citekeys (#3283) 2024-03-25 11:09:47 -04:00
aborel 1c99c1a2b0
Zenodo -> InvenioRDM, support more repositories (#3206)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2024-03-20 10:52:41 -04:00
Sebastian Karcher d81f5fdb5d
Fix OSF Preprints (#3277)
remove tests for preprint item type -- that's now 2 years old.
2024-03-19 22:29:41 -04:00
Abe Jellinek 1d7c11ec5a
Note HTML & Note Markdown: Support EPUB/snapshot annotations (#3253) 2024-03-19 11:47:31 -04:00
aldente-hu f3404ea73f
J-Stage: Handle Japanese names properly (#3157)
Co-authored-by: zoe-translates <zoe.ma@pm.me>
2024-03-19 10:13:56 -04:00
Sebastian Karcher ab9cb7adce
Update Turkish National Library, lint MARC (#3271) 2024-03-18 12:16:07 -04:00
Sebastian Karcher 5b3600e8a2
Fix longstanding bug for L with stroke (#3275)
https://forums.zotero.org/discussion/70322/ive-notice-that-zotero-has-a-problem-with-polish-letter-l-k#latest
2024-03-17 23:38:47 -04:00
Abe Jellinek 41966c2d0b CI: Improve header-translator-type rule
- Add detectSearch and doSearch to the list of handlers we check
- Warn very explicitly when a web translator declares too many types
2024-03-14 17:25:06 -04:00
Abe Jellinek c18f6ee030 CBC: Not a search translator
06ba6d625f (r139804051)
2024-03-14 16:55:22 -04:00
Abe Jellinek 06ba6d625f Merge branch 'geofferb/master' 2024-03-14 15:03:38 -04:00
Abe Jellinek facbef8de9 CBC: Small fixes
- Update target to include slash
- Update one test for data change
2024-03-14 15:03:25 -04:00
geoff B d916216f99 Add translator for CBC.ca 2024-03-14 15:03:25 -04:00
Abe Jellinek ea4775bd1b Springer Link: Support new journal layout
Fixes #3247
2024-03-11 13:59:32 -04:00
Abe Jellinek e8a2581696 Publications Office of the EU: Download one PDF, improve metadata
- Only detect when DOI is present, since we search using that
- Use innerText for search result labels so <br>s become spaces
- Download current-language PDF if possible, falling back to English and
  then anything available
- Don't parse institutional authors
- Remove "LU" place
- Add tags
2024-03-08 12:58:35 -05:00
Laurence Stevens 251549a4c2
Add translator for The Independent (#3251) 2024-03-07 10:56:25 -05:00
Sebastian Karcher 86a51975f4
Fix author split in T&F ebooks (#3267) 2024-03-07 10:52:57 -05:00
zoe-translates ab50e8c580
Frontiers: Improve metadata, save supplements & multiples (#3145) 2024-03-05 15:16:30 -05:00
Dan Stillman 49dc06a079 eLife: Fix PDF downloads
https://forums.zotero.org/discussion/112526/saving-from-elife-does-not-download-pdf
2024-03-05 05:53:33 -05:00
EdwardGao 42cc3d5edc
Google Presentation: Update PDF export URL (#3259) 2024-02-29 12:27:09 -08:00
Abe Jellinek 7bed28c0ed Nature: Delete number when it matches issue, update tests
Fixes #3255
2024-02-29 12:23:44 -08:00
Philipp Zumstein 8cc630507f
Zenodo: Support multiples in Communities (#3263) 2024-02-29 12:14:23 -08:00
Abe Jellinek 7c0b19974d CI: Update `chromedriver`
Fixes #3258
2024-02-28 13:37:10 -08:00
Abe Jellinek 9a1d789475 T&F: Add subtitle if present 2024-02-28 13:21:17 -08:00
Abe Jellinek bad6238df3 Crossref Unixref XML: Remove extra colon when adding subtitle 2024-02-28 13:21:17 -08:00
Abe Jellinek e7004416a8 Primo Normalized XML: Recognize 'pbooks' as book
https://forums.zotero.org/discussion/112192/wrong-item-type-for-books-primo-ve
2024-02-26 17:42:02 -08:00
Adomas Ven e84ecfb370
CI: Specify the Chrome extension key. See zotero/zotero-connectors#460 (#3260) 2024-02-20 07:44:26 -05:00
Sebastian Karcher 7837c42670
Fix CambridgeCore RIS regex. asyncify (#3257) 2024-02-18 13:27:27 -05:00
Franklin Pezzuti Dyer c07d2dfb97
Adding Harvard Caselaw Access Project translator (#3230)
Fixes zotero/translators#3225
2024-02-17 23:01:23 -05:00
Sebastian Karcher ee832ffcda
Fix ORCID ID links appearing in ProQuest author list (#3256)
https://forums.zotero.org/discussion/111918/link-to-external-site-problem#latest
2024-02-17 22:56:56 -05:00
Abe Jellinek edf44a1943
ScienceDirect: Capture italics in titles, update tests (#3246) 2024-02-08 13:05:33 -05:00
Abe Jellinek 12021cddbb YouTube: Grab correct creator name on desktop
https://forums.zotero.org/discussion/111148/saving-youtube-videos-have-the-wrong-director
2024-02-05 13:28:34 -05:00
Sebastian Karcher ac6628e867
Update EBSCO DL Search (#3248)
And do a bit more for item type. Reported: https://forums.zotero.org/discussion/111468/zotero-connector-eds-ebsco-discovery-service-not-working-correctly/p1
2024-02-04 14:41:35 -05:00
Sebastian Karcher cc94c2f725
Add CourtListener (#3226)
Closes  #3224
2024-02-04 14:39:25 -05:00
wolf d955310149
Unbreak NYPL translator when annotatedMarc = null (#3237)
* unbreak when annotatedMarc = null

* bump timestamp
2024-01-27 04:17:31 -05:00
Kagami Sascha Rosylight 469b1b0576
Replace newline to space with xargs (#3213) 2024-01-22 16:51:45 -05:00
Kagami Sascha Rosylight 4a8bd03064
Wait for `translatorServer.serve()` (#3231) 2024-01-17 09:32:04 -08:00
Sebastian Karcher 35fc547908
Fix Retsinformation (#3227)
after update of internal API.
Reported: https://forums.zotero.org/discussion/109451/problems-with-translator-retsinformation#latest
2024-01-15 23:57:59 -05:00
Sebastian Karcher 564c65cb90
DNB Hotfix (#3228)
asyncified but left other code like xpaths in place

reported: https://forums.zotero.org/discussion/110825/translator-deutsche-nationalbibliothek#latest
2024-01-15 23:57:13 -05:00
Abe Jellinek 6b4a4dce60 CI: Use constant extension ID
Thanks @saschanaz: https://github.com/zotero/translators/pull/3210#issue-2058323242
2024-01-09 20:54:03 -05:00
Sebastian Karcher d24b779808
BnF Fix multiples (#3221)
https://forums.zotero.org/discussion/comment/451953#Comment_451953
2024-01-08 23:05:06 -05:00
Sebastian Karcher 8e3f5722e3
Fix Rechtspraak.nl (#3220)
https://forums.zotero.org/discussion/110653/zotero-connector-no-longer-working-rechtspraak-nl/p1
2024-01-08 23:04:45 -05:00
Elsa Granger c73db0a6b2
Use https when access export.arxiv.org (#3216) 2024-01-05 07:41:18 -05:00
Kagami Sascha Rosylight 8cc91dcff1
Run `npm run lint` only when there's any translator change (#3212) 2023-12-28 15:05:25 -05:00
Dan Stillman 713999d25c ScienceDirect: Fix detection on pages with query strings containing "pdf"
https://forums.zotero.org/discussion/110434/60091619-sciencedirect-author-and-pdf
2023-12-28 06:22:33 -05:00
Emiliano Heyns 450efe2d87
stock eslint support (#3177) 2023-12-27 05:28:32 -05:00
aborel 3ad35cf1e3
Zenodo2023 (#3202) 2023-12-08 04:56:33 -05:00
jiaojiaodubai 7bf0dfbede
Adapt to search pages; Update test cases (#3193) 2023-12-01 04:10:54 -05:00
Sebastian Karcher db2771d52d
EBSCO DL - More URL changes (#3192) 2023-11-26 23:23:13 -05:00
l0o0 eb9fca0787
fix: Update request for exporting CNKI refworks text. Update function to find CNKI database keyword for saving multiple items. Update the matching relationship between dbcode and item type (#3191) 2023-11-23 02:26:02 -05:00
zoe-translates 4d6204d400
Update Haaretz (#3176) 2023-11-06 10:20:12 -05:00
Peter Coombe f4741eca4c
Hyphenated "access-date" in Wikipedia Citation Templates.js (#3178)
Wikipedia citation templates have preferred hyphenated "access-date" parameter rather than "accessdate" for many years. See https://en.wikipedia.org/wiki/Help:Citation_Style_1#Access_date
2023-11-05 16:49:13 -05:00
zoe-translates fd45efc081
Refer/BibIX import: recognize value "Audio" for %0 (type) tag (#3174) 2023-10-27 14:36:06 -04:00
zoe-translates 6df218c9b8
ACS Publications: Fix PDF attachment and supplements; recognize more target pages; efficiency improvements (#3128) 2023-10-27 14:33:06 -04:00
Abe Jellinek 5333a7eb61 T&F+NEJM: Support `/doi/10.` pages
Fixes #3160
2023-10-27 12:04:29 -04:00
zoe-translates ccad9be5bd
Cambridge Engage: Fixes for search; minor date normalization (#3166) 2023-10-24 13:49:51 -04:00
zoe-translates 0121bf0fce
Cairn.info: Serialize requests; fix PDF attachment URL (#3165) 2023-10-24 13:49:34 -04:00
zoe-translates 0fdbcd0fd4
Duke Univ. Press: Serialize multiples, add test case (#3167) 2023-10-24 13:48:42 -04:00
Abe Jellinek 5bc9435b63 CI: Clarify error when run outside a git clone
find-root's default message is "package.json not found in path", which
isn't accurate: we look for .git/, not package.json.
2023-10-24 12:13:57 -04:00
vinothk-hw 9518fb4cdd
Add translator for AccessScience (#3127) 2023-10-19 03:03:40 -04:00
Lars Willighagen 30dcd15276
Add ZOBODAT (#3156) 2023-10-18 10:47:22 -04:00
Dan Stillman 7c4cc221d9 DOI: Serialize DOI Content Negotiation requests 2023-10-18 07:18:22 -04:00
vinothk-hw 9fd351f0ea
Update author and multiple scenario (#3125) 2023-10-16 17:03:02 -04:00
zoe-translates 606ba8218d
The Atlantic: Remove FW code; update for newer website (#3132) 2023-09-26 12:51:27 -04:00
zoe-translates f94af5d875
ESLint plugin: Allow array (of objects) as search translator input (#3149) 2023-09-26 12:18:50 -04:00
Abe Jellinek 394f5b715d CBdL ISBN: Fix error on non-ISBN searches
Fixes #3147
2023-09-26 12:11:27 -04:00
Sebastian Karcher 113b77b14b
Fix IEEE after site change (#3150) 2023-09-24 04:14:34 -04:00
zoe-translates 158299ca47
Google Scholar: Add delays between consecutive network requests. (#3043)
Also:

* Better emulation of page navigation.
* Use external services (DOI and ArXiv API) when possible.
2023-09-23 00:52:37 -04:00
zoe-translates 7711e87f07
DOI Content Negotiation (search translator): Asyncify, serialize requests (#3148)
- doSearch() is turned into an async function. Processing of next input
  DOI string only begins after the previous one has been processed. This
  means no more than one request to the CrossRef service is outstanding
  at any time.
- Add a test case with multiple inputs.

Cf.
https://forums.zotero.org/discussion/107976/importing-references-using-doi-failed
2023-09-22 06:43:39 -04:00
aborel 8e5c648bb1
New web translator: https://www.e-periodica.ch (#3008) 2023-09-21 01:41:33 -04:00
Sebastian Karcher 6a2e0b7825
Fix PhilPapers (#3133) 2023-09-20 13:11:32 -04:00
zoe-translates f88a29b3f0
ClinicalTrials.gov: Don't use Array#at(); don't reinvent ZU.strToISO() (#3139) 2023-09-17 21:46:48 -04:00
zoe-translates e9a6b958c8
IPCC: Use final versions of AR6 WG2 chapters in PDF attachments (#3143) 2023-09-17 21:41:16 -04:00
Sebastian Karcher 0f67da4c73
Fix for EBSCO DL (#3138)
https://forums.zotero.org/discussion/107688/zotero-connector-ebsco-discovery-service/p1

Only have the one guest access, but looks like this is really just a change in the bas URL.
2023-09-17 06:45:58 -04:00
Jacob Lee 5f7e0bd99f
Encyclopedia of Korean Culture (#3122) 2023-09-15 21:59:13 -04:00
Sebastian Karcher fdcacbd9ac
Scopus: Update for new search interface (#3120) 2023-09-15 16:56:06 -04:00
Abe Jellinek 42e14d3be0
Add Câmara Brasileira do Livro ISBN search (#3091) 2023-09-15 16:39:10 -04:00
zoe-translates 868a29413d
New translator: Bosworth-Toller dictionary of Old English (#3027) 2023-09-13 10:28:34 -04:00
zoe-translates 7363e03f77
Boston Review: Fix broken translator; remove FW code (#3106) 2023-09-13 10:27:07 -04:00
Marielle Volz 9868aebb9e
Wikidata: Skip linked resources that contain no RDF metadata (#3109) 2023-09-13 10:24:36 -04:00
Dan Stillman 5187948c67 Library of Congress ISBN: Use the new HTTPS endpoint 2023-08-25 01:07:21 -04:00
zoe-translates 1fcdcbaa9f
Climate Change and Human Health Literature Portal: Fix errors (#3111) 2023-08-24 11:28:22 -04:00
zoe-translates 56f29b8877
APA PsychNet: Prevent flooding when saving multiple; lint cleanup (#3115) 2023-08-24 11:27:31 -04:00
zoe-translates 3e73b583eb
Foreign Affairs: multiple bugfixes (#3119) 2023-08-24 11:25:27 -04:00
Abe Jellinek 4c39a47b0f ProQuest: Update PDF link selector
https://forums.zotero.org/discussion/107136/zotero-connector-proquest-connector-not-importing-pdf-file
2023-08-24 11:19:36 -04:00
Sebastian Karcher 70aa1e2076
Add AquaDocs (#2934)
Requested: https://fediscience.org/@thalassa/109303603306517407

Much of the DC data is not actually in the page header & not in the default output formats, so going through the XML.
2023-08-24 05:38:28 -04:00
zoe-translates 0145a6d1e7
Preprints.org: Avoid flooding with multiples; update element for outlink (#3117)
- Avoid flooding when saving multiples; cf. #2983
- Don't access members of null (result of unmatched selector); this is
  caused by the change to site layout and content for preprints with
  peer-reviewed version.
2023-08-23 04:12:08 -04:00
zoe-translates b6eb880277 Open WorldCat: Fix lint errors
This is done to prevent annoying lint failures in CI
2023-08-22 01:25:00 -04:00
zoe-translates b4f925cbbd Open WorldCat: Don't send requests at once when saving search results
Cf. #2983

In addition, a test case with redirect is deferred to prevent spurious
timeout.
2023-08-22 01:25:00 -04:00
zoe-translates 2e467e0478
ESLint rules: Add "ericNumber" to the allowed keys for search translator (#3114)
This prevents the spurious lint errors in ERIC.js caused by the key
"ericNumber".
2023-08-22 01:24:28 -04:00
zoe-translates a4596b5540
ERIC: fix flooding when saving multiple items from search results (#3113)
Cf. #2983
2023-08-22 01:24:18 -04:00
Dan Stillman 999764abc2 DOI: Update timestamp again 2023-08-18 05:22:35 -04:00
Dan Stillman 083c9e0d79 DOI: Update timestamp 2023-08-18 05:15:25 -04:00
Dan Stillman 937f29704a Revert "DOI web overhaul (#3015)"
Probably causing https://forums.zotero.org/discussion/comment/441290/#Comment_441290

This reverts commit 07bbb58919.
2023-08-18 05:08:11 -04:00
zoe-translates a847b8984c
New York Review of Books: Fix translator broken by site updates (#3094) 2023-08-17 16:21:21 -04:00
Abe Jellinek 8ce9ce194d
Merge pull request #3083 from zoe-translates/embedded-metadata-optional-search-body-for-meta 2023-08-17 16:14:51 -04:00
Abe Jellinek daaa60382d Brill: Always set searchForMetaTagsInBody = true 2023-08-17 16:04:10 -04:00
zoe-translates 5112951e99
Al-Sharekh: Fix detection of multiples; asyncify (#3084) 2023-08-17 15:58:00 -04:00
zoe-translates de71137dc6
index.d.ts: Remove declarations of functions moved to internal namespace (#3093) 2023-08-17 15:28:56 -04:00
zoe-translates 5a6bf02961
New translator: Literary Hub (#2991) 2023-08-17 15:15:06 -04:00
zoe-translates 07bbb58919
DOI web overhaul (#3015) 2023-08-17 15:13:55 -04:00
Brendan O'Connell 839a1b74be
Add COBISS library catalog (#2985)
Co-authored-by: Abe Jellinek <jellinek@berkeley.edu>
2023-08-17 14:59:40 -04:00
Abe Jellinek 51ed2d95da Twitter fixup: Non-capturing group 2023-08-17 14:36:16 -04:00
Abe Jellinek f15c4238a9 Twitter: Update regex
Sorry, I mean X.

https://forums.zotero.org/discussion/107010/zotero-connector-twitter-x-translator-seems-broken
2023-08-17 14:30:22 -04:00
Abe Jellinek 2928aa1bc4 RERO ILS: Fix and update tests
- Detect more item types using existing mapping
- Handle more cases where creator metadata has been moved to an external
  JSON document
- Update tests

https://forums.zotero.org/discussion/106951/rero-ils-site-translator-broken
2023-08-17 11:06:10 -04:00
zoe-translates 61558f8a7b [Minor] Fix an ESLint warning for unused parameter in function 2023-08-16 23:19:16 +08:00
zoe-translates 2682e4c58a EM: Workaround for <meta> from head ending up in body due to invalid HTML
A fairly common consequence of being served invalid HTML is that after
parsing, <meta> elements that should have gone into the <head> end up in
the <body> in the output of DOM parser.

This breaks the EM translator which only looks for <meta> tags that are
immediate descendants of <head> -- the sensible behaviour for
well-behaving documents.

To work around this issue, the default behaviour is not changed, and a
configurable flag is introduced to override it.

When the `searchForMetaTagsInBody` property is set to true, <meta> tags
will be searched for in the immediate descendants of <body>.

With this workaround, Web translators that calls the EM translator don't
have to manipulate the document by putting <meta> elements into the
head manually.

This reduces the likelihood of unintentionally mutating the DOM, and it
keeps the EM-based translator code's cleaner.

A real-world example is the Brill translator, also fixed in this commit.
2023-08-16 23:19:09 +08:00
Alex Tereschenko 9180801bd8
ePrint: refactor to modernize, fix issues, and add functionality (#3079) 2023-08-14 06:31:41 -04:00
morganfshirley e1241286b1
Updated Electronic Colloquium on Computational Complexity translator (#3040) 2023-08-14 06:30:27 -04:00
Sebastian Karcher c3c67911ff
Fix linting on NLoP (#3051) 2023-08-14 04:27:33 -04:00
Marielle Volz 06fed1df88
EM: Fix bug where Facebook profiles get added to author field (#3103)
Fix bug where authors from open graph metadata fields only got added if they contained a Facebook link (as opposed to the intended result which is to skip the field if it did).
2023-08-11 05:16:07 -04:00
Abe Jellinek 27f711219b Open WorldCat: Disable ESLint for ISBN ranges
To fix horrible performance in Sublime, which apparently is not
optimized for thousands of lint errors.
2023-08-08 18:53:16 -04:00
Abe Jellinek f3d77f2327 Open WorldCat: Fall back to archived build ID 2023-08-08 18:53:16 -04:00
Pascal Quach c86fe6b0ad
Add Optimization Online translator (#3042) 2023-08-06 23:11:27 +02:00
Alex Tereschenko 7fc02305ef
Zenodo: use preprint item type, add a respective test (#3100)
Closes #3056.
2023-08-06 16:27:23 -04:00
Alex Tereschenko 1590d01890
Fix CI check breakage due to chromedriver changes (#3101)
As of version 115, ChromeDriver uses different package distribution
method (more details at https://googlechromelabs.github.io/chrome-for-testing/),
and currently used version 95.0.0 is not able to handle that,
so all PR checks fail with the following message:

    Your Chrome version is 115.0.5790.110
    Finding Chromedriver version.
    ChromeDriver installation failed Error: Request failed with status code 404
        at createError (/home/runner/work/translators/translators/node_modules/axios/lib/core/createError.js:16:15)
        at settle (/home/runner/work/translators/translators/node_modules/axios/lib/core/settle.js:17:12)
        at IncomingMessage.handleStreamEnd (/home/runner/work/translators/translators/node_modules/axios/lib/adapters/http.js:269:11)
        at IncomingMessage.emit (node:events:539:35)
        at endReadableNT (node:internal/streams/readable:1345:12)
        at processTicksAndRejections (node:internal/process/task_queues:83:21) {
      config: {
        url: 'https://chromedriver.storage.googleapis.com/LATEST_RELEASE_115.0.5790',
        method: 'get',
        headers: {
          Accept: 'application/json, text/plain, */*',
          'User-Agent': 'npm/8.11.0 node/v17.9.1 linux x64 workspaces/false ci/github-actions'
        },
    <...and so on...>

Just updating the chromedriver package is enough to fix, so here it is.

Tested on my fork of the repo, see e.g.,
https://github.com/alex-ter/translators/actions/runs/5777601767/job/15657962595?pr=1
2023-08-06 16:25:39 -04:00
Dan Stillman 3f7531774d Airiti: Remove search flag
Follow-up to c9784da115
2023-08-04 01:04:23 -04:00
Abe Jellinek ca1b311eb0 Add index.d.ts updater script and update item types 2023-08-03 11:52:01 -04:00
Justin Warren b68ed12912
AustLII translator updates (#2882) 2023-08-03 08:39:13 -04:00
hackbunny 2b08a392f7
Twitter: Update title regex (#3092) 2023-08-02 22:49:42 -04:00
Sebastian Karcher 756ce0791c
MathSciNet Update for new site (#3072) 2023-08-02 02:34:29 -04:00
Dan Stillman c9784da115 Airiti: Update tests
A couple are still returning the wrong item type
2023-07-31 17:06:18 -04:00
Dan Stillman bb8c02b5fc Airiti: Remove search translation
Closes #3088
2023-07-31 17:05:22 -04:00
Marielle Volz fc532cd1a8
Add doctoral thesis to type map (#3090)
Map doctoral thesis (https://www.wikidata.org/wiki/Q56462344) to type thesis in type map
2023-07-28 16:20:43 -04:00
Dan Stillman b5180b5847 RIS: Fix Citavi RIS import
An H2 tag, which Citavi seems to export, caused "entry.tags.indexOf is
not a function", probably for many years (but anyone following our
import instructions wouldn't be importing RIS).

Fixes #2884
2023-07-28 05:46:58 -04:00
233 changed files with 42595 additions and 13978 deletions

View File

@ -2,140 +2,8 @@
'use strict';
const fs = require('fs');
const path = require('path');
const find = require('recursive-readdir');
const { ESLint } = require("eslint");
const argv = require('commander');
const translators = require('../lib/translators');
process.argv = process.argv.map(arg => arg === '--output-json' ? [ '--format', 'json', '--output-file' ] : arg).flat();
argv
.version(ESLint.version)
.option('-o, --output-json [file | -]', 'Write report to file or stdout as JSON')
.option('-f, --fix', 'Automatically fix problems')
.option('--no-ignore', 'Disable use of ignore files and patterns')
.option('--quiet', 'Report errors only - default: false')
.option('--dump-decorated [file]', 'Dump decorated translator to file for inspection')
.parse(process.argv);
/* PATCHES */
// disable the processor so that fixing works
const eslintPluginZoteroTranslator = require('eslint-plugin-zotero-translator');
delete eslintPluginZoteroTranslator.processors;
async function main() {
// split sources to lint into regular javascript (handled by lintFiles) and translators (handled by lintText)
const sources = {
javascripts: [],
translators: [],
errors: 0,
};
let allResults = [];
function findIgnore(file, stats) {
if (stats.isDirectory()) return (path.basename(file) == "node_modules" || path.basename(file) == ".ci");
return !file.endsWith('.js');
}
for (const target of argv.args) {
if (!fs.existsSync(target)) {
console.error(`Target file '${target}' does not exist; skipping`); // eslint-disable-line no-console
continue;
}
const files = fs.lstatSync(target).isDirectory() ? await find(target, [findIgnore]) : [target];
for (const file of files) {
if (path.dirname(path.resolve(file)) === translators.cache.repo) {
const translator = translators.cache.get(file);
if (translator.header) {
translator.filename = file;
sources.translators.push(translator);
}
else {
sources.javascripts.push(file);
}
}
else {
sources.javascripts.push(file);
}
}
}
const eslint = new ESLint({
cwd: translators.cache.repo,
fix: argv.fix,
ignore: !!argv.ignore, // otherwise you can't lint stuff in hidden dirs
});
const formatter = await eslint.loadFormatter();
function showResults(files, results) {
if (argv.quiet) results = ESLint.getErrorResults(results);
for (const res of results) {
sources.errors += res.errorCount;
}
if (results.length) {
console.log(formatter.format(results)); // eslint-disable-line no-console
}
else {
if (Array.isArray(files)) files = files.join(', ');
if (!argv.quiet) console.log(files, 'OK'); // eslint-disable-line no-console
}
}
if (sources.javascripts.length) {
const results = await eslint.lintFiles(sources.javascripts);
if (argv.fix) {
for (const result of results) {
if (result.messages.find(msg => msg.ruleId === 'notice/notice' && msg.fix)) {
console.log(`Not safe to apply 'notice/notice' to ${result.filePath}`); // eslint-disable-line no-console
process.exit(1); // eslint-disable-line no-process-exit
}
}
ESLint.outputFixes(results);
}
if (argv.outputJson) {
allResults.push(...results);
}
else {
showResults(sources.javascripts, results);
}
}
for (const translator of sources.translators) {
if (argv.dumpDecorated) fs.writeFileSync(argv.dumpDecorated, translator.source, 'utf-8');
const results = await eslint.lintText(translator.source, { filePath: translator.filename });
if (argv.fix) {
for (const result of results) {
if (result.output) {
try {
fs.writeFileSync(result.filePath, translators.strip(result.output), 'utf-8');
}
catch (err) {
console.log(`Error writing fixed ${result.filePath}: ${err.message}`); // eslint-disable-line no-console
process.exit(1); // eslint-disable-line no-process-exit
}
}
}
}
if (argv.outputJson) {
allResults.push(...results);
}
else {
showResults(translator.filename, results);
}
}
if (argv.outputJson) {
if (argv.outputJson === '-') {
process.stdout.write(JSON.stringify(allResults) + '\n');
}
else {
fs.writeFileSync(argv.outputJson, JSON.stringify(allResults), 'utf-8');
}
}
else {
process.exit(sources.errors); // eslint-disable-line no-process-exit
}
}
main();
require('../../../node_modules/.bin/eslint')

View File

@ -10,6 +10,6 @@ const requireDir = require('require-dir');
module.exports = {
rules: requireDir('./lib/rules'),
processors: {
'.js': require('./lib/processor'),
}
translator: require('./processor'),
},
};

View File

@ -1,15 +0,0 @@
'use strict';
const translators = require('../translators').cache;
module.exports = {
preprocess: function (text, filename) {
const translator = translators.get(filename);
return [(typeof translator.source === 'string') ? translator.source : text];
},
postprocess: function (messages, _filename) {
return messages[0];
},
};

View File

@ -0,0 +1,55 @@
'use strict';
const { parsed, header } = require('../../processor').support;
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'enforce valid lastUpdated in header',
category: 'Possible Errors',
},
fixable: 'code',
},
create: function (context) {
return {
Program: function (node) {
const filename = context.getFilename();
const translator = parsed(filename);
if (!translator || !translator.header.fields) return; // regular js source, or header is invalid
const lastUpdated = header(node).properties.find(p => p.key.value === 'lastUpdated');
if (!lastUpdated) {
context.report({
loc: { start: { line: 1, column: 1 } },
message: 'Header needs lastUpdated field',
});
return;
}
const format = date => date.toISOString().replace('T', ' ').replace(/\..*/, '');
const now = format(new Date());
const fix = fixer => fixer.replaceText(lastUpdated.value, `"${now}"`);
if (typeof lastUpdated.value.value !== 'string' || !lastUpdated.value.value.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/)) {
context.report({
node: lastUpdated.value,
message: `lastUpdated field must be a string in YYYY-MM-DD HH:MM:SS format`,
fix,
});
return;
}
if (translator.lastUpdated && translator.lastUpdated > lastUpdated.value.value) {
context.report({
node: lastUpdated.value,
message: `lastUpdated field must be updated to be > ${translator.lastUpdated} to push to clients`,
fix,
});
}
}
};
},
};

View File

@ -0,0 +1,65 @@
'use strict';
const fs = require('fs');
const path = require('path');
const uuid = require('uuid/v4');
const { repo, parsed, header, IDconflict } = require('../../processor').support;
const deleted = new Set(
fs.readFileSync(path.join(repo, 'deleted.txt'), 'utf-8')
.split('\n')
.map(line => line.split(' ')[0])
.filter(id => id && id.indexOf('-') > 0)
);
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'disallows translatorID re-use',
category: 'Potential Problems',
},
fixable: 'code',
},
create: function (context) {
return {
Program: function (node) {
const filename = context.getFilename();
const translator = parsed(filename);
if (!translator || !translator.header.fields) return; // regular js source, or header is invalid
const translatorID = header(node).properties.find(p => p.key.value === 'translatorID');
if (!translatorID || !translatorID.value.value) {
context.report({
node: header(node),
message: 'Header has no translator ID',
});
return;
}
if (deleted.has(translatorID.value.value)) {
context.report({
node: translatorID.value,
message: 'Header re-uses translator ID of deleted translator',
fix: function (fixer) {
return fixer.replaceText(translatorID.value, `"${uuid()}"`);
}
});
return;
}
const conflict = IDconflict(filename);
if (conflict) {
context.report({
node: translatorID.value,
message: `re-uses translator ID of ${conflict.label}`,
fix: fixer => fixer.replaceText(translatorID.value, `"${uuid()}"`),
});
}
}
};
}
};

View File

@ -0,0 +1,82 @@
'use strict';
const { parsed } = require('../../processor').support;
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'enforce translatorType against handler functions',
category: 'Possible Errors',
},
},
create: function (context) {
return {
Program: function (program) {
const translator = parsed(context.getFilename());
if (!translator || !translator.header.fields) return; // regular js source, or header is invalid
const functions = program.body.map((node) => {
if (node.type === 'FunctionDeclaration') return node.id && node.id.name;
if (node.type === 'VariableDeclaration'
&& node.declarations.length === 1
&& node.declarations[0].init
&& node.declarations[0].init.type === 'FunctionExpression') {
return node.declarations[0].id.name;
}
return null;
})
.filter(name => name);
const type = {
import: 1,
export: 2,
web: 4,
search: 8
};
const translatorType = translator.header.fields.translatorType;
const browserSupport = translator.header.fields.browserSupport;
if (browserSupport && !(translatorType & type.web)) {
context.report({
loc: { start: { line: 1, column: 1 } },
message: `browserSupport set, but translatorType (${translatorType}) does not include web (${type.web})`,
});
return;
}
for (const name of ['detectWeb', 'doWeb', 'detectImport', 'doImport', 'doExport', 'detectSearch', 'doSearch']) {
const handler = functions.includes(name);
const mode = name.replace(/^(detect|do)/, '').toLowerCase();
const bit = type[mode];
if (handler && !(translatorType & bit)) {
context.report({
loc: { start: { line: 1, column: 1 } },
message: `${name} present, but translatorType (${translatorType}) does not specify ${mode} (${bit})`,
});
return;
}
if (!handler && (translatorType & bit)) {
let message = `translatorType specifies ${mode} (${bit}), but no ${name} present`;
if (translatorType & type.web && mode !== 'web') {
// Lots of common errors involve web translator developers not understanding
// translator type jargon and checking too many boxes - checking "search"
// because the translator supports search pages, or "import" because it
// imports items from the site.
// Be extra explicit when it seems like that might be the situation.
message += `. This web translator is probably NOT a${bit <= 2 ? 'n' : ''} ${mode} translator, `
+ `even if it supports "${mode}" pages or "${mode}ing". Uncheck "${mode}" in Scaffold.`;
}
context.report({
loc: { start: { line: 1, column: 1 } },
message,
});
return;
}
}
}
};
},
};

View File

@ -1,6 +1,6 @@
'use strict';
const translators = require('../translators').cache;
const { parsed, json } = require('../../processor').support;
module.exports = {
meta: {
@ -14,14 +14,15 @@ module.exports = {
create: function (context) {
return {
Program: function (_node) {
const translator = translators.get(context.getFilename());
const translator = parsed(context.getFilename());
if (!translator.source) return; // regular js source
if (!translator || translator.header.fields) return; // regular js source, or header is valid json
if (translator.header.error) {
const err = json.try(translator.header.text, { line: 0, position: 1 });
if (err) {
context.report({
message: `Could not parse header: ${translator.header.error.message}`,
loc: { start: { line: translator.error.line, column: translator.error.column } },
message: `Could not parse header: ${err.message}`,
loc: { start: { line: err.line, column: err.column } },
});
}
}

View File

@ -1,56 +0,0 @@
'use strict';
const translators = require('../translators').cache;
const getHeaderFromAST = require('../translators').getHeaderFromAST;
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'enforce valid lastUpdated in header',
category: 'Possible Errors',
},
fixable: 'code',
},
create: function (context) {
return {
Program: function (node) {
const header = getHeaderFromAST(node);
if (!header.declaration) return;
const translator = translators.get(context.getFilename());
const now = new Date()
.toISOString()
.replace('T', ' ')
.replace(/\..*/, '');
if (!header.properties.lastUpdated) {
context.report({
node: header.declaration,
message: 'Header needs lastUpdated field'
});
}
else if (!/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/.test(header.properties.lastUpdated.value)) {
context.report({
node: header.properties.lastUpdated,
message: `lastUpdated field must be in YYYY-MM-DD HH:MM:SS format`,
fix: function (fixer) {
return fixer.replaceText(header.properties.lastUpdated, `"${now}"`);
},
});
}
else if (translator.lastUpdated && translator.lastUpdated >= header.properties.lastUpdated.value) {
context.report({
node: header.properties.lastUpdated,
message: `lastUpdated field must be updated to be > ${translator.lastUpdated} to push to clients`,
fix: function (fixer) {
return fixer.replaceText(header.properties.lastUpdated, `"${now}"`);
},
});
}
}
};
},
};

View File

@ -1,6 +1,6 @@
'use strict';
const translators = require('../translators');
const { parsed } = require('../../processor').support;
const findRoot = require("find-root");
const fs = require('fs');
const path = require('path');
@ -18,69 +18,63 @@ module.exports = {
create: function (context) {
return {
Program: function (node) {
const header = translators.getHeaderFromAST(node);
if (!header.body) return; // if there's no file header, assume it's not a translator
if (!header.followingStatement) return; // if there's no following statement, there's more significant problems than just the license missing
const translator = parsed(context.getFilename());
if (!translator) return; // regular js source
if (node.body.length < 2) return; // no body?
const options = context.options[0];
if (!options.mustMatch) throw new Error('mustMatch not set');
if (!options.mustMatch) throw new Error('license/mustMatch not set');
if (!options.templateFile) throw new Error('license/templateFile not set');
let firstComment = null;
let copyright = null;
for (const comment of context.getSourceCode().getAllComments()) {
if (comment.loc.start.line <= header.body.loc.end.line) continue; // skip decorator comments
const license = context.getSourceCode().getAllComments().find((comment) => {
return comment.type === 'Block' && comment.value.match(/(BEGIN LICENSE BLOCK[\s\S]+END LICENSE BLOCK)|(Copyright)/i);
});
if (comment.value.includes(options.mustMatch)) {
if (firstComment || comment.loc.start.line > header.followingStatement.start.line) {
context.report({
loc: comment.loc,
message: 'Preferred to have license block at the top'
});
}
return;
if (!license) {
const properties = translator.header.fields;
const copyright = {
holder: properties.creator || 'Zotero Contributors',
period: `${(new Date).getFullYear()}`,
};
if (properties.lastUpdated) {
const year = properties.lastUpdated.split('-')[0] || '';
if (year && year !== copyright.period) copyright.period = `${year}-${copyright.period}`;
}
if (comment.value.match(/copyright/i)) {
copyright = comment;
}
const templateFile = fs.existsSync(options.templateFile)
? options.templateFile
: path.resolve(path.join(findRoot(context.getFilename()), options.templateFile));
if (!fs.existsSync(templateFile)) throw new Error(`cannot find ${templateFile}`);
const template = fs.readFileSync(templateFile, 'utf-8');
firstComment = firstComment || comment;
}
if (copyright) {
const licenseText = '\n\n' + template.trim().replace(/\${(.*?)\}/g, (_, id) => {
id = id.trim();
return copyright[id] || `<undefined '${id}'>`;
}) + '\n\n';
context.report({
loc: copyright.loc,
message: `Copyright preferred to be ${options.mustMatch}`,
message: 'Missing license block',
loc: node.body[1].loc.start,
fix: fixer => fixer.insertTextBefore(node.body[1], licenseText),
});
return;
}
if (!options.templateFile) throw new Error('templateFile not set');
const templateFile = fs.existsSync(options.templateFile)
? options.templateFile
: path.resolve(path.join(findRoot(context.getFilename()), options.templateFile));
if (!fs.existsSync(templateFile)) throw new Error(`cannot find ${templateFile}`);
const template = fs.readFileSync(templateFile, 'utf-8');
copyright = {
holder: header.properties.creator ? header.properties.creator.value : null,
period: `${(new Date).getFullYear()}`,
};
if (header.properties.lastUpdated) {
const year = header.properties.lastUpdated.value.split('-')[0] || '';
if (year && year !== copyright.period) copyright.period = `${year}-${copyright.period}`;
if (node.body.length > 2 && node.body[1].loc.start.line < license.loc.start.line) {
context.report({
loc: license.loc,
message: 'Preferred to have license block at the top'
});
return;
}
const licenseText = '\n\n' + template.trim().replace(/\${(.*?)\}/g, (_, id) => {
id = id.trim();
return copyright[id] || `<undefined '${id}'>`;
}) + '\n\n';
context.report({
node: header.followingStatement,
message: "Missing license block",
fix: (firstComment && firstComment.type === 'Block')
? undefined
: fixer => fixer.insertTextBefore(header.followingStatement, licenseText),
});
if (!license.value.match(new RegExp(options.mustMatch))) {
context.report({
loc: license.loc,
message: `Copyright preferred to be ${options.mustMatch}`,
});
}
}
};
},

View File

@ -12,7 +12,7 @@ module.exports = {
create: function (context) {
return {
Program: function (node) {
Program: function (_node) {
let lineno = 0;
for (const line of context.getSourceCode().getText().split('\n')) {
lineno += 1;
@ -20,7 +20,6 @@ module.exports = {
const m = line.match(/for each *\(/);
if (m) {
context.report({
node,
message: "Deprecated JavaScript 'for each' statement",
loc: { start: { line: lineno, column: line.indexOf(m[0]) + 1 } },
});

View File

@ -3,7 +3,7 @@
const fs = require('fs');
const path = require('path');
const translators = require('../translators').cache;
const { parsed } = require('../../processor').support;
module.exports = {
meta: {
@ -19,11 +19,8 @@ module.exports = {
Program: function (node) {
if (process.platform == 'win32') return; // X_OK always succeeds on Windows
const translator = translators.get(context.getFilename());
if (!translator.source) return; // only check translators
const filename = context.getFilename();
if (!parsed(filename)) return; // only check translators
try {
fs.accessSync(filename, fs.constants.X_OK);

View File

@ -26,7 +26,7 @@ module.exports = {
message: node.callee.property.name === 'indexOf'
? "Unnecessary '.indexOf()', use '.includes()' instead"
: "Unnecessary '.search()', use 'RegExp#test()' instead",
*fix(fixer) {
* fix(fixer) {
let test = node.callee.property.name === 'indexOf'
? `${source.getText(node.callee.object)}.contains(${source.getText(node.arguments[0])})`
: `${source.getText(node.arguments[0])}.test(${source.getText(node.callee.object)})`;

View File

@ -21,7 +21,7 @@ module.exports = {
context.report({
node,
message: "Prefer #id over [id=\"id\"]",
*fix(fixer) {
* fix(fixer) {
yield fixer.replaceText(node.arguments[0], arg.replaceAll(idRe, "#$2"));
}
});
@ -31,7 +31,7 @@ module.exports = {
context.report({
node,
message: "Prefer .class over [class=\"class\"]",
*fix(fixer) {
* fix(fixer) {
yield fixer.replaceText(node.arguments[0],
arg.replaceAll(classRe, (_, __, name) => `.${name.replaceAll(/\s+/g, '.')}`));
}

View File

@ -1,30 +0,0 @@
'use strict';
const translators = require('../translators').cache;
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'disallow invalid JSON in test cases',
category: 'Possible Errors',
},
},
create: function (context) {
return {
Program: function (_node) {
const translator = translators.get(context.getFilename());
if (!translator.testCases) return; // regular js or no test cases
if (translator.testCases.error) {
context.report({
message: `Could not parse testCases: ${translator.testCases.error.message}`,
loc: { start: { line: translator.testCases.error.line, column: translator.testCases.error.column } },
});
}
}
};
},
};

View File

@ -1,6 +1,22 @@
'use strict';
const translators = require('../translators').cache;
const { parsed, json } = require('../../processor').support;
function zip(arrays) {
let zipped = null;
for (const [key, array] of Object.entries(arrays)) {
if (!zipped) {
zipped = Array(array.length).fill(null).map((_, i) => ({ _: i }));
}
else if (array.length !== zipped.length) {
throw new Error(`Array length mismatch: ${key} has ${array.length} elements, but ${zipped.length} expected`);
}
for (const [i, value] of array.entries()) {
zipped[i][key] = value;
}
}
return zipped;
}
module.exports = {
meta: {
@ -15,132 +31,154 @@ module.exports = {
create: function (context) {
return {
Program: function (node) {
const translator = translators.get(context.getFilename());
const translator = parsed(context.getFilename());
if (!translator || !translator.testcases.text) return; // regular js source, or no testcases
const declaration = node.body.find(node => node.type === 'VariableDeclaration' && node.declarations.length === 1 && node.declarations[0].id.name === 'testCases');
const testCases = declaration
&& declaration.declarations[0].init
&& declaration.declarations[0].init.type === 'ArrayExpression'
? declaration.declarations[0].init.elements
: [];
if (declaration) {
const sourceCode = context.getSourceCode();
const token = sourceCode.getLastToken(node);
if (token.type === 'Punctuator' && token.value === ';') {
context.report({
message: 'testCases should not have trailing semicolon',
loc: declaration.loc.end,
});
}
const err = json.try(translator.testcases.text, { line: translator.testcases.start, position: 3 });
if (err) {
context.report({
message: `Could not parse testcases: ${err.message}`,
loc: { start: { line: err.line, column: err.column } },
});
return;
}
if (!translator.testCases || translator.testCases.error) return; // regular js or no test cases
const declaration = node.body.find(node => (
node.type === 'VariableDeclaration'
&& node.declarations.length === 1
&& node.declarations[0].id.name === 'testCases'
));
if (declaration.followingStatement) {
context.report({
node: declaration.followingStatement,
message: 'testCases should not have trailing code',
});
}
let caseNo = -1;
for (const testCase of translator.testCases.parsed) {
caseNo += 1;
const prefix = `test case${testCases[caseNo] ? '' : ' ' + (caseNo + 1)}`;
const loc = testCases[caseNo] ? testCases[caseNo].loc.start : { start: { line: translator.testCases.start, column: 1 } };
const nodes = declaration.declarations[0].init.elements;
if (!Array.isArray(nodes)) {
context.report({
node: declaration,
message: 'testCases must be an array',
});
return;
}
const sourceCode = context.getSourceCode();
const token = sourceCode.getLastToken(node);
if (token.type === 'Punctuator' && token.value === ';') {
context.report({
message: 'testCases should not have trailing semicolon',
loc: declaration.loc.end,
});
}
zip({
testCase: JSON.parse(translator.testcases.text),
node: nodes,
})
.forEach(({ testCase, node }) => {
if (!['web', 'import', 'search'].includes(testCase.type)) {
context.report({
message: `${prefix} has invalid type "${testCase.type}"`,
loc,
node,
message: `test case has invalid type "${testCase.type}"`,
});
continue;
return;
}
if (!(Array.isArray(testCase.items) || (testCase.type === 'web' && testCase.items === 'multiple'))) {
context.report({
message: `${prefix} of type "${testCase.type}" needs items`,
loc,
node,
message: `test case of type "${testCase.type}" needs items`,
});
}
if (testCase.type === 'web' && typeof testCase.url !== 'string') {
context.report({
message: `${prefix} of type "${testCase.type}" test needs url`,
loc,
node,
message: `test case of type "${testCase.type}" test needs url`,
});
}
if (['import', 'search'].includes(testCase.type) && !testCase.input) {
context.report({
message: `${prefix} of type "${testCase.type}" needs a string input`,
loc,
node,
message: `test case of type "${testCase.type}" needs a string input`,
});
}
else if (testCase.type === 'import' && typeof testCase.input !== 'string') {
context.report({
message: `${prefix} of type "${testCase.type}" needs input`,
loc,
node,
message: `test case of type "${testCase.type}" needs input`,
});
}
else if (testCase.type === 'search') {
// console.log(JSON.stringify(testCase.input))
const expected = ['DOI', 'ISBN', 'PMID', 'identifiers', 'contextObject', 'adsBibcode'];
if (!Object.keys(testCase.input).every(key => expected.includes(key))) {
let invalidKey = Object.keys(testCase.input).find(key => !expected.includes(key));
const expected = ['DOI', 'ISBN', 'PMID', 'arXiv', 'identifiers', 'contextObject', 'adsBibcode', 'ericNumber', 'openAlex'];
let keys;
if (Array.isArray(testCase.input)) {
keys = testCase.input.flatMap(Object.keys);
}
else {
keys = Object.keys(testCase.input);
}
if (!keys.every(key => expected.includes(key))) {
const invalidKey = keys.find(key => !expected.includes(key));
context.report({
message: `${prefix} of type "${testCase.type}" has invalid search term '${invalidKey}' - expected one of ${expected.join(', ')}`,
loc,
node,
message: `test case of type "${testCase.type}" has invalid search term '${invalidKey}' - expected one of ${expected.join(', ')}`,
});
}
}
if (Array.isArray(testCase.items)) {
let itemsNode = testCases[caseNo].properties
.find(prop => prop.key.type == 'Literal' && prop.key.value == 'items')
.value;
for (let [itemIndex, item] of testCase.items.entries()) {
let itemNode = itemsNode.elements[itemIndex];
let itemLoc = itemNode.loc;
zip({
item: testCase.items,
node: node.properties.find(prop => prop.key.type === 'Literal' && prop.key.value === 'items').value.elements,
})
.forEach(({ item, node }) => {
if (!Array.isArray(item.creators)) {
context.report({
message: 'creators should be an array',
loc: itemLoc,
node,
});
continue;
return;
}
for (let [creatorIndex, creator] of item.creators.entries()) {
let creatorLoc = itemNode.properties
.find(prop => prop.key.type == 'Literal' && prop.key.value == 'creators')
.value
.elements[creatorIndex]
.loc;
zip({
creator: item.creators,
node: node.properties.find(prop => prop.key.type === 'Literal' && prop.key.value === 'creators').value.elements,
})
.forEach(({ creator, node }) => {
if (creator.fieldMode !== undefined && creator.fieldMode !== 1) {
context.report({
node,
message: 'creator.fieldMode should be omitted or 1',
loc: creatorLoc,
});
}
else if (creator.fieldMode === 1 && (creator.firstName || !creator.lastName)) {
context.report({
node,
message: 'creator with fieldMode == 1 should have lastName and no firstName',
loc: creatorLoc,
});
}
else if (!creator.firstName && !creator.lastName) {
context.report({
node,
message: 'creator has no name',
loc: creatorLoc,
});
}
if (!creator.creatorType) {
context.report({
node,
message: 'creator has no creatorType',
loc: creatorLoc,
});
}
}
}
});
});
}
}
});
}
};
},

View File

@ -1,6 +1,6 @@
'use strict';
const translators = require('../translators');
const { parsed } = require('../../processor').support;
module.exports = {
meta: {
@ -14,19 +14,14 @@ module.exports = {
create: function (context) {
return {
Program: function (node) {
const header = translators.getHeaderFromAST(node);
if (!header.body) return; // if there's no file header, assume it's not a translator
Program: function (_node) {
const translator = parsed(context.getFilename());
if (!translator || !translator.FW) return; // regular js source, or no FW present
const sourceCode = context.getSourceCode();
for (const comment of sourceCode.getAllComments()) {
if (comment.value.match(/^\s*FW LINE [0-9]+:/)) {
context.report({
loc: comment.loc,
message: 'uses deprecated Translator Framework'
});
}
}
context.report({
loc: translator.FW.loc,
message: 'uses deprecated Translator Framework'
});
}
};
},

View File

@ -1,69 +0,0 @@
'use strict';
const fs = require('fs');
const path = require('path');
const uuid = require('uuid/v4');
const translators = require('../translators').cache;
const getHeaderFromAST = require('../translators').getHeaderFromAST;
const deleted = new Set(
fs.readFileSync(path.join(translators.repo, 'deleted.txt'), 'utf-8')
.split('\n')
.map(line => line.split(' ')[0])
.filter(id => id && id.indexOf('-') > 0)
);
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'disallows translatorID re-use',
category: 'Potential Problems',
},
fixable: 'code',
},
create: function (context) {
return {
Program: function (node) {
const filename = context.getFilename();
const header = getHeaderFromAST(node);
if (!header.declaration) return;
if (!header.properties.translatorID) {
context.report({
node: header.declaration,
message: 'Header has no translator ID',
});
}
else if (deleted.has(header.properties.translatorID.value)) {
context.report({
node: header.properties.translatorID,
message: 'Header re-uses translator ID of deleted translator',
fix: function (fixer) {
return fixer.replaceText(header.properties.translatorID, `"${uuid()}"`);
}
});
}
else if (!header.properties.translatorID.value) {
context.report({
node: header.properties.translatorID,
message: 'Header has empty translator ID',
});
}
else {
const conflict = translators.conflicts(filename, header.properties.translatorID.value);
if (conflict) {
const translator = translators.get(filename);
context.report({
node: header.properties.translatorID,
message: `Header re-uses translator ID of ${conflict.label}`,
fix: !translator.modified ? undefined : (fixer => fixer.replaceText(header.properties.translatorID, `"${uuid()}"`)),
});
}
}
}
};
},
};

View File

@ -1,72 +0,0 @@
'use strict';
const getHeaderFromAST = require('../translators').getHeaderFromAST;
function getFunction(programNode, name) {
return programNode.body.find((node) => {
if (node.type === 'FunctionDeclaration' && node.id && node.id.name === name) return true;
if (node.type === 'VariableDeclaration'
&& node.declarations.length === 1
&& node.declarations[0].id.name === name
&& node.declarations[0].init
&& node.declarations[0].init.type === 'FunctionExpression'
) return true;
return false;
});
}
module.exports = {
meta: {
type: 'problem',
docs: {
description: 'enforce translatorType against handler functions',
category: 'Possible Errors',
},
},
create: function (context) {
return {
Program: function (node) {
const header = getHeaderFromAST(node);
if (!header.declaration) return;
const type = {
import: 1,
export: 2,
web: 4,
search: 8
};
let translatorTypeNode = header.declaration;
let translatorType = 0;
let browserSupportNode = null;
for (const [p, v] of Object.entries(header.properties)) {
switch (p) {
case 'translatorType':
translatorTypeNode = v;
translatorType = v.value;
break;
case 'browserSupport':
browserSupportNode = v;
break;
}
}
if (browserSupportNode && !(translatorType & type.web)) context.report(browserSupportNode, `browserSupport set, but translatorType (${translatorType}) does not include web (${type.web})`);
for (const name of ['detectWeb', 'doWeb', 'detectImport', 'doImport', 'doExport']) {
const handler = getFunction(node, name);
const mode = name.replace(/^(detect|do)/, '').toLowerCase();
const bit = type[mode];
if (handler && !(translatorType & bit)) {
context.report(handler, `${name} present, but translatorType (${translatorType}) does not specify ${mode} (${bit})`);
}
if (!handler && (translatorType & bit)) {
context.report(translatorTypeNode, `translatorType specifies ${mode} (${bit}), but no ${name} present`);
}
}
}
};
},
};

View File

@ -1,249 +0,0 @@
'use strict';
const fs = require('fs');
const path = require('path');
const findRoot = require('find-root');
const childProcess = require('child_process');
const repo = path.resolve(findRoot(__dirname, dir => fs.existsSync(path.resolve(dir, '.git'))));
const metaDataRules = [
'zotero-translator/header-valid-json',
'zotero-translator/last-updated',
'zotero-translator/translator-id',
'zotero-translator/test-cases-valid-json',
'zotero-translator/test-cases',
'zotero-translator/translator-type',
'zotero-translator/prefer-index-of',
'zotero-translator/no-for-each',
'zotero-translator/not-executable',
'indent',
].join(', ');
const headerVar = '__eslintZoteroTranslatorHeader';
const headerPrefix = `/* eslint-disable no-unused-vars */ const ${headerVar} = /* eslint-disable */(/* eslint-enable ${metaDataRules} */`;
function jsonParseWithErrorInfo(raw, source) {
const target = { raw };
target.lines = target.raw.split('\n').length;
try {
target.parsed = JSON.parse(target.raw);
}
catch (err) {
const position = err.message.match(/at position ([0-9]+)/);
const at = position ? parseInt(position[1]) : 0;
target.error = {
message: err.message,
line: source.substring(0, source.indexOf(raw)).split('\n').length // start of raw JSON
+ target.raw.substring(0, at).split('\n').length, // line within raw JSON
column: at - target.raw.lastIndexOf('\n', at),
};
}
return target;
}
function escapeRE(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
const re = {
undecorated: new RegExp(
/^(\{[\s\S]+?\n\})/.source // the header
+ /(\n[\s\S]+?)/.source // the code
+ '(?:' // test cases
+ /(\/\*\* BEGIN TEST CASES \*\*\/)([\s\S]+?)/.source // var testCases =
+ /(\[[\s\S]+\])/.source // the test cases
+ /([\s\S]+)/.source // trailing stuff after the test cases
+ ')?$' // test cases are optional
),
decorated: new RegExp(
/^([\s\S]*?)/.source // anything the fixer might have placed at the top
+ escapeRE(headerPrefix) // all the eslint junk we injected
+ /(\{[\s\S]+\})/.source // the header
+ escapeRE(');/* eslint-enable */') // more eslint stuff we injected
+ /([\s\S]+?)/.source // the code
+ '(?:' // optional test cases
+ /(\/\*\* BEGIN TEST CASES \*\*\/)/.source
+ escapeRE('/* eslint-disable */') // more eslint stuff we injected
+ /([\s\S]+?)/.source // var testCases =
+ escapeRE(`/* eslint-enable ${metaDataRules} */`)
+ /([\s\S]+)/.source
+ ')?$'
),
};
const tfw = {
rules: [
'block-spacing',
'brace-style',
'comma-spacing',
'consistent-return',
'consistent-this',
'key-spacing',
'keyword-spacing',
'no-array-constructor',
'no-cond-assign',
'no-new-object',
'no-sequences',
'no-undef',
'no-unused-expressions',
'no-void',
'object-curly-spacing',
'semi',
'semi-spacing',
'space-before-blocks',
'space-before-function-paren',
'space-infix-ops',
]
};
tfw.disable = ` // eslint-disable-line ${tfw.rules.join(', ')}`;
tfw.disableRe = new RegExp('(\\n' + escapeRE('/* FW LINE 59:b820c6d */') + '[^\\n]+?)(' + escapeRE(tfw.disable) + ')?(\\n)');
function decorate(source) {
const decorated = {};
if (!source.startsWith('{')) return decorated;
let m = source.match(re.undecorated);
if (!m) throw new Error('no header');
let [, header, code, testCasesPrefix, testCasesVar, testCases, testCasesPostfix] = m;
code = code.replace(tfw.disableRe, `$1${tfw.disable}$3`);
// decorate header
decorated.header = jsonParseWithErrorInfo(header, source);
decorated.source = headerPrefix
+ header // the JSON
+ ');/* eslint-enable */'
+ code; // the actual code
if (testCasesPrefix) {
decorated.testCases = jsonParseWithErrorInfo(testCases, source);
decorated.source += testCasesPrefix // the prefix
+ '/* eslint-disable */' // disable all the rules
+ testCasesVar
+ `/* eslint-enable ${metaDataRules} */` // enable JSON rules
+ testCases
+ testCasesPostfix;
}
return decorated;
}
function tryFormatJSON(raw) {
try {
return JSON.stringify(JSON.parse(raw), null, '\t');
}
catch (_err) {
return raw;
}
}
function strip(source) {
const m = source.match(re.decorated);
if (!m) throw new Error('not decorated');
let [, prefix, header, code, testCasesPrefix, testCasesVar, testCases] = m;
code = code.replace(tfw.disableRe, '$1$3');
return tryFormatJSON(header) + (prefix ? '\n\n' + prefix.replace(/^\s*/, '') : '') + code + (testCasesPrefix || '') + tryFormatJSON(testCasesVar || '') + (testCases || '');
}
function exec(cmd) {
return childProcess.execSync(cmd, { cwd: repo, encoding: 'utf8' });
}
class Cache {
constructor() {
this.decorated = {};
this.repo = path.resolve(repo);
for (const translator of fs.readdirSync(this.repo)) {
if (!translator.endsWith('.js')) continue;
this.decorated[path.basename(translator)] = decorate(fs.readFileSync(path.join(repo, translator), 'utf-8'));
}
const branch = exec('git rev-parse --abbrev-ref HEAD').trim();
const hasUpstream = exec('git remote -v').split('\n')
.map(line => line.trim())
.includes('upstream\thttps://github.com/zotero/translators.git');
// branch to compare lastUpdated against -- assume that if have upstream/master, you want to compare against that
const master = hasUpstream ? 'upstream/master' : 'master';
this.lastUpdated = {};
if (branch !== master) {
// `git diff --name-status ${master}` will fetch the names of the files that have changed against `${master}`
for (const file of exec(`git diff --name-status ${master}`).split('\n')) {
const m = file.match(/^M\t([^/]+\.js)$/); // js files that are modified but don't have a / in their path to pick out files in the root
if (m && this.decorated[m[1]]) this.decorated[m[1]].modified = true;
}
/*
We do a `git grep '"lastUpdated"' ${master} *.js` to get the
`lastUpdated` values from the `${master}` branch. For files that are
deemed changed, the lastUpdated is remembered (so the presence of lastUpdated implies modified).
This info is used in the 'last-updated' rule.
*/
for (const lu of exec(`git grep '"lastUpdated"' ${master} *.js`).split('\n')) {
const m = lu.match(/^[a-z/]+:([^:]+):\s*"lastUpdated"\s*:\s*"([-0-9: ]+)"/);
if (!m) continue;
const translator = m[1];
if (this.decorated[translator] && this.decorated[translator].modified) this.decorated[translator].lastUpdated = m[2];
}
}
}
get(filename) {
const basename = path.basename(filename);
// don't load stuff outside the root dir
if (!this.decorated[basename] && path.dirname(path.resolve(filename)) !== this.repo) this.decorated[basename] = {};
return this.decorated[basename];
}
conflicts(filename, translatorID) {
filename = path.basename(filename);
for (const [otherFilename, otherHeader] of Object.entries(this.decorated)) {
if (otherFilename !== filename && otherHeader.translatorID === translatorID) {
return otherHeader.parsed;
}
}
return false;
}
}
function getHeaderFromAST(programNode) {
const declaration = programNode.body[0];
if (!declaration) return {};
if (declaration.type !== 'VariableDeclaration' || declaration.declarations.length !== 1 || declaration.declarations[0].id.name !== headerVar) return {};
const body = declaration.declarations[0].init;
if (!body || body.type !== 'ObjectExpression') return {};
const properties = {};
for (const property of body.properties) {
properties[property.key.value] = property.value;
}
return { declaration, body, properties, followingStatement: programNode.body[1] };
}
module.exports = {
decorate,
strip,
cache: new Cache(),
getHeaderFromAST,
};
if (require.main === module) {
const orig = fs.readFileSync(path.join(__dirname, '../../../Amazon.js'), 'utf-8');
const decorated = decorate(orig);
const stripped = strip(decorated.source);
console.log(stripped === orig); // eslint-disable-line no-console
}

View File

@ -0,0 +1,257 @@
'use strict';
const espree = require('espree');
const clarinet = require('clarinet');
const findRoot = require('find-root');
const path = require('path');
const fs = require('fs');
const childProcess = require('child_process');
let repo;
try {
repo = path.resolve(findRoot(__dirname, dir => fs.existsSync(path.join(dir, '.git'))));
}
catch (e) {
console.error('ERROR: Translators can only be linted inside a clone of the zotero/translators repo (not a ZIP downloaded from GitHub)');
console.error(' git clone https://github.com/zotero/translators.git');
process.exit(1); // eslint-disable-line no-process-exit
}
function exec(cmd) {
return childProcess.execSync(cmd, { cwd: repo, encoding: 'utf8' });
}
// have to pre-load everything to test for conflicting headers
const cache = new Map();
function updateCache(text, filename) {
if (text[0] !== '{') return;
if (cache.has(filename) && cache.get(filename).text === text) {
// No change - no need to re-parse
return;
}
// detect header
const prefix = `const ZoteroTranslator${Date.now()} = `;
const decorated = `${prefix}${text}`;
let ast;
try {
ast = espree.parse(decorated, { comment: true, loc: true, ecmaVersion: 2023 });
}
catch (err) {
console.log(filename, err.message);
process.exit(1); // eslint-disable-line no-process-exit
}
const header = ((ast.body[0] || {}).declarations[0] || {}).init;
const testcases = ast.body
.filter((node, i) => i === ast.body.length - 1)
.filter(node => node.type === 'VariableDeclaration' && node.declarations.length === 1).map(node => node.declarations[0])
.filter(node => node.type === 'VariableDeclarator' && node.id.type === 'Identifier' && node.id.name === 'testCases')
.map(node => node.init)[0];
const extract = (node) => {
if (!node) return {};
return {
start: node.loc.start.line,
end: node.loc.end.line,
text: decorated.substring(node.start, node.end),
};
};
const entry = {
text,
header: extract(header),
testcases: extract(testcases),
FW: ast.comments.find(comment => comment.type === 'Block' && comment.value.trim === 'FW LINE 59:b820c6d')
};
try {
entry.header.fields = JSON.parse(entry.header.text);
}
catch (err) {
// ignore
}
cache.set(filename, entry);
}
for (let filename of fs.readdirSync(repo).sort()) {
if (!filename.endsWith('.js')) continue;
filename = path.join(repo, filename);
const text = fs.readFileSync(filename, 'utf-8');
updateCache(text, filename);
}
for (const lu of exec(`git grep '"lastUpdated"' HEAD~1`).split('\n')) {
const m = lu.match(/^HEAD~1:([^:]+):\s*"lastUpdated"\s*:\s*"([-0-9: ]+)"/);
if (!m) continue;
const [, translator, lastUpdated] = m;
const filename = path.join(repo, translator);
if (cache.has(filename)) cache.get(filename).lastUpdated = lastUpdated;
}
function tryJSON(json, offset) {
const parser = clarinet.parser();
let error;
const message = e => ({
message: (e.message || '').split('\n', 1)[0],
line: parser.line + offset.line,
column: parser.column,
position: parser.position + offset.position,
});
// trigger the parse error
parser.onerror = function (e) {
error = message(e);
parser.close();
};
try {
parser.write(json).close();
}
catch (e) {
return error || message(e);
}
return error;
}
function JSONTokens(json, offset) {
const parser = clarinet.parser();
const tokens = [];
parser.onvalue = function (v) {
tokens.push({ type: 'value', value: v, line: parser.line + offset.line, column: parser.column, position: parser.position + offset.position });
};
parser.onopenobject = function (key) {
tokens.push({ type: 'object-open', key, line: parser.line + offset.line, column: parser.column, position: parser.position + offset.position });
};
parser.onkey = function (key) {
tokens.push({ type: 'key', key, line: parser.line + offset.line, column: parser.column, position: parser.position + offset.position });
};
parser.oncloseobject = function () {
tokens.push({ type: 'object-close', line: parser.line + offset.line, column: parser.column, position: parser.position + offset.position });
};
parser.onopenarray = function () {
tokens.push({ type: 'array-open', line: parser.line + offset.line, column: parser.column, position: parser.position + offset.position });
};
parser.onclosearray = function () {
tokens.push({ type: 'array-close', line: parser.line + offset.line, column: parser.column, position: parser.position + offset.position });
};
parser.write(json).close();
return tokens;
}
function header(program) {
if (!program) return null;
if (program.type !== 'Program') return null;
if (program.body.length === 0) return null;
if (program.body[0].type !== 'ExpressionStatement') return null;
if (program.body[0].expression.type !== 'ObjectExpression') return null;
return program.body[0].expression;
}
function conflict(filename) {
const translatorID = (((cache.get(filename) || {}).header || {}).fields || {}).translatorID;
if (!translatorID) return null;
for (const [other, header] of cache.entries()) {
if (other !== filename && header.translatorID === translatorID) {
return header.fields;
}
}
return null;
}
const junk = new RegExp(`${path.sep}0_`.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&') + '.*');
module.exports = {
support: {
repo,
parsed: filename => cache.get(filename.replace(junk, '')),
header,
IDconflict: conflict,
json: {
try: tryJSON,
tokens: JSONTokens,
}
},
supportsAutofix: true,
preprocess: function (text, filename) {
// We might be running on an in-memory version of the translator newer
// than what we read from disk earlier, so update the cache
updateCache(text, filename);
const parsed = cache.get(filename);
if (text[0] !== '{' || !parsed) return [{ text, filename }];
if (parsed.header.text) {
return [{ text: `(${text.slice(0, parsed.header.text.length)});${text.slice(parsed.header.text.length)}`, filename }];
}
else {
return [{ text, filename }];
}
},
postprocess: function (messages, filename) {
messages = [].concat(...messages);
const parsed = cache.get(filename);
if (parsed) {
const header = parsed.header;
if (header.text) {
messages = messages.filter((m) => {
if (!m.ruleId) return true;
if (m.ruleId.startsWith('zotero-translator/header') && m.line > header.end) return false;
switch (m.ruleId) {
case 'no-unused-expressions':
return m.line !== 1;
case 'quote-props':
return m.line > header.end;
default:
}
return true;
});
const adjust = (p) => {
if (p > header.text.length) return p - 3; // remove '(' and ');'
if (p > 1) return p - 1; // remove '('
return p;
};
for (const m of messages) {
if (m.fix) m.fix.range = m.fix.range.map(adjust);
if (m.suggestions) {
for (const s of m.suggestions) {
if (s.fix) s.fix.range = s.fix.range.map(adjust);
}
}
}
}
const testcases = parsed.testcases;
if (testcases && testcases.text) {
messages = messages.filter((m) => {
if (!m.ruleId) return true;
if (m.ruleId.startsWith('zotero-translator/test-cases') && m.line < testcases.start) return false;
switch (m.ruleId) {
case 'semi':
case 'quote-props':
return m.line < testcases.start || m.line > testcases.end;
case 'lines-around-comment':
return m.line !== testcases.end + 1;
}
return true;
});
}
}
return messages;
},
};

44
.ci/helper.sh Normal file → Executable file
View File

@ -19,41 +19,11 @@ get_translator_id() {
}
get_translators_to_check() {
# If a PR branch has no conflicts with the master then git
# creates a custom merge commit where it merges PR into master.
# Travis-CI tests on that commit instead of the HEAD of the PR branch.
#
# Thus below we first determine if HEAD is a merge commit by checking how
# many parents the current HEAD has. If number of parents > 1, then it's a merge commit
# in which case we need to diff translator names between HEAD^2 and PR split commit from master.
# The above will generally only be the case in CI or if using a custom PR pulling script which
# pulls the merge PR commit instead of just the PR branch.
#
# If the HEAD commit is not a merge then we diff HEAD with PR split commit from master. This is the case
# when running from a local development PR branch
#
# The branching point hash retrieval logic is based on https://stackoverflow.com/a/12185115/3199106
TRANSLATORS_TO_CHECK=""
# Push to master
if [ "${GITHUB_REF:-}" = "refs/heads/master" ]; then
before_commit=$(jq -r '.before' $(echo $GITHUB_EVENT_PATH))
TRANSLATORS_TO_CHECK=$(git diff $before_commit --name-only | { grep -e "^[^/]*.js$" || true; })
# Pull request
else
# Gets parent commits. Either one or two hashes
parent_commits=($(git show --no-patch --format="%P" HEAD))
# Size of $parent_commits array
num_parent_commits=${#parent_commits[@]}
if [ $num_parent_commits -gt 1 ]; then
first_parent=$(git rev-list --first-parent ^master HEAD^2 | tail -n1)
branch_point=$(git rev-list "$first_parent^^!")
TRANSLATORS_TO_CHECK=$(git diff HEAD^2 $branch_point --name-only | { grep -e "^[^/]*.js$" || true; })
else
first_parent=$(git rev-list --first-parent ^master HEAD | tail -n1)
branch_point=$(git rev-list "$first_parent^^!")
TRANSLATORS_TO_CHECK=$(git diff $branch_point --name-only | { grep -e "^[^/]*.js$" || true; })
fi
fi
# Get the last commit on the target branch before this branch diverged
# Fall back to translators changed on the last commit in case there's no GITHUB_BASE_REF
# and no upstream/master (CI runs on push)
local fork_point=$(git merge-base --fork-point ${GITHUB_BASE_REF:-upstream/master} HEAD 2>/dev/null || echo HEAD~)
# Get translator scripts changed between that commit and now, excluding deleted files
local all_translator_scripts="$(git rev-parse --show-toplevel)"/*.js
git diff --name-only --diff-filter=d $fork_point -- $all_translator_scripts
}

View File

@ -5,5 +5,8 @@ dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
. "$dir/helper.sh"
get_translators_to_check
npm run lint -- "$TRANSLATORS_TO_CHECK"
translators_to_check=$(get_translators_to_check)
if [ -n "$translators_to_check" ]; then
# No `xargs -d` support in macOS, so workaround with `tr`
echo "$translators_to_check" | tr '\n' '\0' | xargs -0 npm run lint --
fi

View File

@ -0,0 +1,164 @@
import chalk from 'chalk';
import path from 'path';
import process from 'process';
import { chromium } from 'playwright';
import * as translatorServer from './translator-server.mjs';
const chromeExtensionDir = path.join(import.meta.dirname, 'connectors', 'build', 'manifestv3');
const KEEP_BROWSER_OPEN = 'KEEP_BROWSER_OPEN' in process.env;
const CI = 'CI' in process.env;
const ZOTERO_CONNECTOR_EXTENSION_ID = 'ekhagklcjbdpajgpjgmbionohlpdbjgc';
async function getTranslatorsToTest() {
const translatorFilenames = process.argv[2].split('\n').filter(filename => filename.trim().length > 0);
let changedTranslatorIDs = [];
let toTestTranslatorIDs = new Set();
let toTestTranslatorNames = new Set();
for (const translatorFilename of translatorFilenames) {
let translator = translatorServer.filenameToTranslator[translatorFilename];
if (!translator) {
console.error(chalk.yellow(`Translator '${translatorFilename}' not found`));
continue;
}
else if (translator.metadata === null) {
console.error(chalk.red(`
Translator '${translatorFilename}' is not correctly formatted.
Please use Scaffold (Tools Translator Editor) to create translators, and test
that your translator works before opening a PR.
AI tools may help with drafting code to add to your translator, but you should
never use an AI tool to generate its overall structure without using Scaffold
first. LLMs have very little Zotero translator code in their training sets and
generally fail to generate translator code with a valid layout (or even a real
UUID).
`.trim()));
continue;
}
let metadata = translator.metadata;
changedTranslatorIDs.push(metadata.translatorID);
toTestTranslatorIDs.add(metadata.translatorID);
toTestTranslatorNames.add(metadata.label);
}
// Find all translators that use the changed translators and add them to list/check them too
let changedTranslatorIDRe = new RegExp(changedTranslatorIDs.join('|'));
let tooManyTranslators = false;
for (let translator of translatorServer.translators) {
if (!changedTranslatorIDRe.test(translator.content)) continue;
toTestTranslatorIDs.add(translator.metadata.translatorID);
toTestTranslatorNames.add(translator.metadata.label);
if (toTestTranslatorIDs.size >= 10) {
tooManyTranslators = true;
break;
}
}
if (tooManyTranslators) {
console.log(
`Over 10 translators need to be tested, but this will take too long
and timeout the CI environment. Truncating to 10.
This is likely to happen when changing Embedded Metadata which is
loaded by pretty much every other translator or when a PR contains
a lot of changed translators.
You may want to consider adding '[ci skip]' in the commit message.`
)
}
console.log(`Will run tests for translators ${JSON.stringify(Array.from(toTestTranslatorNames))}`);
return Array.from(toTestTranslatorIDs);
}
function report(results) {
var allPassed = true;
for (let translatorID in results) {
let translatorResults = results[translatorID];
console.log(chalk.bold(chalk.bgWhite(chalk.black(`Running tests for ${translatorID}: ${translatorResults.label}`))));
let padding = 2;
let output = translatorResults.message.split("\n");
for (let line of output) {
if (/^Running \d+ tests? for/.test(line)) {
console.log(" ".repeat(padding - 1) + chalk.bgCyan(chalk.black(line)));
}
else if (line.match(/^-/)) {
console.log(chalk.red("-" + " ".repeat(padding) + line.substr(1)));
}
else if (line.match(/^\+/)) {
console.log(chalk.green("+" + " ".repeat(padding) + line.substr(1)));
}
else if (line.match(/^Test \d+: succeeded/)) {
console.log(" ".repeat(padding) + chalk.bgGreen(line));
}
else if (line.match(/^Test \d+: failed/)) {
console.log(" ".repeat(padding) + chalk.bgRed(line));
allPassed = false;
}
else {
console.log(" ".repeat(padding) + line);
}
}
console.log("\n");
}
return allPassed
}
var allPassed = false;
let context;
try {
await translatorServer.serve();
context = await chromium.launchPersistentContext('/tmp/chromium-user-data-dir', {
channel: 'chromium',
headless: CI,
args: [
`--disable-extensions-except=${chromeExtensionDir}`,
`--load-extension=${chromeExtensionDir}`
]
});
console.log(`Browser version: ${context.browser().version()}`);
const translatorsToTest = await getTranslatorsToTest();
await new Promise(resolve => setTimeout(resolve, 500));
let testUrl = `chrome-extension://${ZOTERO_CONNECTOR_EXTENSION_ID}/tools/testTranslators/testTranslators.html#translators=${translatorsToTest.join(',')}`;
let page = await context.newPage();
await page.goto(testUrl);
for (let i = 0; i <= 3; i++) {
let title = (await page.title()).trim();
if (title === 'Zotero Translator Tester') {
break;
}
if (i === 3) {
console.error('Failed to load Translator Tester extension page');
process.exit(2);
}
await new Promise(resolve => setTimeout(resolve, 100));
}
await page.locator('#translator-tests-complete')
.waitFor({
state: 'attached',
timeout: 5 * 60 * 1000,
});
let testResults = await page.evaluate(() => window.seleniumOutput);
allPassed = report(testResults);
}
catch (e) {
console.error(e);
}
finally {
if (!KEEP_BROWSER_OPEN) {
await context.close();
}
translatorServer.stopServing();
if (allPassed) {
console.log(chalk.green("All translator tests passed"));
} else {
console.log(chalk.red("Some translator tests failed"));
}
process.exit(allPassed ? 0 : 1);
}

View File

@ -1,6 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
echo "::group::Setup"
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
ROOT_DIR="$( dirname "$DIR" )"
@ -28,11 +29,11 @@ else
fi
export ZOTERO_REPOSITORY_URL="http://localhost:8085/"
export CHROME_EXTENSION_KEY="MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDllBS5q+Z9T9tPgYwRN+/8T9wzyjo9tRo03Wy8zP2DQ5Iy+3q0Tjq2vKXGiMCxC/ZVuEMC68Ekv+jNT43VxPbEXI4dzpK1GMBqPJpAcEOB8B1ROBouQMbGGTG7fOdQVlmpdTTPVndVwysJ02CrDMn96IG2ytOq2PO7GR2xleCudQIDAQAB"
./build.sh -p b -d
cd ..
npm explore chromedriver -- npm run install --detect_chromedriver_version
echo "::endgroup::"
get_translators_to_check
./selenium-test.js "$TRANSLATORS_TO_CHECK"
node browser-test.mjs "$(get_translators_to_check)"

View File

@ -1,150 +0,0 @@
#!/usr/bin/env node
const path = require('path');
const process = require('process');
const selenium = require('selenium-webdriver');
const until = require('selenium-webdriver/lib/until');
const chalk = require('chalk');
const translatorServer = require('./translator-server');
const chromeExtensionDir = path.join(__dirname, 'connectors', 'build', 'chrome');
const KEEP_BROWSER_OPEN = 'KEEP_BROWSER_OPEN' in process.env;
async function getTranslatorsToTest() {
const translatorFilenames = process.argv[2].split('\n').filter(filename => filename.trim().length > 0);
let changedTranslatorIDs = [];
let toTestTranslatorIDs = new Set();
let toTestTranslatorNames = new Set();
for (const translatorFilename of translatorFilenames) {
let translatorInfo = translatorServer.filenameToTranslator[translatorFilename].metadata;
changedTranslatorIDs.push(translatorInfo.translatorID);
toTestTranslatorIDs.add(translatorInfo.translatorID);
toTestTranslatorNames.add(translatorInfo.label);
}
// Find all translators that use the changed translators and add them to list/check them too
let tooManyTranslators = false;
for (let translator of translatorServer.translators) {
for (let translatorID of changedTranslatorIDs) {
if (!translator.content.includes(translatorID)) continue;
toTestTranslatorIDs.add(translator.metadata.translatorID);
toTestTranslatorNames.add(translator.metadata.label);
if (toTestTranslatorIDs.size >= 10) {
tooManyTranslators = true;
break;
}
}
if (tooManyTranslators) break;
}
if (tooManyTranslators) {
console.log(
`Over 10 translators need to be tested, but this will take too long
and timeout the CI environment. Truncating to 10.
This is likely to happen when changing Embedded Metadata which is
loaded by pretty much every other translator or when a PR contains
a lot of changed translators.
You may want to consider adding '[ci skip]' in the commit message.`
)
}
console.log(`Will run tests for translators ${JSON.stringify(Array.from(toTestTranslatorNames))}`);
return Array.from(toTestTranslatorIDs);
}
function report(results) {
var allPassed = true;
for (let translatorID in results) {
let translatorResults = results[translatorID];
console.log(chalk.bold(chalk.bgWhite(chalk.black(`Beginning Tests for ${translatorID}: ${translatorResults.label}`))));
let padding = 2;
let output = translatorResults.message.split("\n");
for (let line of output) {
if (line.match(/^TranslatorTester: Running [^T]*Test [0-9]*$/) ||
line.match(/^TranslatorTester: Running [0-9]* tests for .*$/)) {
console.log(" ".repeat(padding-1) + chalk.bgCyan(chalk.black(line)));
}
else if (line.match(/^-/)) {
console.log(chalk.red("-" + " ".repeat(padding) + line.substr(1)));
}
else if (line.match(/^\+/)) {
console.log(chalk.green("+" + " ".repeat(padding) + line.substr(1)));
}
else if (line.match(/^TranslatorTester: [^T]*Test [0-9]*: succeeded/)) {
console.log(" ".repeat(padding) + chalk.bgGreen(line));
}
else if (line.match(/^TranslatorTester: [^T]*Test [0-9]*: unknown/)) {
console.log(" ".repeat(padding) + chalk.bgYellow(chalk.black(line)));
allPassed = false;
}
else if (line.match(/^TranslatorTester: [^T]*Test [0-9]*: failed/)) {
console.log(" ".repeat(padding) + chalk.bgRed(line));
allPassed = false;
}
else {
console.log(" ".repeat(padding) + line);
}
}
console.log("\n");
}
return allPassed
}
var allPassed = false;
(async function() {
let driver;
try {
translatorServer.serve();
require('chromedriver');
let chrome = require('selenium-webdriver/chrome');
let options = new chrome.Options();
options.addArguments(`load-extension=${chromeExtensionDir}`);
if ('BROWSER_EXECUTABLE' in process.env) {
options.setChromeBinaryPath(process.env['BROWSER_EXECUTABLE']);
}
driver = new selenium.Builder()
.forBrowser('chrome')
.setChromeOptions(options)
.build();
// No API to retrieve extension ID. Hacks, sigh.
await driver.get("chrome://system/");
await driver.wait(until.elementLocated({id: 'btn-extensions-value'}), 60*1000);
// Chrome 89+ has the extension list expanded by default
try {
let extBtn = await driver.findElement({css: '#btn-extensions-value'});
await extBtn.click();
} catch (e) {}
let contentElem = await driver.findElement({css: '#content'});
let text = await contentElem.getText();
let extId = text.match(/([^\s]*) : Zotero Connector/)[1];
// We got the extension ID and test URL, let's test
const translatorsToTest = await getTranslatorsToTest();
let testUrl = `chrome-extension://${extId}/tools/testTranslators/testTranslators.html#translators=${translatorsToTest.join(',')}`;
await new Promise((resolve) => setTimeout(() => resolve(driver.get(testUrl)), 500));
await driver.wait(until.elementLocated({id: 'translator-tests-complete'}), 30*60*1000);
testResults = await driver.executeScript('return window.seleniumOutput');
allPassed = report(testResults);
}
catch (e) {
console.error(e);
}
finally {
if (!KEEP_BROWSER_OPEN) {
await driver.quit();
}
translatorServer.stopServing();
if (allPassed) {
console.log(chalk.green("All translator tests passed"));
} else {
console.log(chalk.red("Some translator tests failed"));
}
process.exit(allPassed ? 0 : 1);
}
})();

View File

@ -1,6 +1,6 @@
const http = require("http");
const fs = require('fs').promises;
const path = require('path');
import http from 'http';
import { promises as fs } from 'fs';
import path from 'path';
const host = 'localhost';
const port = 8085;
@ -9,7 +9,7 @@ var server;
var translators = [];
var idToTranslator = {};
var filenameToTranslator = {};
const rootPath = path.join(__dirname, '../..');
const rootPath = path.join(import.meta.dirname, '../..');
const infoRe = /^\s*{[\S\s]*?}\s*?[\r\n]/;
async function loadTranslators() {
@ -19,11 +19,17 @@ async function loadTranslators() {
const fullPath = path.join(rootPath, file);
if (!fullPath.endsWith('.js') || !(await fs.stat(fullPath)).isFile()) continue;
let content = await fs.readFile(fullPath);
let translatorInfo = JSON.parse(infoRe.exec(content)[0]);
let translator = { metadata: translatorInfo, content };
let translator;
try {
let translatorInfo = JSON.parse(infoRe.exec(content)[0]);
translator = { metadata: translatorInfo, content };
idToTranslator[translatorInfo.translatorID] = translator;
}
catch (e) {
translator = { metadata: null, content };
}
translators.push(translator);
filenameToTranslator[file] = translator;
idToTranslator[translatorInfo.translatorID] = translator;
}
}
}
@ -56,17 +62,16 @@ async function requestListener(req, res) {
res.end();
}
module.exports = {
serve: async function() {
await loadTranslators();
server = http.createServer(requestListener);
server.listen(port, host, () => {
console.log(`Translator server is running on http://${host}:${port}`);
});
},
stopServing: function() {
server.close();
},
filenameToTranslator,
translators
};
async function serve() {
await loadTranslators();
server = http.createServer(requestListener);
server.listen(port, host, () => {
console.log(`Translator server is running on http://${host}:${port}`);
});
}
function stopServing() {
server.close();
}
export { serve, stopServing, filenameToTranslator, translators };

View File

@ -1,2 +0,0 @@
#!/bin/sh
/usr/bin/xvfb-run /usr/bin/google-chrome $@

75
.ci/updateTypes.mjs Executable file
View File

@ -0,0 +1,75 @@
#!/usr/bin/env node
import { readFile, writeFile } from 'fs/promises';
const INDEX_D_TS_URL = new URL('../index.d.ts', import.meta.url);
const SCHEMA_JSON_URL = new URL('../../zotero-client/resource/schema/global/schema.json', import.meta.url);
const BEGIN_MARKER = '\t/* *** BEGIN GENERATED TYPES *** */';
const END_MARKER = '\t/* *** END GENERATED TYPES *** */';
async function updateIndexDTS() {
let indexDTS = await readFile(INDEX_D_TS_URL, { encoding: 'utf8' });
let schema = JSON.parse(await readFile(SCHEMA_JSON_URL));
let typeItemTypes = '\ttype ItemTypes = {';
let itemTypeTypes = '';
let creatorTypes = new Set();
for (let typeSchema of schema.itemTypes) {
let itemType = typeSchema.itemType;
if (['annotation', 'attachment', 'note'].includes(itemType)) {
continue;
}
let itemTypeUppercase = itemType[0].toUpperCase() + itemType.substring(1) + 'Item';
if (itemTypeUppercase == 'TvBroadcastItem') {
itemTypeUppercase = 'TVBroadcastItem';
}
typeItemTypes += `\n\t\t"${itemType}": ${itemTypeUppercase},`;
itemTypeTypes += `\n\n\ttype ${itemTypeUppercase} = {`;
itemTypeTypes += `\n\t\titemType: "${itemType}";`;
for (let { field } of typeSchema.fields) {
itemTypeTypes += `\n\t\t${field}?: string;`
}
let creatorTypesJoined = typeSchema.creatorTypes.map(typeSchema => '"' + typeSchema.creatorType + '"').join(' | ');
itemTypeTypes += `\n\n\t\tcreators: Creator<${creatorTypesJoined}>[];`;
itemTypeTypes += '\n\t\tattachments: Attachment[];';
itemTypeTypes += '\n\t\ttags: Tag[];';
itemTypeTypes += '\n\t\tnotes: Note[];';
itemTypeTypes += '\n\t\tseeAlso: string[];';
itemTypeTypes += '\n\t\tcomplete(): void;';
itemTypeTypes += '\n\n\t\t[key: string]: string;';
itemTypeTypes += '\n\t};';
for (let { creatorType } of typeSchema.creatorTypes) {
creatorTypes.add(creatorType);
}
}
typeItemTypes += '\n\t};'
let typeCreatorType = '\n\ttype CreatorType =';
for (let creatorType of Array.from(creatorTypes).sort()) {
typeCreatorType += `\n\t\t| "${creatorType}"`;
}
typeCreatorType += ';';
let beginIdx = indexDTS.indexOf(BEGIN_MARKER);
let endIdx = indexDTS.indexOf(END_MARKER);
if (beginIdx == -1 || endIdx == -1) {
throw new Error('Could not find generated types section in index.d.ts');
}
indexDTS = indexDTS.substring(0, beginIdx) + BEGIN_MARKER + '\n'
+ typeItemTypes
+ itemTypeTypes
+ '\n' + typeCreatorType
+ '\n'
+ indexDTS.substring(endIdx);
await writeFile(INDEX_D_TS_URL, indexDTS);
}
updateIndexDTS();

View File

@ -1,11 +1,14 @@
{
"env": {
"browser": true,
"es2018": true
"es2021": true
},
"extends": [
"@zotero"
],
"parserOptions": {
"ecmaVersion": "2023"
},
"globals": {
"Zotero": "readonly",
"Z": "readonly",
@ -23,23 +26,35 @@
"error",
{
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^detectWeb$|^doWeb$|^detectImport$|^doImport$|^doExport$|^detectSearch$|^doSearch$|^exports$"
"varsIgnorePattern": "^testCases$|^detectWeb$|^doWeb$|^detectImport$|^doImport$|^doExport$|^detectSearch$|^doSearch$|^exports$"
}
],
"no-redeclare": ["error", {"builtinGlobals": true}],
"linebreak-style": ["error", "unix"],
"lines-around-comment": [
"error",
{
"ignorePattern": "END TEST CASES"
}
],
"no-restricted-globals": ["error", {
"name": "document",
"message": "Use doc instead."
}],
"zotero-translator/not-executable": "error",
"zotero-translator/header-valid-json": "error",
"zotero-translator/translator-id": "error",
"zotero-translator/last-updated": "warn",
"zotero-translator/translator-type": "warn",
"zotero-translator/header-translator-id": "error",
"zotero-translator/header-last-updated": "warn",
"zotero-translator/header-translator-type": "warn",
"zotero-translator/no-for-each": "warn",
"zotero-translator/prefer-index-of": "warn",
"zotero-translator/robust-query-selector": "warn",
"zotero-translator/test-cases-valid-json": "error",
"zotero-translator/test-cases": "error",
"zotero-translator/translator-framework": "warn",
@ -50,5 +65,6 @@
},
"plugins": [
"zotero-translator"
]
],
"processor": "zotero-translator/translator"
}

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: "All other translator issues and requests: Post to the Zotero Forums"
url: https://forums.zotero.org/post/discussion
about: Please do not use GitHub Issues to report problems saving webpages or to request a new translator. Post to the Zotero Forums. Zotero developers will create issues as necessary in the relevant repositories.

View File

@ -1,6 +1,11 @@
---
name: Report a confirmed bug with technical details
about: If youre sure youve identified a bug in a specific Zotero translator and can provide technical details, you can open an issue here.
---
**READ THIS BEFORE CREATING AN ISSUE**
Zotero generally does not use GitHub Issues for bug reports or feature requests regarding Zotero software.
Zotero generally does not use GitHub Issues for bug reports or feature requests in Zotero software.
If youre sure youve identified a bug in a specific Zotero translator, youre welcome to create an issue here.

View File

@ -6,7 +6,7 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
with:
submodules: true
@ -19,13 +19,8 @@ jobs:
- name: Install Node
uses: actions/setup-node@v2
with:
node-version: 17
# Local via act
- name: Install packages for act
if: env.ACT == 'true'
run: apt update && apt install -y xvfb git rsync
node-version: 22
- name: Get current connector hash
id: get-connector-hash
run: |
@ -34,21 +29,19 @@ jobs:
- name: Cache connector code
id: connector-cache
uses: actions/cache@v2
uses: actions/cache@v4
with:
path: .ci/pull-request-check/connectors
key: connectors-${{ hashFiles('.ci/pull-request-check/check-pull-request.sh') }}-${{ steps.get-connector-hash.outputs.hash }}
- name: Install node packages
run: npm ci
#- name: Debugging with tmate
# uses: mxschmitt/action-tmate@v3.1
- name: Install Chromium
run: npx playwright install chromium
- name: Test pull request
if: github.event_name == 'pull_request'
env:
BROWSER_EXECUTABLE: /home/runner/work/translators/translators/.ci/pull-request-check/xvfb-run-chrome
run: ./check-pull-request.sh
working-directory: .ci/pull-request-check

View File

@ -9,7 +9,7 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2023-03-16 04:39:27"
"lastUpdated": "2024-07-30 05:19:59"
}
/*
@ -167,7 +167,7 @@ function scrape(doc) {
item.abstractNote = ZU.trimInternal(abstract);
}
let pdfElement = doc.querySelector('a[title=PDF]');
let pdfElement = doc.querySelector('a[title="View PDF"]');
if (pdfElement) {
item.attachments.push({
url: pdfElement.href,

391
ACM Queue.js Normal file
View File

@ -0,0 +1,391 @@
{
"translatorID": "212ffcc8-927c-4e84-a097-bd24fd4a44b6",
"label": "ACM Queue",
"creator": "Bogdan Lynn",
"target": "^https://queue\\.acm\\.org/",
"minVersion": "5.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2025-12-04 18:10:19"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2025 Bogdan Lynn
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
function detectWeb(doc, url) {
if (url.includes('detail.cfm?id=')) {
return 'journalArticle';
}
else if (getSearchResults(doc, true)) {
return 'multiple';
}
return false;
}
function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
var rows = doc.querySelectorAll('a[href*="detail.cfm?id="]');
for (let row of rows) {
let href = row.href;
// Skip links to specific parts of the article, like #comments,
// since those normally appear below the actual top-level link
if (href.includes("#")) continue;
let title = ZU.trimInternal(row.textContent);
if (!href || !title) continue;
if (checkOnly) return true;
found = true;
items[href] = title;
}
return found ? items : false;
}
async function doWeb(doc, url) {
if (detectWeb(doc, url) == 'multiple') {
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(await requestDocument(url));
}
}
else {
await scrape(doc, url);
}
}
async function scrape(doc, url = doc.location.href) {
// DOI can be found in the URL of the PDF link
let pdfUrl = doc.querySelector('a[href*="/doi/pdf"]');
let doi = pdfUrl.href.split("/pdf/")[1];
let translate = Zotero.loadTranslator("search");
// DOI Content Negotiation translator
translate.setTranslator("b28d0d42-8549-4c6d-83fc-8382874a5cb9");
translate.setSearch({ itemType: "journalArticle", DOI: doi });
// Do nothing on error
translate.setHandler("error", () => {});
translate.setHandler("itemDone", (obj, item) => {
item.publicationTitle = "ACM Queue";
item.publisher = "Association for Computing Machinery";
// 'DOI Content Negotiation' translator does not add attachments
let pdfUrl = doc.querySelector('a[href*="/doi/pdf"]');
item.attachments.push({
url: pdfUrl.href,
title: 'Full Text PDF',
mimeType: 'application/pdf'
});
item.complete();
});
// Try to resolve the DOI, and if it does not work, scrape the DOM.
try {
await translate.translate();
return;
}
catch (e) {
Zotero.debug(`Failed to resolve DOI. Scrape the page.`);
}
await scrapeDocument(doc, url);
}
async function scrapeDocument(doc, url) {
let item = new Zotero.Item("journalArticle");
item.title = text(doc, "h1");
item.publicationTitle = "ACM Queue";
item.publisher = "Association for Computing Machinery";
item.journalAbbreviation = "Queue";
item.language = "en";
item.ISSN = "1542-7730";
item.url = url;
// Extract volume and issue from "Volume X, issue Y" at the top
let descriptor = text(doc, ".descriptor").toLowerCase();
let re = /^volume\s+(\d+),\s*issue\s+(\d+)\s*$/i;
let matches = descriptor.match(re) || [];
item.volume = matches[1];
item.issue = matches[2];
// Add PDF attachment and DOI
let pdfUrl = doc.querySelector('a[href*="/doi/pdf"]');
let doi = pdfUrl.href.split("/pdf/")[1];
item.DOI = doi;
item.attachments.push({
url: pdfUrl.href,
title: 'Full Text PDF',
mimeType: 'application/pdf'
});
// Some info needs to be fetched from the page of the entire issue
// because it appears in difference places on the article page
let issueDoc = await requestDocument(attr(doc, ".descriptor", "href"));
// Fetch date
let dateContainer = text(issueDoc, "#lead p");
let date = dateContainer.split(" ").slice(-2).join(" ");
if (date.includes("/")) {
date = date.split("/")[1];
}
item.date = date;
// Find link to the article on the page of the issue
let searchParams = new URLSearchParams(url.split("?")[1]);
let id = searchParams.get("id");
let articleLinkOnissueDoc = issueDoc.querySelector(`a[href*="detail.cfm?id=${id}"]`);
// Fetch abstract below the link
item.abstractNote = articleLinkOnissueDoc.parentNode.nextElementSibling.textContent;
// Fetch creators below the abstract
let potentialAuthors = articleLinkOnissueDoc.parentNode.nextElementSibling.nextElementSibling;
if (potentialAuthors?.classList.contains("meta")) {
let creators = potentialAuthors.textContent.split(",");
for (let creator of creators) {
item.creators.push(ZU.cleanAuthor(creator, "author"));
}
}
item.complete();
}
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "https://queue.acm.org/detail.cfm?id=3664275",
"items": [
{
"itemType": "journalArticle",
"title": "Make Two Trips: Larry David's New Year's resolution works for IT too.",
"creators": [
{
"creatorType": "author",
"firstName": "Thomas A.",
"lastName": "Limoncelli"
}
],
"date": "2024-04-30",
"DOI": "10.1145/3664275",
"ISSN": "1542-7730, 1542-7749",
"abstractNote": "Whether your project is as simple as carrying groceries into the house or as complex as a multiyear engineering project, \"make two trips\" can simplify the project, reduce the chance of error, improve the probability of success, and lead to easier explanations.",
"issue": "2",
"journalAbbreviation": "Queue",
"language": "en",
"libraryCatalog": "DOI.org (Crossref)",
"pages": "5-14",
"publicationTitle": "ACM Queue",
"shortTitle": "Make Two Trips",
"url": "https://dl.acm.org/doi/10.1145/3664275",
"volume": "22",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://queue.acm.org/detail.cfm?id=3762991",
"items": [
{
"itemType": "journalArticle",
"title": "Understanding the Harm Teens Experience on Social Media",
"creators": [
{
"firstName": "Arturo",
"lastName": "Béjar",
"creatorType": "author"
}
],
"date": "August 2025",
"DOI": "10.1145/3762991",
"ISSN": "1542-7730",
"abstractNote": "The current approach to online safety, focusing on objectively harmful content and deletion or downranking, is necessary but not sufficient, as it addresses only a small fraction of the harm that teens experience. In order to understand harm, it is essential to understand it from their perspective by surveying and creating safety tools and reporting that make it easy to capture what happens and provide immediate help. Many of the recommendations in this article come from what you learn when you analyze behavioral correlates: that you need approaches that rely on conduct in context, better personalization, and providing feedback to actors.",
"issue": "4",
"journalAbbreviation": "Queue",
"language": "en",
"libraryCatalog": "ACM Queue",
"publicationTitle": "ACM Queue",
"url": "https://queue.acm.org/detail.cfm?id=3762991",
"volume": "23",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://queue.acm.org/detail.cfm?id=3546935",
"items": [
{
"itemType": "journalArticle",
"title": "I'm Probably Less Deterministic Than I Used to Be: Embracing randomness is necessary in cloud environments.",
"creators": [
{
"creatorType": "author",
"firstName": "Pat",
"lastName": "Helland"
}
],
"date": "2022-06-30",
"DOI": "10.1145/3546935",
"ISSN": "1542-7730, 1542-7749",
"abstractNote": "In my youth, I thought the universe was ruled by cause and effect like a big clock. In this light, computing made sense. Now I see that both life and computing can be a crapshoot, and that has given me a new peace.",
"issue": "3",
"journalAbbreviation": "Queue",
"language": "en",
"libraryCatalog": "DOI.org (Crossref)",
"pages": "5-13",
"publicationTitle": "ACM Queue",
"shortTitle": "I'm Probably Less Deterministic Than I Used to Be",
"url": "https://dl.acm.org/doi/10.1145/3546935",
"volume": "20",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://queue.acm.org/detail.cfm?id=3501293",
"items": [
{
"itemType": "journalArticle",
"title": "Federated Learning and Privacy",
"creators": [
{
"firstName": "Kallista",
"lastName": "Bonawitz",
"creatorType": "author"
},
{
"firstName": "Peter",
"lastName": "Kairouz",
"creatorType": "author"
},
{
"firstName": "Brendan",
"lastName": "McMahan",
"creatorType": "author"
},
{
"firstName": "Daniel",
"lastName": "Ramage",
"creatorType": "author"
}
],
"date": "September-October 2021",
"DOI": "10.1145/3494834.3501293",
"ISSN": "1542-7730",
"abstractNote": "Centralized data collection can expose individuals to privacy risks and organizations to legal risks if data is not properly managed. Federated learning is a machine learning setting where multiple entities collaborate in solving a machine learning problem, under the coordination of a central server or service provider. Each client's raw data is stored locally and not exchanged or transferred; instead, focused updates intended for immediate aggregation are used to achieve the learning objective. This article provides a brief introduction to key concepts in federated learning and analytics with an emphasis on how privacy technologies may be combined in real-world systems and how their use charts a path toward societal benefit from aggregate statistics in new domains and with minimized risk to individuals and to the organizations who are custodians of the data.",
"issue": "5",
"journalAbbreviation": "Queue",
"language": "en",
"libraryCatalog": "ACM Queue",
"publicationTitle": "ACM Queue",
"url": "https://queue.acm.org/detail.cfm?id=3501293",
"volume": "19",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://queue.acm.org/detail.cfm?id=3773095",
"items": [
{
"itemType": "journalArticle",
"title": "Memory Safety for Skeptics",
"creators": [
{
"firstName": "Andrew Lilley",
"lastName": "Brinker",
"creatorType": "author"
}
],
"date": "October 2025",
"DOI": "10.1145/3773095",
"ISSN": "1542-7730",
"abstractNote": "The state of possibility with memory safety today is similar to the state of automobile safety just prior to the widespread adoption of mandatory seat-belt laws. As car manufacturers began to integrate seat belts as a standard feature across their model lines and states began to require that drivers wear seat belts while driving, the rate of traffic fatalities and severity of traffic-related injuries dropped drastically. Seat belts did not solve automobile safety, but they credibly improved it, and at remarkably low cost.",
"issue": "5",
"journalAbbreviation": "Queue",
"language": "en",
"libraryCatalog": "ACM Queue",
"publicationTitle": "ACM Queue",
"url": "https://queue.acm.org/detail.cfm?id=3773095",
"volume": "23",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://queue.acm.org/issuedetail.cfm?issue=2838344",
"items": "multiple"
},
{
"type": "web",
"url": "https://queue.acm.org/listing.cfm?item_topic=Blockchain&qc_type=theme_list&filter=Blockchain&page_title=Blockchain&order=desc",
"items": "multiple"
}
]
/** END TEST CASES **/

View File

@ -2,76 +2,81 @@
"translatorID": "938ebe32-2b2e-4349-a5b3-b3a05d3de627",
"label": "ACS Publications",
"creator": "Sean Takats, Michael Berkowitz, Santawort, and Aurimas Vinckevicius",
"target": "^https?://pubs\\.acs\\.org/(toc/|journal/|topic/|isbn/\\d|doi/(full/|abs/)?10\\.|action/doSearch\\?)",
"target": "^https?://pubs\\.acs\\.org/(toc/|journal/|topic/|isbn/\\d|doi/(full/|abs/|epdf/|book/)?10\\.|action/(doSearch\\?|showCitFormats\\?.*doi))",
"minVersion": "4.0.5",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2019-10-07 09:04:25"
"lastUpdated": "2024-09-30 13:50:18"
}
/*
***** BEGIN LICENSE BLOCK *****
function getSearchResults(doc, checkOnly, itemOpts) {
Copyright © 2008 Sean Takats, Michael Berkowitz, Santawort, Aurimas
Vinckevicius, Philipp Zumstein, and other contributors.
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
function getSearchResults(doc, checkOnly) {
var items = {}, found = false;
var rows = doc.querySelectorAll('.issue-item_title a, .teaser_title a');
for (let i = 0; i < rows.length; i++) {
var href = rows[i].href;
var title = ZU.trimInternal(rows[i].textContent);
if (!href || !title) continue;
var doi = getDoi(href);
if (!href || !title || !doi) continue;
if (!doi) continue;
if (checkOnly) return true;
found = true;
items[doi] = title;
// Not sure if this is still working on the new websites...
itemOpts[doi] = {};
/*
//check if article contains supporting info,
//so we don't have to waste an HTTP request later if it doesn't
var articleBox = titles[i].parentNode.parentNode;
if (!articleBox.classList.contains('articleBox')) {
// e.g. Most Recently Published under Subject Search
continue;
}
if (ZU.xpath(articleBox, './/a[text()="Supporting Info"]').length) {
itemOpts[doi].hasSupp = true;
}
*/
items[href] = title;
}
return found ? items : false;
}
// Return the DOI indicated by the URL, or null when no DOI is found
// The input should be a properly encoded URL
function getDoi(url) {
var m = url.match(/https?:\/\/[^/]*\/doi\/(?:abs\/|full\/)?(10\.[^?#]+)/);
if (m) {
var doi = m[1];
if (doi.includes("prevSearch")) {
doi = doi.substring(0, doi.indexOf("?"));
}
return decodeURIComponent(doi);
let urlObj = new URL(url);
let doi = decodeURIComponent(urlObj.pathname).match(/^\/doi\/(?:.+\/)?(10\.\d{4,}\/.+)$/);
if (doi) {
doi = doi[1];
}
return false;
else {
doi = urlObj.searchParams.get("doi");
}
return doi;
}
/** ***************************
* BEGIN: Supplementary data *
*****************************/
// Get supplementary file names either from the Supporting Info page or the tooltip
function getSuppFiles(div) {
var fileNames = ZU.xpath(div, './/li//li');
var attach = [];
for (var i = 0, n = fileNames.length; i < n; i++) {
attach.push(fileNames[i].textContent.trim().replace(/\s[\s\S]+/, ''));
}
return attach;
}
var suppTypeMap = {
txt: 'text/plain',
csv: 'text/csv',
bz2: 'application/x-bzip2',
gz: 'application/gzip',
zip: 'application/zip',
pdf: 'application/pdf',
doc: 'application/msword',
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
@ -79,28 +84,33 @@ var suppTypeMap = {
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
};
function getSuppMimeType(fileName) {
var ext = fileName.substr(fileName.lastIndexOf('.') + 1);
var mimeType = suppTypeMap[ext];
return mimeType ? mimeType : undefined;
}
function attachSupp(item, doi, opts) {
if (!opts.attach) return;
if (!item.attachments) item.attachments = [];
var attachment;
for (var i = 0, n = opts.attach.length; i < n; i++) {
attachment = {
title: opts.attach[i]
};
attachment.url = '/doi/suppl/' + doi + '/suppl_file/' + attachment.title;
attachment.mimeType = getSuppMimeType(attachment.title);
if (opts.attachAsLink || !attachment.mimeType) { // don't download unknown file types
attachment.snapshot = false;
}
item.attachments.push(attachment);
function getSupplements(doc, supplementAsLink = false) {
let supplements = [];
// Note that the lists of supplements are duplicated in the main
// content side and right-side panel (if any). We want to confine it to
// one (or the only) side in order to avoid having to deduplicate.
let supplementLinks = doc.querySelectorAll(".article_content-left .suppl-anchor");
for (let i = 0; i < supplementLinks.length; i++) {
let elem = supplementLinks[i];
let url = elem.href;
if (!url) continue;
let pathComponents = url.replace(/[?#].+$/, "").split(".");
// possible location of file extension (following the last dot)
let ext = pathComponents[pathComponents.length - 1].toLowerCase();
let mimeType = suppTypeMap[ext];
// Only save file when MIME type is known *and* when we aren't
// specifically told otherwise
let snapshot = Boolean(!supplementAsLink && mimeType);
// The "title" (text describing what the supplement file is for) can be
// substantially long, while the filename is redundant (and it doesn't
// inform the user that the file is meant to be a supplement). We
// simply number them in the order they appear.
let title = `Supplement ${i + 1}`;
let attachment = { title, url, snapshot };
if (mimeType) attachment.mimeType = mimeType;
supplements.push(attachment);
}
return supplements;
}
/** *************************
@ -111,7 +121,28 @@ function detectWeb(doc, url) {
if (getSearchResults(doc, true)) {
return "multiple";
}
let urlObj = new URL(url);
// standalone "download citation" page
if (urlObj.pathname === "/action/showCitFormats"
&& urlObj.searchParams.get("doi")) {
// May be inaccurate, but better than not detecting
return "journalArticle";
}
// epdf viewer web app
if (urlObj.pathname.startsWith("/doi/epdf/")) {
// TODO: check if "epdf" viewer is always for journal articles
return "journalArticle";
}
// books such as https://pubs.acs.org/doi/book/10.1021/acsguide
if (urlObj.pathname.startsWith("/doi/book/")) {
return "book";
}
if (doc.querySelector("#returnToBook")) {
// Some of them may be conference articles, but the RIS doesn't say so
return "bookSection";
}
else if (getDoi(url)) {
// TODO: check if this block still works
var type = doc.getElementsByClassName("content-navigation__contentType");
if (type.length && type[0].textContent.includes("Chapter")) {
return "bookSection";
@ -123,160 +154,117 @@ function detectWeb(doc, url) {
return false;
}
function doWeb(doc, url) {
var opts = {};
function cleanNumberField(item, field) {
if (item[field]) {
let n = parseInt(item[field]);
if (n <= 0 || isNaN(n)) {
delete item[field];
}
}
}
// In most cases the URL contains the DOI which is sufficient for obtaining the
// RIS, so there's no need to download the document if it's not already there.
// But when supplements as attachments are desired, we need the actual document
// for the supplement links. Our convention here is to pass falsy as the "doc"
// argument when supplements are not requested, and the actual doc (maybe
// fetched by us) when we want the supplements.
async function doWeb(doc, url) {
let attachSupplement = false;
let supplementAsLink = false;
// reduce some overhead by fetching these only once
if (Z.getHiddenPref) {
opts.attachSupp = Z.getHiddenPref("attachSupplementary");
opts.attachAsLink = Z.getHiddenPref("supplementaryAsLink");
attachSupplement = Z.getHiddenPref("attachSupplementary");
supplementAsLink = Z.getHiddenPref("supplementaryAsLink");
}
var itemOpts = {};
if (detectWeb(doc, url) == "multiple") { // search
Zotero.selectItems(getSearchResults(doc, false, itemOpts), function (items) {
if (!items) {
return;
}
var dois = [];
for (let i in items) {
itemOpts[i].pdf = '/doi/pdf/' + i;
dois.push({ doi: i, opts: itemOpts[i] });
}
scrape(dois, opts);
});
}
else { // single article
var doi = getDoi(url);
Zotero.debug("DOI= " + doi);
// we can determine file names from the tooltip, which saves us an HTTP request
var suppTip = doc.getElementById('suppTipDiv');
if (opts.attachSupp && suppTip) {
try {
opts.attach = getSuppFiles(suppTip, opts);
}
catch (e) {
Z.debug("Error getting supplementary files.");
Z.debug(e);
}
let items = await Z.selectItems(getSearchResults(doc));
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(
attachSupplement && await requestDocument(url),
url,
supplementAsLink
);
await delay(500);
}
// if we couldn't find this on the individual item page,
// then it doesn't have supp info anyway. This way we know not to check later
if (!opts.attach) opts.attach = [];
itemOpts.pdf = ZU.xpathText(doc, '(//a[i[contains(@class, "icon-file-pdf-o")]]/@href)[1]') || '/doi/pdf/' + doi;
scrape([{ doi: doi, opts: itemOpts }], opts);
}
else {
// single article
await scrape(attachSupplement && doc, url, supplementAsLink);
}
}
function scrape(items, opts) {
for (var i = 0, n = items.length; i < n; i++) {
processCallback(items[i], opts);
}
function delay(milliseconds) {
return new Promise(resolve => setTimeout(resolve, milliseconds));
}
function processCallback(fetchItem, opts) {
var baseurl = "/action/downloadCitation";
var doi = fetchItem.doi;
var post = "https//pubs.acs.org/action/downloadCitation?direct=true&doi=" + encodeURIComponent(fetchItem.doi) + "&format=ris&include=abs&submit=Download+Citation";
ZU.doPost(baseurl, post, function (text) {
// Fix the RIS doi mapping
text = text.replace("\nN1 - doi:", "\nDO - ");
// Fix the wrong mapping for journal abbreviations
text = text.replace("\nJO -", "\nJ2 -");
// Use publication date when available
if (text.includes("\nDA -")) {
text = text.replace(/\nY1 {2}- [^\n]*/, "")
.replace("\nDA -", "\nY1 -");
}
// Zotero.debug("ris= "+ text);
var translator = Zotero.loadTranslator("import");
translator.setTranslator("32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7");
translator.setString(text);
translator.setHandler("itemDone", function (obj, item) {
if (item.date) {
item.date = ZU.strToISO(item.date);
}
item.attachments = [];
async function scrape(doc, url, supplementAsLink) {
let doi = getDoi(url);
// standard pdf and snapshot
if (fetchItem.opts.pdf) {
if (doc && /\/action\/showCitFormats\?|\/doi\/epdf\//.test(url)) {
// standalone "export citation" page or "epdf viewer", *and*
// supplements are desired; we need to fetch the actual article page
// and scrape that
url = `https://pubs.acs.org/doi/${doi}`;
doc = await requestDocument(url);
}
let risURL = new URL("/action/downloadCitation?include=abs&format=ris&direct=true", url);
risURL.searchParams.set("doi", doi);
risURL.searchParams.set("downloadFileName", doi.replace(/^10\.\d{4,}\//, ""));
let risText = await requestText(risURL.href, { headers: { Referer: url } });
// Delete redundant DOI info
risText = risText.replace(/\nN1 {2}- doi:[^\n]+/, "");
// Fix noise in DO field
risText = risText.replace("\nDO - doi:", "\nDO - ");
// Fix the wrong mapping for journal abbreviations
risText = risText.replace("\nJO -", "\nJ2 -");
// Use publication date when available
if (risText.includes("\nDA -")) {
risText = risText.replace(/\nY1 {2}- [^\n]*/, "")
.replace("\nDA -", "\nY1 -");
}
let translator = Zotero.loadTranslator("import");
// RIS
translator.setTranslator("32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7");
translator.setString(risText);
translator.setHandler("itemDone", function (obj, item) {
if (item.date) {
item.date = ZU.strToISO(item.date);
}
item.attachments = [];
if (/\/doi\/book\//.test(url)) {
// books as standalone items don't have full pdfs (TODO: verify)
if (doc) {
item.attachments.push({
title: "Full Text PDF",
url: fetchItem.opts.pdf,
mimeType: "application/pdf"
title: "Snapshot",
url: url,
mimeType: "text/html"
});
}
}
else {
// standard pdf
item.attachments.push({
title: "ACS Full Text Snapshot",
url: '/doi/full/' + doi,
mimeType: "text/html"
title: "Full Text PDF",
url: `/doi/pdf/${doi}`,
mimeType: "application/pdf"
});
// supplementary data
try {
if (opts.attachSupp && opts.attach) {
// came from individual item page
attachSupp(item, doi, opts);
}
else if (opts.attachSupp && fetchItem.opts.hasSupp) {
// was a search result and has supp info
var suppUrl = '/doi/suppl/' + doi;
if (opts.attachAsLink) {
// if we're only attaching links, it's not worth linking to each doc
item.attachments.push({
title: "Supporting Information",
url: suppUrl,
mimeType: 'text/html',
snapshot: false
});
}
else {
ZU.processDocuments(suppUrl, function (suppDoc) {
try {
var div = suppDoc.getElementById('supInfoBox');
if (div) {
var files = getSuppFiles(div);
attachSupp(item, doi, {
attach: files,
attachAsLink: opts.attachAsLink
});
}
else {
Z.debug("Div not found");
item.attachments.push({
title: "Supporting Information",
url: suppUrl,
mimeType: 'text/html',
snapshot: false
});
}
}
catch (e) {
Z.debug("Error attaching supplementary files.");
Z.debug(e);
}
item.complete();
}, null, function () {
item.complete();
});
return; // don't call item.complete() yet
}
}
}
catch (e) {
Z.debug("Error attaching supplementary files.");
Z.debug(e);
}
item.complete();
});
translator.translate();
}
// supplements
if (doc) {
item.attachments.push(...getSupplements(doc, supplementAsLink));
}
// Cleanup fields that may contain invalid numeric values
cleanNumberField(item, "numberOfVolumes");
cleanNumberField(item, "numPages");
item.complete();
});
await translator.translate();
}
/** BEGIN TEST CASES **/
@ -320,10 +308,6 @@ var testCases = [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
},
{
"title": "ACS Full Text Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
@ -362,7 +346,6 @@ var testCases = [
"bookTitle": "Aquatic Redox Chemistry",
"extra": "DOI: 10.1021/bk-2011-1071.ch005",
"libraryCatalog": "ACS Publications",
"numberOfVolumes": "0",
"pages": "85-111",
"publisher": "American Chemical Society",
"series": "ACS Symposium Series",
@ -374,10 +357,6 @@ var testCases = [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
},
{
"title": "ACS Full Text Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
@ -435,10 +414,6 @@ var testCases = [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
},
{
"title": "ACS Full Text Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
@ -447,11 +422,6 @@ var testCases = [
}
]
},
{
"type": "web",
"url": "https://pubs.acs.org/isbn/9780841239999",
"items": "multiple"
},
{
"type": "web",
"url": "https://pubs.acs.org/journal/acbcct",
@ -461,6 +431,203 @@ var testCases = [
"type": "web",
"url": "https://pubs.acs.org/action/doSearch?text1=zotero&field1=AllField",
"items": "multiple"
},
{
"type": "web",
"url": "https://pubs.acs.org/doi/book/10.1021/acsguide",
"items": [
{
"itemType": "book",
"title": "The ACS Guide to Scholarly Communication",
"creators": [
{
"lastName": "Banik",
"firstName": "Gregory M.",
"creatorType": "author"
},
{
"lastName": "Baysinger",
"firstName": "Grace",
"creatorType": "author"
},
{
"lastName": "Kamat",
"firstName": "Prashant V.",
"creatorType": "author"
},
{
"lastName": "Pienta",
"firstName": "Norbert",
"creatorType": "author"
}
],
"date": "2019-10-02",
"ISBN": "9780841235861",
"extra": "DOI: 10.1021/acsguide",
"libraryCatalog": "ACS Publications",
"publisher": "American Chemical Society",
"series": "ACS Guide to Scholarly Communication",
"url": "https://doi.org/10.1021/acsguide",
"attachments": [],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://pubs.acs.org/action/showCitFormats?doi=10.1021%2Facscentsci.3c00243",
"items": [
{
"itemType": "journalArticle",
"title": "Generic Platform for the Multiplexed Targeted Electrochemical Detection of Osteoporosis-Associated Single Nucleotide Polymorphisms Using Recombinase Polymerase Solid-Phase Primer Elongation and Ferrocene-Modified Nucleoside Triphosphates",
"creators": [
{
"lastName": "Ortiz",
"firstName": "Mayreli",
"creatorType": "author"
},
{
"lastName": "Jauset-Rubio",
"firstName": "Miriam",
"creatorType": "author"
},
{
"lastName": "Trummer",
"firstName": "Olivia",
"creatorType": "author"
},
{
"lastName": "Foessl",
"firstName": "Ines",
"creatorType": "author"
},
{
"lastName": "Kodr",
"firstName": "David",
"creatorType": "author"
},
{
"lastName": "Acero",
"firstName": "Josep Lluís",
"creatorType": "author"
},
{
"lastName": "Botero",
"firstName": "Mary Luz",
"creatorType": "author"
},
{
"lastName": "Biggs",
"firstName": "Phil",
"creatorType": "author"
},
{
"lastName": "Lenartowicz",
"firstName": "Daniel",
"creatorType": "author"
},
{
"lastName": "Trajanoska",
"firstName": "Katerina",
"creatorType": "author"
},
{
"lastName": "Rivadeneira",
"firstName": "Fernando",
"creatorType": "author"
},
{
"lastName": "Hocek",
"firstName": "Michal",
"creatorType": "author"
},
{
"lastName": "Obermayer-Pietsch",
"firstName": "Barbara",
"creatorType": "author"
},
{
"lastName": "OSullivan",
"firstName": "Ciara K.",
"creatorType": "author"
}
],
"date": "2023-08-23",
"DOI": "10.1021/acscentsci.3c00243",
"ISSN": "2374-7943",
"abstractNote": "Osteoporosis is a multifactorial disease influenced by genetic and environmental factors, which contributes to an increased risk of bone fracture, but early diagnosis of this disease cannot be achieved using current techniques. We describe a generic platform for the targeted electrochemical genotyping of SNPs identified by genome-wide association studies to be associated with a genetic predisposition to osteoporosis. The platform exploits isothermal solid-phase primer elongation with ferrocene-labeled nucleoside triphosphates. Thiolated reverse primers designed for each SNP were immobilized on individual gold electrodes of an array. These primers are designed to hybridize to the SNP site at their 3OH terminal, and primer elongation occurs only where there is 100% complementarity, facilitating the identification and heterozygosity of each SNP under interrogation. The platform was applied to real blood samples, which were thermally lysed and directly used without the need for DNA extraction or purification. The results were validated using Taqman SNP genotyping assays and Sanger sequencing. The assay is complete in just 15 min with a total cost of 0.3€ per electrode. The platform is completely generic and has immense potential for deployment at the point of need in an automated device for targeted SNP genotyping with the only required end-user intervention being sample addition.",
"issue": "8",
"journalAbbreviation": "ACS Cent. Sci.",
"libraryCatalog": "ACS Publications",
"pages": "1591-1602",
"publicationTitle": "ACS Central Science",
"url": "https://doi.org/10.1021/acscentsci.3c00243",
"volume": "9",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://pubs.acs.org/doi/epdf/10.1021/acscentsci.3c00323",
"items": [
{
"itemType": "journalArticle",
"title": "Dynamics of Rayleigh Fission Processes in 100 nm Charged Aqueous Nanodrops",
"creators": [
{
"lastName": "Hanozin",
"firstName": "Emeline",
"creatorType": "author"
},
{
"lastName": "Harper",
"firstName": "Conner C.",
"creatorType": "author"
},
{
"lastName": "McPartlan",
"firstName": "Matthew S.",
"creatorType": "author"
},
{
"lastName": "Williams",
"firstName": "Evan R.",
"creatorType": "author"
}
],
"date": "2023-08-23",
"DOI": "10.1021/acscentsci.3c00323",
"ISSN": "2374-7943",
"abstractNote": "Fission of micron-size charged droplets has been observed using optical methods, but little is known about fission dynamics and breakup of smaller nanosize droplets that are important in a variety of natural and industrial processes. Here, spontaneous fission of individual aqueous nanodrops formed by electrospray is investigated using charge detection mass spectrometry. Fission processes ranging from formation of just two progeny droplets in 2 ms to production of dozens of progeny droplets over 100+ ms are observed for nanodrops that are charged above the Rayleigh limit. These results indicate that Rayleigh fission is a continuum of processes that produce progeny droplets that vary widely in charge, mass, and number.",
"issue": "8",
"journalAbbreviation": "ACS Cent. Sci.",
"libraryCatalog": "ACS Publications",
"pages": "1611-1622",
"publicationTitle": "ACS Central Science",
"url": "https://doi.org/10.1021/acscentsci.3c00323",
"volume": "9",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

View File

@ -3,12 +3,12 @@
"label": "ADS Bibcode",
"creator": "Abe Jellinek",
"target": "",
"minVersion": "4.0",
"minVersion": "6.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 8,
"lastUpdated": "2023-06-09 17:04:40"
"lastUpdated": "2025-04-29 03:02:00"
}
/*
@ -34,9 +34,23 @@
***** END LICENSE BLOCK *****
*/
const preprintType = ZU.fieldIsValidForType('title', 'preprint')
? 'preprint'
: 'report';
// Logic for accurate type detection. In general, the type in the RIS export is
// fairly accurate. However, it may misidentify a proceedings book as JOUR (but
// usually identifies conference papers fine). Theses are also identified as
// JOUR in the RIS file. Preprints are usually correctly identified.
function getRealType(bibStem, exportType) {
if (/^(PhDT|MsT)/.test(bibStem)) {
return "thesis";
}
// Fix misidentifying full proceedings book as JOUR
let volume = bibStem.substring(5, 9);
if (volume === "conf" && exportType === "journalArticle") {
return "book";
}
return exportType;
}
// https://github.com/yymao/adstex/blob/64989c9e75d7401ea2b33b546664cbc34cce6a27/adstex.py
const bibcodeRe = /^\d{4}\D\S{13}[A-Z.:]$/;
@ -45,10 +59,10 @@ function detectSearch(items) {
return !!filterQuery(items).length;
}
function doSearch(items) {
async function doSearch(items) {
let bibcodes = filterQuery(items);
if (!bibcodes.length) return;
scrape(bibcodes);
await scrape(bibcodes);
}
function filterQuery(items) {
@ -70,95 +84,93 @@ function filterQuery(items) {
}
function extractId(url) {
return /\/abs\/([^/]+)/.exec(url)[1];
}
function getTypeFromId(id) {
// bibcodes always start with 4 digit year, then bibstem
const bibstem = id.slice(4);
if (bibstem.startsWith("MsT") || bibstem.startsWith("PhDT")) {
return "thesis";
}
else if (bibstem.startsWith("arXiv")) {
return preprintType;
}
else {
// now scan past the bibstem and find the volume number/type abbrev.
const volume = bibstem.substring(5, 9);
if (volume == "conf" || volume == "meet" || volume == "coll"
|| volume == "proc" || volume == "book") {
return "book";
}
else if (volume == "rept") {
return "report";
}
}
return "journalArticle";
let m = url.match(/\/abs\/([^/]+)/);
return m && decodeURIComponent(m[1]);
}
function makePdfUrl(id) {
return "https://ui.adsabs.harvard.edu/link_gateway/" + id + "/ARTICLE";
}
function scrape(ids) {
ZU.doGet('https://api.adsabs.harvard.edu/v1/accounts/bootstrap', function (respText) {
let json = JSON.parse(respText);
let token = json.access_token;
// Detect if an item is from arXiv. This is necessary because bibcodes of older
// arXiv preprints don't start with "arXiv"
function isArXiv(item, bibStem) {
if (item.DOI && item.DOI.startsWith("10.48550/")) return true;
if (bibStem.startsWith("arXiv")) return true;
return false;
}
let exportUrl = "https://ui.adsabs.harvard.edu/v1/export/ris";
let body = JSON.stringify({
bibcode: ids,
sort: ['date desc, bibcode desc']
async function scrape(ids) {
let bootstrap = await requestJSON("https://api.adsabs.harvard.edu/v1/accounts/bootstrap");
if (!bootstrap || !bootstrap.access_token) {
throw new Error("ADS Bibcode: cannot obtain access token");
}
let body = JSON.stringify({ bibcode: ids, sort: ['no sort'] });
let response = await requestJSON("https://api.adsabs.harvard.edu/v1/export/ris", {
method: "POST",
body,
headers: {
Accept: "application/json",
Authorization: `Bearer ${bootstrap.access_token}`,
"Content-Type": "application/json",
},
});
let translator = Zotero.loadTranslator("import");
translator.setTranslator("32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7"); // RIS
translator.setString(response.export);
translator.setHandler("itemDone", function (obj, item) {
let id = extractId(item.url);
let bibStem = id.slice(4);
let type = getRealType(bibStem, item.itemType);
if (type !== item.itemType) {
Z.debug(`ADS Bibcode: changing item type: ${item.itemType} -> ${type}`);
item.itemType = type;
}
if (isArXiv(item, bibStem)) {
item.itemType = "preprint";
item.publisher = "arXiv";
delete item.pages;
delete item.publicationTitle;
delete item.journalAbbreviation;
}
item.extra = (item.extra || '') + `\nADS Bibcode: ${id}`;
// for thesis-type terminology, see
// https://adsabs.harvard.edu/abs_doc/journals1.html
if (item.itemType === "thesis") {
if (bibStem.startsWith("PhDT")) {
item.thesisType = "Ph.D. thesis";
}
else if (bibStem.startsWith("MsT")) {
item.thesisType = "Masters thesis";
}
delete item.journalAbbreviation; // from spurious JO tag
delete item.publicationTitle;
}
item.attachments.push({
url: makePdfUrl(id),
title: "Full Text PDF",
mimeType: "application/pdf"
});
ZU.doPost(exportUrl, body, function (respText) {
let json = JSON.parse(respText);
if (item.journalAbbreviation == item.publicationTitle) {
delete item.journalAbbreviation;
}
const translator = Zotero.loadTranslator("import");
translator.setTranslator("32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7"); // RIS
translator.setString(json.export);
translator.setHandler("itemDone", function (obj, item) {
const id = extractId(item.url);
let detectedType = getTypeFromId(id);
if (detectedType != item.itemType) {
Z.debug(`Changing item type: ${item.itemType} -> ${detectedType}`);
item.itemType = detectedType;
}
if (item.date) {
item.date = ZU.strToISO(item.date);
}
item.extra = (item.extra || '') + `\nADS Bibcode: ${id}`;
item.libraryCatalog = 'NASA ADS';
if (id.slice(4).startsWith('arXiv')) {
if (preprintType == "report") {
item.extra += '\nType: article'; // will map to preprint
}
}
if (item.pages && item.pages.startsWith('arXiv:')) {
// not sure why this ends up in the SP tag
delete item.pages;
}
item.attachments.push({
url: makePdfUrl(id),
title: "Full Text PDF",
mimeType: "application/pdf"
});
if (item.journalAbbreviation == item.publicationTitle) {
item.journalAbbreviation = '';
}
if (item.date) {
item.date = ZU.strToISO(item.date);
}
item.libraryCatalog = 'NASA ADS';
item.complete();
});
translator.translate();
}, { Authorization: 'Bearer:' + token });
item.complete();
});
await translator.translate();
}
/** BEGIN TEST CASES **/
@ -253,6 +265,7 @@ var testCases = [
"abstractNote": "Gravitational-wave astronomy is now a reality. During my time at Caltech, the Advanced LIGO and Virgo observatories have detected gravitational waves from dozens of compact binary coalescences. All of these gravitational-wave events occurred in the relatively local Universe. In the first part of this thesis, I will instead look towards the remote Universe, investigating what LIGO and Virgo may be able to learn about cosmologically-distant compact binaries via observation of the stochastic gravitational-wave background. The stochastic gravitational-wave background is composed of the incoherent superposition of all distant, individually-unresolvable gravitational-wave sources. I explore what we learn from study of the gravitational-wave background, both about the astrophysics of compact binaries and the fundamental nature of gravitational waves. Of course, before we can study the gravitational-wave background we must first detect it. I therefore present searches for the gravitational-wave background using data from Advanced LIGO's first two observing runs, obtaining the most stringent upper limits to date on strength of the stochastic background. Finally, I consider how one might validate an apparent detection of the gravitational-wave background, confidently distinguishing a true astrophysical signal from spurious terrestrial artifacts. The second part of this thesis concerns the search for electromagnetic counterparts to gravitational-wave events. The binary neutron star merger GW170817 was accompanied by a rich set of electromagnetic counterparts spanning nearly the entire electromagnetic spectrum. Beyond these counterparts, compact binaries may additionally generate powerful radio transients at or near their time of merger. First, I consider whether there is a plausible connection between this so-called \"prompt radio emission\" and fast radio bursts — enigmatic radio transients of unknown origin. Next, I present the first direct search for prompt radio emission from a compact binary merger using the Owens Valley Radio Observatory Long Wavelength Array (OVRO-LWA). While no plausible candidates are identified, this effort successfully demonstrates the prompt radio follow-up of a gravitational-wave source, providing a blueprint for LIGO and Virgo follow-up in their O3 observing run and beyond.",
"extra": "ADS Bibcode: 2021PhDT.........5C",
"libraryCatalog": "NASA ADS",
"thesisType": "Ph.D. thesis",
"url": "https://ui.adsabs.harvard.edu/abs/2021PhDT.........5C",
"attachments": [
{
@ -415,121 +428,67 @@ var testCases = [
{
"type": "search",
"input": {
"adsBibcode": "2023arXiv230604024S"
"adsBibcode": "2020jsrs.conf..209S"
},
"items": [
{
"itemType": "preprint",
"title": "The FLAMINGO project: cosmological hydrodynamical simulations for large-scale structure and galaxy cluster surveys",
"itemType": "conferencePaper",
"title": "Atmospheric angular momentum related to Earth rotation studies: history and modern developments",
"creators": [
{
"lastName": "Schaye",
"firstName": "Joop",
"creatorType": "author"
},
{
"lastName": "Kugel",
"firstName": "Roi",
"creatorType": "author"
},
{
"lastName": "Schaller",
"firstName": "Matthieu",
"creatorType": "author"
},
{
"lastName": "Helly",
"firstName": "John C.",
"creatorType": "author"
},
{
"lastName": "Braspenning",
"firstName": "Joey",
"creatorType": "author"
},
{
"lastName": "Elbers",
"firstName": "Willem",
"creatorType": "author"
},
{
"lastName": "McCarthy",
"firstName": "Ian G.",
"creatorType": "author"
},
{
"lastName": "van Daalen",
"firstName": "Marcel P.",
"creatorType": "author"
},
{
"lastName": "Vandenbroucke",
"firstName": "Bert",
"creatorType": "author"
},
{
"lastName": "Frenk",
"firstName": "Carlos S.",
"creatorType": "author"
},
{
"lastName": "Kwan",
"firstName": "Juliana",
"creatorType": "author"
},
{
"lastName": "Salcido",
"firstName": "Jaime",
"creatorType": "author"
},
{
"lastName": "Bahé",
"firstName": "Yannick M.",
"creatorType": "author"
},
{
"lastName": "Borrow",
"firstName": "Josh",
"creatorType": "author"
},
{
"lastName": "Chaikin",
"firstName": "Evgenii",
"creatorType": "author"
},
{
"lastName": "Hahn",
"firstName": "Oliver",
"creatorType": "author"
},
{
"lastName": "Huško",
"firstName": "Filip",
"creatorType": "author"
},
{
"lastName": "Jenkins",
"firstName": "Adrian",
"creatorType": "author"
},
{
"lastName": "Lacey",
"firstName": "Cedric G.",
"creatorType": "author"
},
{
"lastName": "Nobels",
"firstName": "Folkert S. J.",
"lastName": "Salstein",
"firstName": "D.",
"creatorType": "author"
}
],
"date": "2023-06-01",
"DOI": "10.48550/arXiv.2306.04024",
"abstractNote": "We introduce the Virgo Consortium's FLAMINGO suite of hydrodynamical simulations for cosmology and galaxy cluster physics. To ensure the simulations are sufficiently realistic for studies of large-scale structure, the subgrid prescriptions for stellar and AGN feedback are calibrated to the observed low-redshift galaxy stellar mass function and cluster gas fractions. The calibration is performed using machine learning, separately for three resolutions. This approach enables specification of the model by the observables to which they are calibrated. The calibration accounts for a number of potential observational biases and for random errors in the observed stellar masses. The two most demanding simulations have box sizes of 1.0 and 2.8 Gpc and baryonic particle masses of $1\\times10^8$ and $1\\times10^9 \\text{M}_\\odot$, respectively. For the latter resolution the suite includes 12 model variations in a 1 Gpc box. There are 8 variations at fixed cosmology, including shifts in the stellar mass function and/or the cluster gas fractions to which we calibrate, and two alternative implementations of AGN feedback (thermal or jets). The remaining 4 variations use the unmodified calibration data but different cosmologies, including different neutrino masses. The 2.8 Gpc simulation follows $3\\times10^{11}$ particles, making it the largest ever hydrodynamical simulation run to $z=0$. Lightcone output is produced on-the-fly for up to 8 different observers. We investigate numerical convergence, show that the simulations reproduce the calibration data, and compare with a number of galaxy, cluster, and large-scale structure observations, finding very good agreement with the data for converged predictions. Finally, by comparing hydrodynamical and `dark-matter-only' simulations, we confirm that baryonic effects can suppress the halo mass function and the matter power spectrum by up to $\\approx20$ per cent.",
"extra": "ADS Bibcode: 2023arXiv230604024S",
"date": "2020-09-01",
"abstractNote": "It was noted some time ago that the angular momentum of the atmosphere varies, both regionally as well as in total. Given the conservation of angular momentum in the Earth system, except for known external torques, such variability implies transfer of the angular momentum across the atmosphere's lower boundary. As nearly all is absorbed by the Earth below, the solid Earth changes its overall rotation from this impact. Due to the large difference between in the moments of inertia of the atmosphere and Earth, relatively big differences in the atmosphere are translated as relatively very small differences in the Earth, measurable as changes in Earth rotation rate, and polar motion. The atmospheric angular momentum (AAM) is that due to the motion of the winds and to the changes in mass distribution, closely related to the atmosphere pressure patterns; its variability in the atmosphere is mirrored in the Earth rotation rate and polar motion. This connection between the global solid Earth properties and the global and regional atmosphere on a number of time scales, especially seasonal and interannual, was much appreciated by Barbara Kolaczek, with Jolanta Nastula, at the Space Research Center in Warsaw, and this was a subject of our collaborative studies. Many calculations were made of atmospheric angular momentum, leading to a service under the Global Geophysical Fluids Center of the IERS based on calculations using both operational meteorological series, determined for weather forecasting purposes, and retrospective analyses of the atmosphere. Theoretical development of the connection between the AAM, Earth rotation/polar motion, and also the angular momentum of the other geophysical fluids occurred at the same time that space-based observations and enhanced computer power were allowing improved skills for both weather analysis and forecasting. Hence better determination of the AAM became possible, which could be used as a measure for forecasting Earth rotation. Today we are looking at the atmosphere in combination with the ocean and other fluids, and also assessing the implications of climate variability on Earth rotation through climate model research. According to models of the Earth system, significant changes in winds appear to be a possible result of climate change, with implications for the Earth rotation parameters.",
"conferenceName": "Astrometry, Earth Rotation, and Reference Systems in the GAIA era",
"extra": "ADS Bibcode: 2020jsrs.conf..209S",
"libraryCatalog": "NASA ADS",
"shortTitle": "The FLAMINGO project",
"url": "https://ui.adsabs.harvard.edu/abs/2023arXiv230604024S",
"pages": "209-213",
"shortTitle": "Atmospheric angular momentum related to Earth rotation studies",
"url": "https://ui.adsabs.harvard.edu/abs/2020jsrs.conf..209S",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "search",
"input": [
{
"adsBibcode": "2002math.....11159P"
},
{
"adsBibcode": "2003math......3109P"
}
],
"items": [
{
"itemType": "preprint",
"title": "The entropy formula for the Ricci flow and its geometric applications",
"creators": [
{
"lastName": "Perelman",
"firstName": "Grisha",
"creatorType": "author"
}
],
"date": "2002-11-01",
"DOI": "10.48550/arXiv.math/0211159",
"abstractNote": "We present a monotonic expression for the Ricci flow, valid in all dimensions and without curvature assumptions. It is interpreted as an entropy for a certain canonical ensemble. Several geometric applications are given. In particular, (1) Ricci flow, considered on the space of riemannian metrics modulo diffeomorphism and scaling, has no nontrivial periodic orbits (that is, other than fixed points); (2) In a region, where singularity is forming in finite time, the injectivity radius is controlled by the curvature; (3) Ricci flow can not quickly turn an almost euclidean region into a very curved one, no matter what happens far away. We also verify several assertions related to Richard Hamilton's program for the proof of Thurston geometrization conjecture for closed three-manifolds, and give a sketch of an eclectic proof of this conjecture, making use of earlier results on collapsing with local lower curvature bound.",
"extra": "ADS Bibcode: 2002math.....11159P",
"libraryCatalog": "NASA ADS",
"repository": "arXiv",
"url": "https://ui.adsabs.harvard.edu/abs/2002math.....11159P",
"attachments": [
{
"title": "Full Text PDF",
@ -538,10 +497,162 @@ var testCases = [
],
"tags": [
{
"tag": "Astrophysics - Astrophysics of Galaxies"
"tag": "53C"
},
{
"tag": "Astrophysics - Cosmology and Nongalactic Astrophysics"
"tag": "Differential Geometry"
}
],
"notes": [],
"seeAlso": []
},
{
"itemType": "preprint",
"title": "Ricci flow with surgery on three-manifolds",
"creators": [
{
"lastName": "Perelman",
"firstName": "Grisha",
"creatorType": "author"
}
],
"date": "2003-03-01",
"DOI": "10.48550/arXiv.math/0303109",
"abstractNote": "This is a technical paper, which is a continuation of math.DG/0211159. Here we construct Ricci flow with surgeries and verify most of the assertions, made in section 13 of that e-print; the exceptions are (1) the statement that manifolds that can collapse with local lower bound on sectional curvature are graph manifolds - this is deferred to a separate paper, since the proof has nothing to do with the Ricci flow, and (2) the claim on the lower bound for the volume of maximal horns and the smoothness of solutions from some time on, which turned out to be unjustified and, on the other hand, irrelevant for the other conclusions.",
"extra": "ADS Bibcode: 2003math......3109P",
"libraryCatalog": "NASA ADS",
"repository": "arXiv",
"url": "https://ui.adsabs.harvard.edu/abs/2003math......3109P",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [
{
"tag": "53C"
},
{
"tag": "Differential Geometry"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "search",
"input": {
"adsBibcode": "1995LNP...463...51E"
},
"items": [
{
"itemType": "bookSection",
"title": "Observations and Cosmological Models",
"creators": [
{
"lastName": "Ellis",
"firstName": "G. F. R.",
"creatorType": "author"
}
],
"date": "1995-01-01",
"bookTitle": "Galaxies in the Young Universe",
"extra": "DOI: 10.1007/BFb0102359\nADS Bibcode: 1995LNP...463...51E",
"libraryCatalog": "NASA ADS",
"pages": "51",
"url": "https://ui.adsabs.harvard.edu/abs/1995LNP...463...51E",
"volume": "463",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "search",
"input": {
"adsBibcode": "1997MsT...........B"
},
"items": [
{
"itemType": "thesis",
"title": "Comparative Analysis of Selected Radiation Effects in Medium Earth Orbits",
"creators": [
{
"lastName": "Bolin",
"firstName": "Jennifer A.",
"creatorType": "author"
}
],
"date": "1997-12-01",
"abstractNote": "Satellite design is well developed for the common Low Earth Orbit (LEO) and Geosynchronous Orbit (GEO) and Highly Elliptical Orbits (HEO), i.e., Molniya, cases; Medium Earth Orbit (MEO) satellite design is a relatively new venture. MEO is roughly defined as being altitudes above LEO and below GEO. A primary concern, and a major reason for the delay in exploiting the MEO altitudes, has been the expected radiation environment and corresponding satellite degradation anticipated to occur at MEO altitudes. The presence of the Van Allen belts, a major source of radiation, along with the suitability of GEO and LEO orbits, has conventionally discouraged satellite placement in MEO. As conventional Earth orbits become increasingly crowded, MEO will become further populated. This thesis investigates the major sources of radiation (geomagnetically trapped particles, solar particle events and galactic cosmic radiation) with respect to specific Naval Research Laboratory (NRL) designated MEO (altitudes between 3,000 nautical miles (nmi) and 9,000 nmi; (inclination angle of 15 degrees). The contribution of each of these components to the total radiation experienced in MEO and the effects of the expected radiation on a representative spacecraft are analyzed in comparison to a baseline LEO orbit of 400 nmi and 70 degrees inclination. Dose depth curves are calculated for several configurations, and show that weight gains from necessary expected shielding are not extreme. The radiation effects considered include proton displacement dose and solar cell degradation.",
"extra": "ADS Bibcode: 1997MsT...........B",
"libraryCatalog": "NASA ADS",
"thesisType": "Masters thesis",
"url": "https://ui.adsabs.harvard.edu/abs/1997MsT...........B",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [
{
"tag": "Aerospace Environments"
},
{
"tag": "Astrophysics"
},
{
"tag": "Cosmic Rays"
},
{
"tag": "Degradation"
},
{
"tag": "Elliptical Orbits"
},
{
"tag": "Galactic Radiation"
},
{
"tag": "Geosynchronous Orbits"
},
{
"tag": "Low Earth Orbits"
},
{
"tag": "Radiation Belts"
},
{
"tag": "Radiation Effects"
},
{
"tag": "Satellite Design"
},
{
"tag": "Solar Activity"
},
{
"tag": "Solar Cells"
},
{
"tag": "Solar Corpuscular Radiation"
},
{
"tag": "Solar Storms"
},
{
"tag": "Unmanned Spacecraft"
}
],
"notes": [],

View File

@ -9,7 +9,7 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2016-08-27 10:23:44"
"lastUpdated": "2025-05-08 17:43:18"
}
/*
@ -93,6 +93,13 @@ function scrape(doc, url) {
//and another text node with the actual abstract.
var abstract = ZU.xpathText(doc, '//section[contains(@class,"abstract")]/text()[last()]');
item.abstractNote = abstract;
for (let jelCode of doc.querySelectorAll('.jel-codes .code')) {
let jelTag = jelCode.nextSibling;
if (jelTag && jelTag.textContent.trim()) {
item.tags.push({ tag: jelTag.textContent.trim() });
}
}
item.complete();
});
@ -102,7 +109,7 @@ function scrape(doc, url) {
}
/** BEGIN TEST CASES **/
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
@ -133,6 +140,7 @@ var testCases = [
"ISSN": "0895-3309",
"abstractNote": "As economists endeavor to build better models of human behavior, they cannot ignore that humans are fundamentally a social species with interaction patterns that shape their behaviors. People's opinions, which products they buy, whether they invest in education, become criminals, and so forth, are all influenced by friends and acquaintances. Ultimately, the full network of relationships—how dense it is, whether some groups are segregated, who sits in central positions—affects how information spreads and how people behave. Increased availability of data coupled with increased computing power allows us to analyze networks in economic settings in ways not previously possible. In this paper, I describe some of the ways in which networks are helping economists to model and understand behavior. I begin with an example that demonstrates the sorts of things that researchers can miss if they do not account for network patterns of interaction. Next I discuss a taxonomy of network properties and how they impact behaviors. Finally, I discuss the problem of developing tractable models of network formation.",
"issue": "4",
"language": "en",
"libraryCatalog": "www.aeaweb.org",
"pages": "3-22",
"publicationTitle": "Journal of Economic Perspectives",
@ -142,12 +150,46 @@ var testCases = [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
},
{
"title": "Snapshot"
}
],
"tags": [],
"tags": [
{
"tag": "Belief"
},
{
"tag": "Communication"
},
{
"tag": "Consumer Economics: Theory"
},
{
"tag": "Consumer Economics: Theory, Search"
},
{
"tag": "Economic Anthropology"
},
{
"tag": "Economic Sociology; Economic Anthropology; Social and Economic Stratification"
},
{
"tag": "Information and Knowledge"
},
{
"tag": "Learning"
},
{
"tag": "Network Formation and Analysis: Theory"
},
{
"tag": "Search; Learning; Information and Knowledge; Communication; Belief; Unawareness"
},
{
"tag": "Social and Economic Stratification"
},
{
"tag": "Unawareness, Network Formation and Analysis: Theory, Economic Sociology"
}
],
"notes": [],
"seeAlso": []
}
@ -177,6 +219,7 @@ var testCases = [
"ISSN": "0002-8282",
"abstractNote": "Using a model of statistical discrimination and educational sorting,\nwe explain why blacks get more education than whites of similar\ncognitive ability, and we explore how the Armed Forces Qualification\nTest (AFQT), wages, and education are related. The model suggests\nthat one should control for both AFQT and education when comparing\nthe earnings of blacks and whites, in which case a substantial\nblack-white wage differential emerges. We reject the hypothesis that\ndifferences in school quality between blacks and whites explain the\nwage and education differentials. Our findings support the view that\nsome of the black-white wage differential reflects the operation of the\nlabor market. (JEL I21, J15, J24, J31, J71)",
"issue": "4",
"language": "en",
"libraryCatalog": "www.aeaweb.org",
"pages": "1467-1496",
"publicationTitle": "American Economic Review",
@ -186,12 +229,43 @@ var testCases = [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
},
{
"title": "Snapshot"
}
],
"tags": [],
"tags": [
{
"tag": "Analysis of Education"
},
{
"tag": "Analysis of Education, Economics of Minorities and Races"
},
{
"tag": "Economics of Minorities and Races; Non-labor Discrimination"
},
{
"tag": "Human Capital; Skills; Occupational Choice; Labor Productivity"
},
{
"tag": "Labor Discrimination"
},
{
"tag": "Labor Productivity, Wage Level and Structure"
},
{
"tag": "Non-labor Discrimination, Human Capital"
},
{
"tag": "Occupational Choice"
},
{
"tag": "Skills"
},
{
"tag": "Wage Differentials, Labor Discrimination"
},
{
"tag": "Wage Level and Structure; Wage Differentials"
}
],
"notes": [],
"seeAlso": []
}
@ -221,6 +295,7 @@ var testCases = [
"ISSN": "0895-3309",
"abstractNote": "We can imagine a plausible case for government support of science based on traditional economic reasons of externalities and public goods. Yet when it comes to government support of grants from the National Science Foundation (NSF) for economic research, our sense is that many economists avoid critical questions, skimp on analysis, and move straight to advocacy. In this essay, we take a more skeptical attitude toward the efforts of the NSF to subsidize economic research. We offer two main sets of arguments. First, a key question is not whether NSF funding is justified relative to laissez-faire, but rather, what is the marginal value of NSF funding given already existing government and nongovernment support for economic research? Second, we consider whether NSF funding might more productively be shifted in various directions that remain within the legal and traditional purview of the NSF. Such alternative focuses might include data availability, prizes rather than grants, broader dissemination of economic insights, and more. Given these critiques, we suggest some possible ways in which the pattern of NSF funding, and the arguments for such funding, might be improved.",
"issue": "3",
"language": "en",
"libraryCatalog": "www.aeaweb.org",
"pages": "235-248",
"publicationTitle": "Journal of Economic Perspectives",
@ -230,16 +305,146 @@ var testCases = [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
},
{
"title": "Snapshot"
}
],
"tags": [],
"tags": [
{
"tag": "Higher Education; Research Institutions"
},
{
"tag": "Market for Economists, Higher Education"
},
{
"tag": "Research Institutions, Technological Change: Government Policy"
},
{
"tag": "Role of Economics"
},
{
"tag": "Role of Economics; Role of Economists; Market for Economists"
},
{
"tag": "Role of Economists"
},
{
"tag": "Technological Change: Government Policy"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.aeaweb.org/articles?id=10.1257/jel.20201641",
"items": [
{
"itemType": "journalArticle",
"title": "The 1918 Influenza Pandemic and Its Lessons for COVID-19",
"creators": [
{
"firstName": "Brian",
"lastName": "Beach",
"creatorType": "author"
},
{
"firstName": "Karen",
"lastName": "Clay",
"creatorType": "author"
},
{
"firstName": "Martin",
"lastName": "Saavedra",
"creatorType": "author"
}
],
"date": "2022/03",
"DOI": "10.1257/jel.20201641",
"ISSN": "0022-0515",
"abstractNote": "This article reviews the global health and economic consequences of the 1918 influenza pandemic, with a particular focus on topics that have seen a renewed interest because of COVID-19. We begin by providing an overview of key contextual and epidemiological details as well as the data that are available to researchers. We then examine the effects on mortality, fertility, and the economy in the short and medium run. The role of non-pharmaceutical interventions in shaping those outcomes is discussed throughout. We then examine longer-lasting health consequences and their impact on human capital accumulation and socioeconomic status. Throughout the paper we highlight important areas for future work.",
"issue": "1",
"language": "en",
"libraryCatalog": "www.aeaweb.org",
"pages": "41-84",
"publicationTitle": "Journal of Economic Literature",
"url": "https://www.aeaweb.org/articles?id=10.1257/jel.20201641",
"volume": "60",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [
{
"tag": "Aggregate Human Capital"
},
{
"tag": "Aggregate Labor Productivity, Business Fluctuations"
},
{
"tag": "Business Fluctuations; Cycles"
},
{
"tag": "Child Care"
},
{
"tag": "Children"
},
{
"tag": "Cycles, Health Behavior, Health and Economic Development, Fertility"
},
{
"tag": "Economic History: Labor and Consumers, Demography, Education, Health, Welfare, Income, Wealth, Religion, and Philanthropy: General, International, or Comparative"
},
{
"tag": "Employment"
},
{
"tag": "Employment; Unemployment; Wages; Intergenerational Income Distribution; Aggregate Human Capital; Aggregate Labor Productivity"
},
{
"tag": "Family Planning"
},
{
"tag": "Fertility; Family Planning; Child Care; Children; Youth"
},
{
"tag": "Health Behavior"
},
{
"tag": "Health and Economic Development"
},
{
"tag": "Human Capital; Skills; Occupational Choice; Labor Productivity"
},
{
"tag": "Intergenerational Income Distribution"
},
{
"tag": "Labor Productivity, Economic History: Labor and Consumers, Demography, Education, Health, Welfare, Income, Wealth, Religion, and Philanthropy: General, International, or Comparative"
},
{
"tag": "Occupational Choice"
},
{
"tag": "Skills"
},
{
"tag": "Unemployment"
},
{
"tag": "Wages"
},
{
"tag": "Youth, Human Capital"
}
],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/
/** END TEST CASES **/

313
AMS MathSciNet (Legacy).js Normal file
View File

@ -0,0 +1,313 @@
{
"translatorID": "a354331-981b-43de-a61-bc26dd1be3a9",
"label": "AMS MathSciNet (Legacy)",
"creator": "Simon Kornblith, Sebastian Karcher",
"target": "^https?://(mathscinet\\.)?ams\\.[^/]*/(mathscinet/2006/)?mathscinet(\\-getitem\\?|/search/(publications\\.html|publdoc\\.html))",
"minVersion": "3.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2023-07-06 17:03:34"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2015-2023 Simon Kornblith & Sebastian Karcher
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
function detectWeb(doc, _url) {
var itemType;
if (getSearchResults(doc, true)) {
return "multiple";
}
else if (ZU.xpathText(doc, '//div[@class="headlineMenu"]/*[last()-1]')) {
itemType = ZU.xpathText(doc, '//div[@class="headlineMenu"]/*[last()-1]');
switch (itemType.trim().toLowerCase()) {
case 'article':
return "journalArticle";
case 'book':
return "book";
case 'chapter':
return "bookSection";
}
}
return false;
}
function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
var rows = ZU.xpath(doc, '//div[@class="headlineText"]');
for (var i = 0; i < rows.length; i++) {
var href = ZU.xpathText(rows[i], './a[@class="mrnum"]/@href');
var title = ZU.xpathText(rows[i], './span[@class="title"]');
if (!href || !title) continue;
if (checkOnly) return true;
found = true;
items[href] = title;
}
return found ? items : false;
}
async function doWeb(doc, url) {
if (detectWeb(doc, url) == 'multiple') {
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(await requestDocument(url));
}
}
else {
await scrape(doc, url);
}
}
async function scrape(doc, url = doc.location.href) {
var host = url.match(/^(.+)\/mathscinet/);
var pub = host[0] + "/search/publications.html?fmt=bibtex";
var MR = ZU.xpathText(doc, '//div[@id="content"]/div[@class="doc"]/div[@class="headline"]/strong[1]');
pub += "&pg1=MR&s1=" + MR.replace(/^MR0*/, "");
let text = await requestText(pub);
var preRE = /<pre>\s*([\s\S]*?)\s*<\/pre>/g;
var bibTeXString = "";
var m;
//eslint-disable-next-line no-cond-assign
while (m = preRE.exec(text)) {
bibTeXString += m[1] + '\n';
}
// import using BibTeX
let translator = Zotero.loadTranslator("import");
translator.setTranslator("9cb70025-a888-4a29-a210-93ec52da40d4");
translator.setString(bibTeXString);
translator.setHandler("itemDone", function (obj, item) {
// Fix/fetch MR number
var mrnumber;
if (item.extra) {
item.extra = item.extra.replace(/^MR:\s*(?:MR)?(\d+).*/gm,
function (m, mr) {
mrnumber = mr;
return 'MR: ' + mr;
});
}
if (mrnumber) {
url = 'https://mathscinet.ams.org/mathscinet-getitem?mr=' + mrnumber;
}
item.attachments.push({ title: "MathSciNet Snapshot", document: doc });
item.url = url;
item.complete();
});
await translator.translate();
}
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "https://mathscinet.ams.org/mathscinet/search/publications.html?pg4=AUCN&s4=Karcher&co4=AND&pg5=TI&s5=&co5=AND&pg6=PC&s6=&co6=AND&pg7=ALLF&s7=&co7=AND&Submit=Search&dr=all&yrop=eq&arg3=&yearRangeFirst=&yearRangeSecond=&pg8=ET&s8=All&review_format=html",
"items": "multiple"
},
{
"type": "web",
"url": "https://mathscinet.ams.org/mathscinet/2006/mathscinet/search/publdoc.html?arg3=&co4=AND&co5=AND&co6=AND&co7=AND&dr=all&pg4=MR&pg5=TI&pg6=PC&pg7=ALLF&pg8=ET&r=1&review_format=html&s4=3004573",
"items": [
{
"itemType": "journalArticle",
"title": "Extrapolation of stable random fields",
"creators": [
{
"firstName": "Wolfgang",
"lastName": "Karcher",
"creatorType": "author"
},
{
"firstName": "Elena",
"lastName": "Shmileva",
"creatorType": "author"
},
{
"firstName": "Evgeny",
"lastName": "Spodarev",
"creatorType": "author"
}
],
"date": "2013",
"DOI": "10.1016/j.jmva.2012.11.004",
"ISSN": "0047-259X",
"extra": "MR: 3004573",
"itemID": "MR3004573",
"journalAbbreviation": "J. Multivariate Anal.",
"libraryCatalog": "AMS MathSciNet (Legacy)",
"pages": "516536",
"publicationTitle": "Journal of Multivariate Analysis",
"url": "https://mathscinet.ams.org/mathscinet-getitem?mr=3004573",
"volume": "115",
"attachments": [
{
"title": "MathSciNet Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://mathscinet.ams.org/mathscinet/search/publications.html?pg1=ISSI&s1=308850",
"items": "multiple"
},
{
"type": "web",
"url": "https://mathscinet.ams.org/mathscinet/2006/mathscinet/search/publdoc.html?arg3=&co4=AND&co5=AND&co6=AND&co7=AND&dr=all&pg4=MR&pg5=TI&pg6=PC&pg7=ALLF&pg8=ET&r=1&review_format=html&s4=2767535",
"items": [
{
"itemType": "bookSection",
"title": "On implementation of the Markov chain Monte Carlo stochastic approximation algorithm",
"creators": [
{
"firstName": "Yihua",
"lastName": "Jiang",
"creatorType": "author"
},
{
"firstName": "Peter",
"lastName": "Karcher",
"creatorType": "author"
},
{
"firstName": "Yuedong",
"lastName": "Wang",
"creatorType": "author"
}
],
"date": "2011",
"bookTitle": "Advances in directional and linear statistics",
"extra": "MR: 2767535\nDOI: 10.1007/978-3-7908-2628-9_7",
"itemID": "MR2767535",
"libraryCatalog": "AMS MathSciNet (Legacy)",
"pages": "97111",
"publisher": "Physica-Verlag/Springer, Heidelberg",
"url": "https://mathscinet.ams.org/mathscinet-getitem?mr=2767535",
"attachments": [
{
"title": "MathSciNet Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://mathscinet.ams.org/mathscinet/2006/mathscinet/search/publdoc.html?arg3=&co4=AND&co5=AND&co6=AND&co7=AND&dr=all&pg4=MR&pg5=TI&pg6=PC&pg7=ALLF&pg8=ET&r=1&review_format=html&s4=2663710",
"items": [
{
"itemType": "book",
"title": "Advances in directional and linear statistics",
"creators": [
{
"firstName": "Martin T.",
"lastName": "Wells",
"creatorType": "editor"
},
{
"firstName": "Ashis",
"lastName": "SenGupta",
"creatorType": "editor"
}
],
"date": "2011",
"ISBN": "9783790826272",
"extra": "MR: 2663710\nDOI: 10.1007/978-3-7908-2628-9",
"itemID": "MR2663710",
"libraryCatalog": "AMS MathSciNet (Legacy)",
"numPages": "xiv+321",
"publisher": "Physica-Verlag/Springer, Heidelberg",
"url": "https://mathscinet.ams.org/mathscinet-getitem?mr=2663710",
"attachments": [
{
"title": "MathSciNet Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [
{
"note": "<p>A Festschrift for Sreenivasa Rao Jammalamadaka</p>"
}
],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://mathscinet.ams.org/mathscinet-getitem?mr=1346201",
"items": [
{
"itemType": "journalArticle",
"title": "Sommation des séries divergentes",
"creators": [
{
"firstName": "Bernard",
"lastName": "Malgrange",
"creatorType": "author"
}
],
"date": "1995",
"ISSN": "0723-0869",
"extra": "MR: 1346201",
"issue": "2-3",
"itemID": "MR1346201",
"journalAbbreviation": "Exposition. Math.",
"libraryCatalog": "AMS MathSciNet",
"pages": "163222",
"publicationTitle": "Expositiones Mathematicae. International Journal",
"url": "https://mathscinet.ams.org/mathscinet-getitem?mr=1346201",
"volume": "13",
"attachments": [
{
"title": "MathSciNet Snapshot"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

View File

@ -1,45 +1,61 @@
{
"translatorID": "a354331-981b-43de-a61-bc26dd1be3a9",
"translatorID": "16f2936d-a059-40e8-a48e-f0acbb1e93e0",
"label": "AMS MathSciNet",
"creator": "Simon Kornblith",
"target": "^https?://(mathscinet\\.)?ams\\.[^/]*/mathscinet(\\-getitem\\?|/search/(publications\\.html|publdoc\\.html))",
"creator": "Sebastian Karcher",
"target": "^https?://mathscinet\\.ams\\.[^/]*/mathscinet/(article\\?|publications-search\\?|author\\?)",
"minVersion": "3.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2017-10-20 16:08:00"
"lastUpdated": "2023-07-14 11:04:37"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2023 Sebastian Karcher
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
function detectWeb(doc, url) {
var itemType;
if (getSearchResults(doc, true)) {
return "multiple"
} else if (itemType = ZU.xpathText(doc, '//div[@class="headlineMenu"]/*[last()-1]')) {
switch (itemType.trim().toLowerCase()) {
case 'article':
return "journalArticle";
case 'book':
return "book";
case 'chapter':
return "bookSection";
}
return "multiple";
}
else if (url.includes("article?mr=")) {
if (doc.querySelector('div[data-testid="ap-book-isbn"]')) {
if (doc.querySelector('div[data-testid="ap-book-collection"] a.router-link-active')) return "bookSection";
else return "book";
}
else return "journalArticle";
}
else return false;
}
function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
//TODO: adjust the xpath
var rows = ZU.xpath(doc, '//div[@class="headlineText"]');
for (var i=0; i<rows.length; i++) {
//TODO: check and maybe adjust
var href = ZU.xpathText(rows[i], './a[@class="mrnum"]/@href')
//TODO: check and maybe adjust
var title = ZU.xpathText(rows[i], './span[@class="title"]')
var rows = doc.querySelectorAll('.results div.font-weight-bold');
for (let row of rows) {
let href = attr(row, 'a', 'href');
let title = ZU.trimInternal(row.textContent);
if (!href || !title) continue;
if (checkOnly) return true;
found = true;
@ -48,74 +64,51 @@ function getSearchResults(doc, checkOnly) {
return found ? items : false;
}
function doWeb(doc, url) {
if (detectWeb(doc, url) == "multiple") {
Zotero.selectItems(getSearchResults(doc, false), function (items) {
if (!items) {
return true;
}
var articles = [];
for (var i in items) {
articles.push(i);
}
ZU.processDocuments(articles, scrape);
});
} else {
scrape(doc, url);
async function doWeb(doc, url) {
if (detectWeb(doc, url) == 'multiple') {
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(await requestDocument(url));
}
}
else {
await scrape(doc, url);
}
}
function scrape(doc, url) {
var host = url.match(/^(.+)\/mathscinet/)
var pub = host[0] + "/search/publications.html?fmt=bibtex";
var MR = ZU.xpathText(doc, '//div[@id="content"]/div[@class="doc"]/div[@class="headline"]/strong[1]');
pub += "&pg1=MR&s1="+MR.replace(/^MR0*/, "");
ZU.doGet(pub, function(text) {
var preRE = /<pre>\s*([\s\S]*?)\s*<\/pre>/g;
var bibTeXString = "";
var m;
while (m = preRE.exec(text)) {
bibTeXString += m[1] + '\n';
}
// import using BibTeX
var translator = Zotero.loadTranslator("import");
translator.setTranslator("9cb70025-a888-4a29-a210-93ec52da40d4");
translator.setString(bibTeXString);
translator.setHandler("itemDone", function(obj, item) {
// Fix/fetch MR number
var mrnumber;
if (item.extra) {
item.extra = item.extra.replace(/^MR:\s*(?:MR)?(\d+).*/gm,
function(m, mr) {
mrnumber = mr;
return 'MR: ' + mr;
});
}
if (mrnumber) {
url = 'https://mathscinet.ams.org/mathscinet-getitem?mr=' + mrnumber;
}
item.attachments.push({title: "MathSciNet Snapshot", document: doc});
item.url = url;
item.complete();
async function scrape(doc, url = doc.location.href) {
let id = url.match(/\?mr=(\d+)/);
if (!id) {
throw new Error("No MR ID, can't proceed");
}
let bibJSONUrl = '/mathscinet/api/publications/format?formats=bib&ids=' + id[1];
// Z.debug(bibJSONUrl)
let bibJSON = await requestText(bibJSONUrl);
// Z.debug(bibJSON)
bibJSON = JSON.parse(bibJSON);
let bibTex = bibJSON[0].bib;
// Z.debug(bibTex)
let translator = Zotero.loadTranslator("import");
translator.setTranslator('9cb70025-a888-4a29-a210-93ec52da40d4');
translator.setString(bibTex);
translator.setHandler('itemDone', (_obj, item) => {
item.url = ""; // these aren't full text URLs
item.attachments.push({
title: 'Snapshot',
document: doc
});
translator.translate();
item.complete();
});
await translator.translate();
}
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "https://mathscinet.ams.org/mathscinet/search/publications.html?pg4=AUCN&s4=Karcher&co4=AND&pg5=TI&s5=&co5=AND&pg6=PC&s6=&co6=AND&pg7=ALLF&s7=&co7=AND&Submit=Search&dr=all&yrop=eq&arg3=&yearRangeFirst=&yearRangeSecond=&pg8=ET&s8=All&review_format=html",
"items": "multiple"
},
{
"type": "web",
"url": "https://mathscinet.ams.org/mathscinet-getitem?mr=3004573",
"url": "https://mathscinet.ams.org/mathscinet/article?mr=3004573",
"items": [
{
"itemType": "journalArticle",
@ -139,18 +132,18 @@ var testCases = [
],
"date": "2013",
"DOI": "10.1016/j.jmva.2012.11.004",
"ISSN": "0047-259X",
"ISSN": "0047-259X,1095-7243",
"extra": "MR: 3004573",
"itemID": "MR3004573",
"journalAbbreviation": "J. Multivariate Anal.",
"libraryCatalog": "AMS MathSciNet",
"pages": "516536",
"publicationTitle": "Journal of Multivariate Analysis",
"url": "https://mathscinet.ams.org/mathscinet-getitem?mr=3004573",
"volume": "115",
"attachments": [
{
"title": "MathSciNet Snapshot"
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
@ -161,12 +154,7 @@ var testCases = [
},
{
"type": "web",
"url": "https://mathscinet.ams.org/mathscinet/search/publications.html?pg1=ISSI&s1=308850",
"items": "multiple"
},
{
"type": "web",
"url": "https://mathscinet.ams.org/mathscinet-getitem?mr=2767535",
"url": "https://mathscinet.ams.org/mathscinet/article?mr=2767535",
"items": [
{
"itemType": "bookSection",
@ -189,16 +177,17 @@ var testCases = [
}
],
"date": "2011",
"ISBN": "9783790826272",
"bookTitle": "Advances in directional and linear statistics",
"extra": "MR: 2767535\nDOI: 10.1007/978-3-7908-2628-9_7",
"itemID": "MR2767535",
"libraryCatalog": "AMS MathSciNet",
"pages": "97111",
"publisher": "Physica-Verlag/Springer, Heidelberg",
"url": "https://mathscinet.ams.org/mathscinet-getitem?mr=2767535",
"attachments": [
{
"title": "MathSciNet Snapshot"
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
@ -206,10 +195,10 @@ var testCases = [
"seeAlso": []
}
]
},
},
{
"type": "web",
"url": "https://mathscinet.ams.org/mathscinet-getitem?mr=2663710",
"url": "https://mathscinet.ams.org/mathscinet/article?mr=2663710",
"items": [
{
"itemType": "book",
@ -233,10 +222,10 @@ var testCases = [
"libraryCatalog": "AMS MathSciNet",
"numPages": "xiv+321",
"publisher": "Physica-Verlag/Springer, Heidelberg",
"url": "https://mathscinet.ams.org/mathscinet-getitem?mr=2663710",
"attachments": [
{
"title": "MathSciNet Snapshot"
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
@ -251,7 +240,7 @@ var testCases = [
},
{
"type": "web",
"url": "https://mathscinet.ams.org/mathscinet-getitem?mr=1346201",
"url": "https://mathscinet.ams.org/mathscinet/article?mr=1346201",
"items": [
{
"itemType": "journalArticle",
@ -272,11 +261,11 @@ var testCases = [
"libraryCatalog": "AMS MathSciNet",
"pages": "163222",
"publicationTitle": "Expositiones Mathematicae. International Journal",
"url": "https://mathscinet.ams.org/mathscinet-getitem?mr=1346201",
"volume": "13",
"attachments": [
{
"title": "MathSciNet Snapshot"
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
@ -284,6 +273,16 @@ var testCases = [
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://mathscinet.ams.org/mathscinet/publications-search?query=karcher&page=1&size=20&sort=newest&facets=",
"items": "multiple"
},
{
"type": "web",
"url": "https://mathscinet.ams.org/mathscinet/author?authorId=98350",
"items": "multiple"
}
]
/** END TEST CASES **/

View File

@ -9,7 +9,7 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2022-11-02 16:50:48"
"lastUpdated": "2025-03-10 19:48:42"
}
/*
@ -52,12 +52,12 @@ function detectWeb(doc, url) {
|| url.includes('/fulltext/')
|| url.includes('/buy/')
|| url.includes('/doiLanding?doi=')) {
if (doc.getElementById('bookchapterstoc')) {
return "book";
}
else if (attr(doc, 'meta[property="og:type"]', 'content') == 'Chapter') {
if (attr(doc, 'meta[name="og:type"]', 'content') == 'Chapter') {
return "bookSection";
}
else if (doc.getElementById('bookchapterstoc')) {
return "book";
}
else {
return "journalArticle";
}
@ -91,9 +91,9 @@ async function doWeb(doc, url) {
if (!items) {
return;
}
await Promise.all(
Object.keys(items).map(async url => scrape(await requestDocument(url), url))
);
for (let url of Object.keys(items)) {
await scrape(await requestDocument(url), url);
}
}
else {
await scrape(doc, url);
@ -132,7 +132,7 @@ async function scrape(doc, url) {
var postData = JSON.stringify({
api: "record.exportRISFile",
params: {
UIDList: [{UID: uid, ProductCode: productCode}],
UIDList: [{ UID: uid, ProductCode: productCode }],
exportType: "zotero"
}
});
@ -151,7 +151,7 @@ async function scrape(doc, url) {
// 2. Download the requested data (after step 1)
let data = await requestText('/ris/download');
if (data.includes('Content: application/x-research-info-systems')) {
processRIS(data, doc);
await processRIS(data, doc);
}
else {
// sometimes (e.g. during testing) the data is not loaded
@ -165,7 +165,34 @@ async function scrape(doc, url) {
}
function processRIS(text, doc) {
async function processRIS(text, doc) {
let pdfURL = attr(doc, 'a[href*="/fulltext"]', 'href');
if (!pdfURL) {
Zotero.debug('Fetching institution ID for PDF');
try {
let uid = doc.location.pathname.match(/\/(?:record|fulltext)\/([^/.]+)/)[1];
let { institution } = await requestJSON(
'https://psycnet.apa.org/api/request/institution.getInstitutionByIpAddress', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
api: 'institution.getInstitutionByIpAddress',
params: { uid }
})
}
);
if (institution) {
pdfURL = `https://psycnet.apa.org/fulltext/${uid}.pdf?auth_id=${institution.ringGoldId}&returnUrl=${encodeURIComponent(doc.location.href)}`;
}
}
catch (e) {
Zotero.debug('Failed to fetch institution ID');
Zotero.debug(e);
}
}
var translator = Zotero.loadTranslator("import");
translator.setTranslator("32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7");
translator.setString(text);
@ -176,10 +203,12 @@ function processRIS(text, doc) {
if (item.series) item.series = cleanTitle(item.series);
if (item.place) item.place = item.place.replace(/\s+/g, ' ');
if (item.ISSN) item.ISSN = ZU.cleanISSN(item.ISSN);
if (item.pages && item.pages.includes('No Pagination Specified')) {
delete item.pages;
}
for (var i = 0; i < item.tags.length; i++) {
item.tags[i] = item.tags[i].replace(/^\*/, '');
}
var pdfURL = attr(doc, 'a[href*="/fulltext"]', 'href');
if (pdfURL) {
item.attachments.push({
url: pdfURL,
@ -187,19 +216,21 @@ function processRIS(text, doc) {
mimeType: "application/pdf"
});
}
item.attachments.push({
title: "Snapshot",
document: doc
});
else {
item.attachments.push({
title: "Snapshot",
document: doc
});
}
item.complete();
});
translator.translate();
await translator.translate();
}
// try to figure out ids that we can use for fetching RIS
async function getIds(doc, url) {
Z.debug('Finding IDs in ' + url)
Z.debug('Finding IDs in ' + url);
// try to extract uid from the table
var uid = text(doc, '#uid + dd') || text(doc, '#bookUID');
if (uid) {
@ -207,8 +238,8 @@ async function getIds(doc, url) {
}
// try to extract uid from the url
if (url.includes('/record/')) {
let m = url.match(/\/record\/([\d-]*)/);
if (url.includes('/record/') || url.includes('/fulltext/')) {
let m = url.match(/\/(?:record|fulltext)\/([\d-]*)/);
if (m && m[1]) {
return m[1];
}
@ -313,7 +344,7 @@ function cleanTitle(title) {
var testCases = [
{
"type": "web",
"url": "http://psycnet.apa.org/record/2004-16644-010",
"url": "https://psycnet.apa.org/record/2004-16644-010",
"items": [
{
"itemType": "journalArticle",
@ -337,17 +368,18 @@ var testCases = [
],
"date": "2004",
"DOI": "10.1037/0894-4105.18.3.485",
"ISSN": "1931-1559(Electronic),0894-4105(Print)",
"abstractNote": "A comprehensive, empirically based review of the published studies addressing neuropsychological performance in adults diagnosed with attention-deficit/hyperactivity disorder (ADHD) was conducted to identify patterns of performance deficits. Findings from 33 published studies were submitted to a meta-analytic procedure producing sample-size-weighted mean effect sizes across test measures. Results suggest that neuropsychological deficits are expressed in adults with ADHD across multiple domains of functioning, with notable impairments in attention, behavioral inhibition, and memory, whereas normal performance is noted in simple reaction time. Theoretical and developmental considerations are discussed, including the role of behavioral inhibition and working memory impairment. Future directions for research based on these findings are highlighted, including further exploration of specific impairments and an emphasis on particular tests and testing conditions. (PsycINFO Database Record (c) 2016 APA, all rights reserved)",
"ISSN": "1931-1559",
"abstractNote": "A comprehensive, empirically based review of the published studies addressing neuropsychological performance in adults diagnosed with attention-deficit/hyperactivity disorder (ADHD) was conducted to identify patterns of performance deficits. Findings from 33 published studies were submitted to a meta-analytic procedure producing sample-size-weighted mean effect sizes across test measures. Results suggest that neuropsychological deficits are expressed in adults with ADHD across multiple domains of functioning, with notable impairments in attention, behavioral inhibition, and memory, whereas normal performance is noted in simple reaction time. Theoretical and developmental considerations are discussed, including the role of behavioral inhibition and working memory impairment. Future directions for research based on these findings are highlighted, including further exploration of specific impairments and an emphasis on particular tests and testing conditions. (PsycInfo Database Record (c) 2022 APA, all rights reserved)",
"issue": "3",
"libraryCatalog": "APA PsycNET",
"libraryCatalog": "APA PsycNet",
"pages": "485-503",
"publicationTitle": "Neuropsychology",
"shortTitle": "Neuropsychology of Adults With Attention-Deficit/Hyperactivity Disorder",
"volume": "18",
"attachments": [
{
"title": "Snapshot"
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [
@ -364,7 +396,7 @@ var testCases = [
"tag": "Experimentation"
},
{
"tag": "Hyperkinesis"
"tag": "Hyperactivity"
},
{
"tag": "Inhibition (Personality)"
@ -386,7 +418,7 @@ var testCases = [
},
{
"type": "web",
"url": "http://psycnet.apa.org/record/1956-05944-001",
"url": "https://psycnet.apa.org/record/1956-05944-001",
"items": [
{
"itemType": "journalArticle",
@ -405,16 +437,17 @@ var testCases = [
],
"date": "1955",
"DOI": "10.1037/h0043965",
"ISSN": "0022-1015(Print)",
"ISSN": "0022-1015",
"abstractNote": "Two factor analytic studies of meaningful judgments based upon the same sample of 50 bipolar descriptive scales are reported. Both analyses reveal three major connotative factors: evaluation, potency, and activity. These factors appear to be independent dimensions of the semantic space within which the meanings of concepts may be specified. (PsycINFO Database Record (c) 2016 APA, all rights reserved)",
"issue": "5",
"libraryCatalog": "APA PsycNET",
"libraryCatalog": "APA PsycNet",
"pages": "325-338",
"publicationTitle": "Journal of Experimental Psychology",
"volume": "50",
"attachments": [
{
"title": "Snapshot"
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [
@ -441,7 +474,8 @@ var testCases = [
},
{
"type": "web",
"url": "http://psycnet.apa.org/record/1992-98221-010",
"url": "https://psycnet.apa.org/record/1992-98221-010",
"defer": true,
"items": [
{
"itemType": "bookSection",
@ -460,9 +494,9 @@ var testCases = [
],
"date": "1977",
"ISBN": "9780716703686 9780716703679",
"abstractNote": "tonic immobility [animal hypnosis] might be a useful laboratory analog or research model for catatonia / we have been collaborating on an interdisciplinary program of research in an effort to pinpoint the behavioral antecedents and biological bases for tonic immobility / attempt to briefly summarize our findings, and . . . discuss the implications of these data in terms of the model characteristics of tonic immobility / hypnosis / catatonia, catalepsy, and cataplexy / tonic immobility as a model for catatonia / fear potentiation / fear alleviation / fear or arousal / learned helplessness / neurological correlates / pharmacology and neurochemistry / genetic underpinnings / evolutionary considerations / implications for human psychopathology (PsycINFO Database Record (c) 2016 APA, all rights reserved)",
"abstractNote": "tonic immobility [animal hypnosis] might be a useful laboratory analog or research model for catatonia / we have been collaborating on an interdisciplinary program of research in an effort to pinpoint the behavioral antecedents and biological bases for tonic immobility / attempt to briefly summarize our findings, and . . . discuss the implications of these data in terms of the model characteristics of tonic immobility / hypnosis / catatonia, catalepsy, and cataplexy / tonic immobility as a model for catatonia / fear potentiation / fear alleviation / fear or arousal / learned helplessness / neurological correlates / pharmacology and neurochemistry / genetic underpinnings / evolutionary considerations / implications for human psychopathology (PsycInfo Database Record (c) 2022 APA, all rights reserved)",
"bookTitle": "Psychopathology: Experimental models",
"libraryCatalog": "APA PsycNET",
"libraryCatalog": "APA PsycNet",
"pages": "334-357",
"place": "New York, NY, US",
"publisher": "W H Freeman/Times Books/ Henry Holt & Co",
@ -470,7 +504,8 @@ var testCases = [
"shortTitle": "Catatonia",
"attachments": [
{
"title": "Snapshot"
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [
@ -506,7 +541,8 @@ var testCases = [
},
{
"type": "web",
"url": "http://psycnet.apa.org/record/2004-16329-000?doi=1",
"url": "https://psycnet.apa.org/record/2004-16329-000?doi=1",
"defer": true,
"items": [
{
"itemType": "book",
@ -519,9 +555,9 @@ var testCases = [
}
],
"date": "1948",
"abstractNote": "The author's intent is to write about abnormal people in a way that will be valuable and interesting to students new to the subject. A first course in abnormal psychology is not intended to train specialists. Its goal is more general: it should provide the student with the opportunity to whet his interest, expand his horizons, register a certain body of new facts, and relate this to the rest of his knowledge about mankind. I have tried to present the subject in such a way as to emphasize its usefulness to all students of human nature. I have tried the experiment of writing two introductory chapters, one historical and the other clinical. This reflects my desire to set the subject-matter in a broad perspective and at the same time to anchor it in concrete fact. Next comes a block of six chapters designed to set forth the topics of maladjustment and neurosis. The two chapters on psychotherapy complete the more purely psychological or developmental part of the work. In the final chapter the problem of disordered personalities is allowed to expand to its full social dimensions. Treatment, care, and prevention call for social effort and social organization. I have sought to show some of the lines, both professional and nonprofessional, along which this effort can be expended. (PsycINFO Database Record (c) 2016 APA, all rights reserved)",
"abstractNote": "The author's intent is to write about abnormal people in a way that will be valuable and interesting to students new to the subject. A first course in abnormal psychology is not intended to train specialists. Its goal is more general: it should provide the student with the opportunity to whet his interest, expand his horizons, register a certain body of new facts, and relate this to the rest of his knowledge about mankind. I have tried to present the subject in such a way as to emphasize its usefulness to all students of human nature. I have tried the experiment of writing two introductory chapters, one historical and the other clinical. This reflects my desire to set the subject-matter in a broad perspective and at the same time to anchor it in concrete fact. Next comes a block of six chapters designed to set forth the topics of maladjustment and neurosis. The two chapters on psychotherapy complete the more purely psychological or developmental part of the work. In the final chapter the problem of disordered personalities is allowed to expand to its full social dimensions. Treatment, care, and prevention call for social effort and social organization. I have sought to show some of the lines, both professional and nonprofessional, along which this effort can be expended. (PsycInfo Database Record (c) 2022 APA, all rights reserved)",
"extra": "DOI: 10.1037/10023-000",
"libraryCatalog": "APA PsycNET",
"libraryCatalog": "APA PsycNet",
"numPages": "x, 617",
"place": "New York, NY, US",
"publisher": "Ronald Press Company",
@ -529,7 +565,8 @@ var testCases = [
"shortTitle": "The abnormal personality",
"attachments": [
{
"title": "Snapshot"
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [
@ -542,9 +579,99 @@ var testCases = [
}
]
},
{
"type": "web",
"url": "https://psycnet.apa.org/fulltext/2022-40433-002.html",
"items": [
{
"itemType": "journalArticle",
"title": "Expertise in emotion: A scoping review and unifying framework for individual differences in the mental representation of emotional experience",
"creators": [
{
"lastName": "Hoemann",
"firstName": "Katie",
"creatorType": "author"
},
{
"lastName": "Nielson",
"firstName": "Catie",
"creatorType": "author"
},
{
"lastName": "Yuen",
"firstName": "Ashley",
"creatorType": "author"
},
{
"lastName": "Gurera",
"firstName": "J. W.",
"creatorType": "author"
},
{
"lastName": "Quigley",
"firstName": "Karen S.",
"creatorType": "author"
},
{
"lastName": "Barrett",
"firstName": "Lisa Feldman",
"creatorType": "author"
}
],
"date": "2021",
"DOI": "10.1037/bul0000327",
"ISSN": "1939-1455",
"abstractNote": "Expertise refers to outstanding skill or ability in a particular domain. In the domain of emotion, expertise refers to the observation that some people are better at a range of competencies related to understanding and experiencing emotions, and these competencies may help them lead healthier lives. These individual differences are represented by multiple constructs including emotional awareness, emotional clarity, emotional complexity, emotional granularity, and emotional intelligence. These constructs derive from different theoretical perspectives, highlight different competencies, and are operationalized and measured in different ways. The full set of relationships between these constructs has not yet been considered, hindering scientific progress and the translation of findings to aid mental and physical well-being. In this article, we use a scoping review procedure to integrate these constructs within a shared conceptual space. Scoping reviews provide a principled means of synthesizing large and diverse literature in a transparent fashion, enabling the identification of similarities as well as gaps and inconsistencies across constructs. Using domain-general accounts of expertise as a guide, we build a unifying framework for expertise in emotion and apply this to constructs that describe how people understand and experience their own emotions. Our approach offers opportunities to identify potential mechanisms of expertise in emotion, encouraging future research on those mechanisms and on educational or clinical interventions. (PsycInfo Database Record (c) 2023 APA, all rights reserved)",
"issue": "11",
"libraryCatalog": "APA PsycNet",
"pages": "1159-1183",
"publicationTitle": "Psychological Bulletin",
"shortTitle": "Expertise in emotion",
"volume": "147",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [
{
"tag": "Alexithymia"
},
{
"tag": "Awareness"
},
{
"tag": "Conceptual Imagery"
},
{
"tag": "Creativity"
},
{
"tag": "Emotional Intelligence"
},
{
"tag": "Emotions"
},
{
"tag": "Experience Level"
},
{
"tag": "Experiences (Events)"
},
{
"tag": "Individual Differences"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "http://psycnet.apa.org/buy/2004-16329-002",
"defer": true,
"items": [
{
"itemType": "bookSection",
@ -585,7 +712,7 @@ var testCases = [
},
{
"type": "web",
"url": "http://psycnet.apa.org/buy/2010-19350-001",
"url": "https://psycnet.apa.org/record/2010-19350-001",
"items": [
{
"itemType": "journalArticle",
@ -619,16 +746,17 @@ var testCases = [
],
"date": "2010",
"DOI": "10.1037/a0020280",
"ISSN": "1939-2222(Electronic),0096-3445(Print)",
"ISSN": "1939-2222",
"abstractNote": "Social scientists often rely on economic experiments such as ultimatum and dictator games to understand human cooperation. Systematic deviations from economic predictions have inspired broader conceptions of self-interest that incorporate concerns for fairness. Yet no framework can describe all of the major results. We take a different approach by asking players directly about their self-interest—defined as what they want to do (pleasure-maximizing options). We also ask players directly about their sense of fairness—defined as what they think they ought to do (fairness-maximizing options). Player-defined measures of self-interest and fairness predict (a) the majority of ultimatum-game and dictator-game offers, (b) ultimatum-game rejections, (c) exiting behavior (i.e., escaping social expectations to cooperate) in the dictator game, and (d) who cooperates more after a positive mood induction. Adopting the players' perspectives of self-interest and fairness permits better predictions about who cooperates, why they cooperate, and when they punish noncooperators. (PsycINFO Database Record (c) 2016 APA, all rights reserved)",
"issue": "4",
"libraryCatalog": "APA PsycNET",
"libraryCatalog": "APA PsycNet",
"pages": "743-755",
"publicationTitle": "Journal of Experimental Psychology: General",
"volume": "139",
"attachments": [
{
"title": "Snapshot"
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [
@ -658,7 +786,8 @@ var testCases = [
},
{
"type": "web",
"url": "http://psycnet.apa.org/record/2010-09295-002",
"url": "https://psycnet.apa.org/record/2010-09295-002",
"defer": true,
"items": [
{
"itemType": "bookSection",
@ -672,17 +801,18 @@ var testCases = [
],
"date": "2011",
"ISBN": "9781433808616 9781433808623",
"abstractNote": "In this chapter, I seek to redress vocational psychologys inattention to the self and address the ambiguity of the meaning of self. To begin, I offer a chronological survey of vocational psychologys three main views of human singularity. During succeeding historical eras, different aspects of human singularity interested vocational psychologists, so they developed a new set of terms and concepts to deal with shifts in the meaning of individuality. Over time, vocational psychology developed what Kuhn (2000) referred to as language communities, each with its own paradigm for understanding the self and vocational behavior. Because the self is fundamentally ambiguous, adherents to each paradigm describe it with an agreed on language and metaphors. Thus, each paradigm has a textual tradition, or way of talking about the self. As readers shall see, when they talk about individuals, differentialists use the language of personality, developmentalists use the language of personhood, and constructionists use the language of identity. (PsycINFO Database Record (c) 2017 APA, all rights reserved)",
"abstractNote": "In this chapter, I seek to redress vocational psychologys inattention to the self and address the ambiguity of the meaning of self. To begin, I offer a chronological survey of vocational psychologys three main views of human singularity. During succeeding historical eras, different aspects of human singularity interested vocational psychologists, so they developed a new set of terms and concepts to deal with shifts in the meaning of individuality. Over time, vocational psychology developed what Kuhn (2000) referred to as language communities, each with its own paradigm for understanding the self and vocational behavior. Because the self is fundamentally ambiguous, adherents to each paradigm describe it with an agreed on language and metaphors. Thus, each paradigm has a textual tradition, or way of talking about the self. As readers shall see, when they talk about individuals, differentialists use the language of personality, developmentalists use the language of personhood, and constructionists use the language of identity. (PsycInfo Database Record (c) 2024 APA, all rights reserved)",
"bookTitle": "Developing self in work and career: Concepts, cases, and contexts",
"extra": "DOI: 10.1037/12348-002",
"libraryCatalog": "APA PsycNET",
"libraryCatalog": "APA PsycNet",
"pages": "17-33",
"place": "Washington, DC, US",
"publisher": "American Psychological Association",
"shortTitle": "The self in vocational psychology",
"attachments": [
{
"title": "Snapshot"
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [
@ -700,6 +830,86 @@ var testCases = [
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://psycnet.apa.org/record/2025-80032-001?doi=1",
"items": [
{
"itemType": "journalArticle",
"title": "Linking adolescent bullying perpetration with adult fertility: Two preliminary studies",
"creators": [
{
"lastName": "Volk",
"firstName": "Anthony A.",
"creatorType": "author"
},
{
"lastName": "Brazil",
"firstName": "Kristopher J.",
"creatorType": "author"
},
{
"lastName": "Dane",
"firstName": "Andrew V.",
"creatorType": "author"
},
{
"lastName": "Vaillancourt",
"firstName": "Tracy",
"creatorType": "author"
},
{
"lastName": "Al-Jbouri",
"firstName": "Elizabeth",
"creatorType": "author"
},
{
"lastName": "Farrell",
"firstName": "Ann H.",
"creatorType": "author"
}
],
"date": "2025",
"DOI": "10.1037/ebs0000374",
"ISSN": "2330-2933",
"abstractNote": "Researchers have suggested that bullying perpetration is, at least in part, an evolved adaptation. A key prediction of this evolutionary perspective is that bullying facilitates the transmission of genes from one generation to the next. To date, only one study (using a limited measure of bullying) has examined the link between adolescent bullying and adult fertility, showing a positive association between adolescent bullying and number of children in adulthood. We sought to replicate and expand this unique finding using a more robust measure of adolescent bullying and young adults parental status in a prospective longitudinal study of Canadians (Study 1), along with an MTurk study of retrospective adolescent bullying and current adult fertility (Study 2). In support of an evolutionary theory of bullying, we found that higher bullying was associated with having children in young adulthood (ages 23 and/or 24 years, Study 1) and that retrospective reports of adolescent bullying were associated with having more children in adulthood (Study 2). Overall, our studies offer additional support for the idea that adolescent bullying is, at least in part, an evolutionary adaptation that may help individuals to later pass on their genes to future generations through enhanced reproductive and perhaps parental effort. Although needing replication, our data highlight the importance of considering reproductive outcomes when designing future bullying research or interventions. (PsycInfo Database Record (c) 2025 APA, all rights reserved)",
"libraryCatalog": "APA PsycNet",
"publicationTitle": "Evolutionary Behavioral Sciences",
"shortTitle": "Linking adolescent bullying perpetration with adult fertility",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [
{
"tag": "Adaptation"
},
{
"tag": "Adolescent Characteristics"
},
{
"tag": "Bullying"
},
{
"tag": "Fertility"
},
{
"tag": "Genes"
},
{
"tag": "Parenthood Status"
},
{
"tag": "Theory of Evolution"
}
],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

228
APS.js
View File

@ -1,7 +1,7 @@
{
"translatorID": "2c310a37-a4dd-48d2-82c9-bd29c53c1c76",
"label": "APS",
"creator": "Aurimas Vinckevicius",
"creator": "Aurimas Vinckevicius and Abe Jellinek",
"target": "^https?://journals\\.aps\\.org/([^/]+/(abstract|supplemental|references|cited-by|issues)/|search(\\?|/))",
"minVersion": "3.0.12",
"maxVersion": "",
@ -9,24 +9,52 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2017-01-14 21:44:41"
"lastUpdated": "2024-11-21 18:50:09"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2024 Aurimas Vinckevicius and Abe Jellinek
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
function detectWeb(doc, url) {
var title = doc.getElementById('title');
if (title && ZU.xpath(title, './/a[@id="export-article-link"]').length) {
if (doc.querySelector('#article-body #export-article-dialog')
|| doc.querySelector('main#main') && /^\/[^/]+\/(abstract|supplemental|references|cited-by)\//.test(new URL(url).pathname)) {
return "journalArticle";
} else if (getSearchResults(doc, true)){
}
else if (getSearchResults(doc, true)) {
return "multiple";
}
return false;
}
function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
var rows = ZU.xpath(doc, '//div[contains(@class, "search-results")]//div[contains(@class, "row")]//h5/a');
for (var i=0; i<rows.length; i++) {
var rows = doc.querySelectorAll('#issue-body .headline .title > a');
if (!rows.length) {
rows = doc.querySelectorAll('#search-main h3 > a');
}
for (var i = 0; i < rows.length; i++) {
var href = rows[i].href;
var title = ZU.trimInternal(cleanMath(rows[i].textContent));
if (!href || !title) continue;
@ -42,7 +70,7 @@ function doWeb(doc, url) {
if (detectWeb(doc, url) == "multiple") {
Zotero.selectItems(getSearchResults(doc, false), function (items) {
if (!items) {
return true;
return;
}
var articles = [];
for (var i in items) {
@ -50,7 +78,8 @@ function doWeb(doc, url) {
}
ZU.processDocuments(articles, scrape);
});
} else {
}
else {
scrape(doc, url);
}
}
@ -58,13 +87,13 @@ function doWeb(doc, url) {
// Extension to mimeType mapping
var suppTypeMap = {
'pdf': 'application/pdf',
'zip': 'application/zip',
'doc': 'application/msword',
'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'xls': 'application/vnd.ms-excel',
'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'mov': 'video/quicktime'
pdf: 'application/pdf',
zip: 'application/zip',
doc: 'application/msword',
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
xls: 'application/vnd.ms-excel',
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
mov: 'video/quicktime'
};
var dontDownload = [
@ -75,20 +104,20 @@ var dontDownload = [
function scrape(doc, url) {
url = url.replace(/[?#].*/, '');
if (url.indexOf('/abstract/') == -1) {
if (!url.includes('/abstract/')) {
// Go to Abstract page first so we can scrape the abstract
url = url.replace(/\/(?:supplemental|references|cited-by)\//, '/abstract/');
if (url.indexOf('/abstract/') == -1) {
if (!url.includes('/abstract/')) {
Zotero.debug('Unrecognized URL ' + url);
return;
}
ZU.processDocuments(url, function(doc, url) {
if (url.indexOf('/abstract/') == -1) {
ZU.processDocuments(url, function (doc, url) {
if (!url.includes('/abstract/')) {
Zotero.debug('Redirected when trying to go to abstract page. ' + url);
return;
}
scrape(doc, url)
scrape(doc, url);
});
return;
}
@ -97,26 +126,23 @@ function scrape(doc, url) {
// fetch RIS
var risUrl = url.replace('{REPLACE}', 'export')
+ '?type=ris&download=true';
ZU.doGet(risUrl, function(text) {
text = text.replace(/^ID\s+-\s+/mg, 'DO - ');
+ '?type=ris&download=true';
ZU.doGet(risUrl, function (risText) {
risText = risText.replace(/^ID\s+-\s+/mg, 'DO - ');
var trans = Zotero.loadTranslator('import');
trans.setTranslator('32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7'); //RIS
trans.setString(text);
trans.setHandler('itemDone', function(obj, item) {
trans.setString(risText);
trans.setHandler('itemDone', function (obj, item) {
// scrape abstract from page
item.abstractNote = ZU.trimInternal(cleanMath(
ZU.xpathText(doc, '//section[contains(@class,"abstract")]/div[@class="content"]/p[1]')
text(doc, '#abstract-section-content p')
));
// attach PDF
if (ZU.xpath(doc, '//div[@class="article-nav-actions"]/a[contains(text(), "PDF")]').length) {
item.attachments.push({
title: 'Full Text PDF',
url: url.replace('{REPLACE}', 'pdf'),
mimeType: 'application/pdf'
});
}
item.attachments.push({
title: 'Full Text PDF',
url: url.replace('{REPLACE}', 'pdf'),
mimeType: 'application/pdf'
});
item.attachments.push({
title: "APS Snapshot",
@ -124,38 +150,37 @@ function scrape(doc, url) {
});
if (Z.getHiddenPref && Z.getHiddenPref('attachSupplementary')) {
ZU.processDocuments(url.replace('{REPLACE}', 'supplemental'), function(doc) {
try {
var asLink = Z.getHiddenPref('supplementaryAsLink');
var suppFiles = doc.getElementsByClassName('supplemental-file');
for (var i=0; i<suppFiles.length; i++) {
var link = suppFiles[i].getElementsByTagName('a')[0];
if (!link || !link.href) continue;
var title = link.getAttribute('data-id') || 'Supplementary Data';
var type = suppTypeMap[link.href.split('.').pop()];
if (asLink || dontDownload.indexOf(type) != -1) {
item.attachments.push({
title: title,
url: link.href,
mimeType: type || 'text/html',
snapshot: false
});
} else {
item.attachments.push({
title: title,
url: link.href,
mimeType: type
});
}
try {
var asLink = Z.getHiddenPref('supplementaryAsLink');
var suppFiles = doc.querySelectorAll('.supplemental-file');
for (let suppFile of suppFiles) {
let link = suppFile.querySelector('a');
if (!link || !link.href) continue;
var title = link.getAttribute('data-id') || 'Supplementary Data';
var type = suppTypeMap[link.href.split('.').pop()];
if (asLink || dontDownload.includes(type)) {
item.attachments.push({
title: title,
url: link.href,
mimeType: type || 'text/html',
snapshot: false
});
}
else {
item.attachments.push({
title: title,
url: link.href,
mimeType: type
});
}
} catch (e) {
Z.debug('Could not attach supplemental data');
Z.debug(e);
}
}, function() { item.complete() });
} else {
item.complete();
}
catch (e) {
Z.debug('Could not attach supplemental data');
Z.debug(e);
}
}
item.complete();
});
trans.translate();
});
@ -165,6 +190,7 @@ function cleanMath(str) {
//math tags appear to have duplicate content and are somehow left in even after textContent
return str.replace(/<(math|mi)[^<>]*>.*?<\/\1>/g, '');
}
/** BEGIN TEST CASES **/
var testCases = [
{
@ -186,7 +212,7 @@ var testCases = [
"creatorType": "author"
}
],
"date": "October 21, 2011",
"date": "2011-10-21",
"DOI": "10.1103/PhysRevD.84.077701",
"abstractNote": "We reconsider Higgs boson invisible decays into Dark Matter in the light of recent Higgs searches at the LHC. Present hints in the Compact Muon Solenoid and ATLAS data favor a nonstandard Higgs boson with approximately 50% invisible branching ratio, and mass around 143 GeV. This situation can be realized within the simplest thermal scalar singlet Dark Matter model, predicting a Dark Matter mass around 50 GeV and direct detection cross section just below present bound. The present runs of the Xenon100 and LHC experiments can test this possibility.",
"issue": "7",
@ -202,7 +228,8 @@ var testCases = [
"mimeType": "application/pdf"
},
{
"title": "APS Snapshot"
"title": "APS Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
@ -260,9 +287,9 @@ var testCases = [
"creatorType": "author"
}
],
"date": "March 4, 2015",
"date": "2015-03-04",
"DOI": "10.1103/PhysRevLett.114.098105",
"abstractNote": "Cellular aggregates (spheroids) are widely used in biophysics and tissue engineering as model systems for biological tissues. In this Letter we propose novel methods for molding stem-cell spheroids, deforming them, and measuring their interfacial and elastic properties with a single method based on cell tagging with magnetic nanoparticles and application of a magnetic field gradient. Magnetic molding yields spheroids of unprecedented sizes (up to a few mm in diameter) and preserves tissue integrity. On subjecting these spheroids to magnetic flattening (over 150g), we observed a size-dependent elastocapillary transition with two modes of deformation: liquid-drop-like behavior for small spheroids, and elastic-sphere-like behavior for larger spheroids, followed by relaxation to a liquidlike drop.",
"abstractNote": "Cellular aggregates (spheroids) are widely used in biophysics and tissue engineering as model systems for biological tissues. In this Letter we propose novel methods for molding stem-cell spheroids, deforming them, and measuring their interfacial and elastic properties with a single method based on cell tagging with magnetic nanoparticles and application of a magnetic field gradient. Magnetic molding yields spheroids of unprecedented sizes (up to a few mm in diameter) and preserves tissue integrity. On subjecting these spheroids to magnetic flattening (over ), we observed a size-dependent elastocapillary transition with two modes of deformation: liquid-drop-like behavior for small spheroids, and elastic-sphere-like behavior for larger spheroids, followed by relaxation to a liquidlike drop.",
"issue": "9",
"journalAbbreviation": "Phys. Rev. Lett.",
"libraryCatalog": "APS",
@ -276,7 +303,8 @@ var testCases = [
"mimeType": "application/pdf"
},
{
"title": "APS Snapshot"
"title": "APS Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
@ -319,7 +347,7 @@ var testCases = [
"creatorType": "author"
}
],
"date": "March 17, 2015",
"date": "2015-03-17",
"DOI": "10.1103/PhysRevX.5.011029",
"abstractNote": "Based on first-principle calculations, we show that a family of nonmagnetic materials including TaAs, TaP, NbAs, and NbP are Weyl semimetals (WSM) without inversion centers. We find twelve pairs of Weyl points in the whole Brillouin zone (BZ) for each of them. In the absence of spin-orbit coupling (SOC), band inversions in mirror-invariant planes lead to gapless nodal rings in the energy-momentum dispersion. The strong SOC in these materials then opens full gaps in the mirror planes, generating nonzero mirror Chern numbers and Weyl points off the mirror planes. The resulting surface-state Fermi arc structures on both (001) and (100) surfaces are also obtained, and they show interesting shapes, pointing to fascinating playgrounds for future experimental studies.",
"issue": "1",
@ -335,7 +363,8 @@ var testCases = [
"mimeType": "application/pdf"
},
{
"title": "APS Snapshot"
"title": "APS Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
@ -378,7 +407,7 @@ var testCases = [
"creatorType": "author"
}
],
"date": "March 17, 2015",
"date": "2015-03-17",
"DOI": "10.1103/PhysRevX.5.011029",
"abstractNote": "Based on first-principle calculations, we show that a family of nonmagnetic materials including TaAs, TaP, NbAs, and NbP are Weyl semimetals (WSM) without inversion centers. We find twelve pairs of Weyl points in the whole Brillouin zone (BZ) for each of them. In the absence of spin-orbit coupling (SOC), band inversions in mirror-invariant planes lead to gapless nodal rings in the energy-momentum dispersion. The strong SOC in these materials then opens full gaps in the mirror planes, generating nonzero mirror Chern numbers and Weyl points off the mirror planes. The resulting surface-state Fermi arc structures on both (001) and (100) surfaces are also obtained, and they show interesting shapes, pointing to fascinating playgrounds for future experimental studies.",
"issue": "1",
@ -394,7 +423,8 @@ var testCases = [
"mimeType": "application/pdf"
},
{
"title": "APS Snapshot"
"title": "APS Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
@ -437,7 +467,7 @@ var testCases = [
"creatorType": "author"
}
],
"date": "January 20, 2015",
"date": "2015-01-20",
"DOI": "10.1103/PhysRevX.5.011003",
"abstractNote": "We report on a stringent test of the nonclassicality of the motion of a massive quantum particle, which propagates on a discrete lattice. Measuring temporal correlations of the position of single atoms performing a quantum walk, we observe a 6σ violation of the Leggett-Garg inequality. Our results rigorously excludes (i.e., falsifies) any explanation of quantum transport based on classical, well-defined trajectories. We use so-called ideal negative measurements—an essential requisite for any genuine Leggett-Garg test—to acquire information about the atoms position, yet avoiding any direct interaction with it. The interaction-free measurement is based on a novel atom transport system, which allows us to directly probe the absence rather than the presence of atoms at a chosen lattice site. Beyond the fundamental aspect of this test, we demonstrate the application of the Leggett-Garg correlation function as a witness of quantum superposition. Here, we employ the witness to discriminate different types of walks spanning from merely classical to wholly quantum dynamics.",
"issue": "1",
@ -453,7 +483,53 @@ var testCases = [
"mimeType": "application/pdf"
},
{
"title": "APS Snapshot"
"title": "APS Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://journals.aps.org/pra/abstract/10.1103/PhysRevA.65.032314",
"items": [
{
"itemType": "journalArticle",
"title": "Computable measure of entanglement",
"creators": [
{
"lastName": "Vidal",
"firstName": "G.",
"creatorType": "author"
},
{
"lastName": "Werner",
"firstName": "R. F.",
"creatorType": "author"
}
],
"date": "2002-02-22",
"DOI": "10.1103/PhysRevA.65.032314",
"abstractNote": "We present a measure of entanglement that can be computed effectively for any mixed state of an arbitrary bipartite system. We show that it does not increase under local manipulations of the system, and use it to obtain a bound on the teleportation capacity and on the distillable entanglement of mixed states.",
"issue": "3",
"journalAbbreviation": "Phys. Rev. A",
"libraryCatalog": "APS",
"pages": "032314",
"publicationTitle": "Physical Review A",
"url": "https://link.aps.org/doi/10.1103/PhysRevA.65.032314",
"volume": "65",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
},
{
"title": "APS Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
@ -463,4 +539,4 @@ var testCases = [
]
}
]
/** END TEST CASES **/
/** END TEST CASES **/

File diff suppressed because one or more lines are too long

View File

@ -2,14 +2,14 @@
"translatorID": "d120a8a7-9d45-446e-8c18-ad9ef0a6bf47",
"label": "Access Engineering",
"creator": "Vinoth K - highwirepress.com",
"target": "^https?://www\\.accessengineeringlibrary\\.com/content/(book|chapter|case-study|video|calculator|tutorial)",
"target": "^https?://www\\.accessengineeringlibrary\\.com/",
"minVersion": "3.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2023-03-07 08:48:13"
"lastUpdated": "2023-09-09 09:42:36"
}
/*
@ -97,13 +97,16 @@ function scrape(doc, url) {
if (edition) item.edition = edition;
// Author
let author = ZU.xpath(doc, '//ul[@class="contributor-list"]//li//a');
if (author.length > 0) {
// Handled using data attribute
for (let i = 0; i < author.length; i++) {
item.creators[i].firstName = author[i].getAttribute('data-firstnames');
item.creators[i].lastName = author[i].getAttribute('data-surname');
}
// Some of old pages not having firstname, lastname seperation in markup and ignore if not
let author = doc.querySelectorAll("ul.contributor-list > [data-firstnames]");
item.creators = [];
for (let i = 0; i < author.length; i++) {
let creatorData = author[i].dataset;
item.creators.push({
firstName: creatorData.firstnames,
lastName: creatorData.surname,
creatorType: creatorData.authortype
});
}
// Abstract
@ -116,12 +119,7 @@ function scrape(doc, url) {
translator.getTranslatorObject(function (trans) {
// Detect web not get trigger for scape EM translator
// - so wll fill those in manually.
if (detectWeb(doc, url)) {
trans.itemType = detectWeb(doc, url);
}
trans.addCustomFields({
citation_book_title: "bookTitle"
});
trans.itemType = detectWeb(doc, url);
trans.doWeb(doc, url);
});
}
@ -130,26 +128,51 @@ function scrape(doc, url) {
var testCases = [
{
"type": "web",
"url": "https://www.accessengineeringlibrary.com/content/book/9781259860386/",
"url": "https://www.accessengineeringlibrary.com/content/book/9781259860225",
"items": [
{
"itemType": "book",
"title": "3D Printer Projects for Makerspaces",
"title": "Handbook of Environmental Engineering",
"creators": [
{
"firstName": "Lydia Sloan",
"lastName": "Cline",
"creatorType": "author"
"firstName": "Rao Y.",
"lastName": "Surampalli",
"creatorType": "editor"
},
{
"firstName": "Tian C.",
"lastName": "Zhang",
"creatorType": "editor"
},
{
"firstName": "Satinder Kaur",
"lastName": "Brar",
"creatorType": "editor"
},
{
"firstName": "Krishnamoorthy",
"lastName": "Hegde",
"creatorType": "editor"
},
{
"firstName": "Rama",
"lastName": "Pulicharla",
"creatorType": "editor"
},
{
"firstName": "Mausam",
"lastName": "Verma",
"creatorType": "editor"
}
],
"date": "2017",
"ISBN": "9781259860386",
"abstractNote": "Learn to model and print 3D designs—no experience required!This easy-to-follow guide features twenty 3D printing projects for makers of all skill levels to enjoy. Written in a tutorial, step-by-step manner, 3D Printer Projects for Makerspaces shows how to use Fusion 360, SketchUp, Meshmixer, Remake, and Inkscape to create fun and useful things. Scanning, slicers, silicone molds, settings, and build plate orientation are also covered, as well as post-processing methods that will make your prints really pop!Inside, you9ll learn to model, analyze, and print a:• Phone case• Coin bank• Art stencil• Cookie cutter• Cookie dunker• Personalized key fob• Lens cap holder• Lithophane night-light• Pencil cup with applied sketch• Business card with QR code• Bronze pendant• Soap mold• Hanging lampshade• Scanned Buddha charm• And more!",
"date": "2018",
"ISBN": "9781259860225",
"abstractNote": "A complete guide to environmental regulations and remediation.This practical resource offers thorough coverage of current environmental issues and policies along with step-by-step remediation procedures. With contributions from dozens of industry-recognized experts, Handbook of Environmental Engineering features information on all segments of the market—including water and air quality and hazardous waste—and enables you to ensure compliance with all applicable regulations. You will get details about sensors, monitoring, and toxicity treatment and controls as well as waste management and safe disposal. Real-world examples demonstrate how to apply techniques and achieve compliance, while environmental impact assessments and measurement data enhance the book9s utility.Coverage includes:• Environmental legislation• Environmental impact assessments• Air pollution control and management• Potable water treatment• Wastewater treatment and reuse• Solid waste management• Hazardous waste management• Emerging wastes in the environment• Environmental monitoring and measurements",
"edition": "1st Edition",
"language": "en",
"libraryCatalog": "www.accessengineeringlibrary.com",
"publisher": "McGraw-Hill Education",
"url": "https://www.accessengineeringlibrary.com/content/book/9781259860386",
"url": "https://www.accessengineeringlibrary.com/content/book/9781259860225",
"attachments": [
{
"title": "Full Text PDF",
@ -164,28 +187,61 @@ var testCases = [
},
{
"type": "web",
"url": "https://www.accessengineeringlibrary.com/content/book/9781259860386/chapter/chapter12",
"url": "https://www.accessengineeringlibrary.com/content/book/9781259860225/toc-chapter/chapter3/section/section1",
"items": [
{
"itemType": "bookSection",
"title": "PROJECT 12: Lithophane Night-Light",
"title": "CHAPTER PRELIMINARIES",
"creators": [
{
"firstName": "Lydia Sloan",
"lastName": "Cline",
"firstName": "Ashok",
"lastName": "Kumar",
"creatorType": "author"
},
{
"firstName": "Hamid",
"lastName": "Omidvarborna",
"creatorType": "author"
},
{
"firstName": "Rao Y.",
"lastName": "Surampalli",
"creatorType": "editor"
},
{
"firstName": "Tian C.",
"lastName": "Zhang",
"creatorType": "editor"
},
{
"firstName": "Satinder Kaur",
"lastName": "Brar",
"creatorType": "editor"
},
{
"firstName": "Krishnamoorthy",
"lastName": "Hegde",
"creatorType": "editor"
},
{
"firstName": "Rama",
"lastName": "Pulicharla",
"creatorType": "editor"
},
{
"firstName": "Mausam",
"lastName": "Verma",
"creatorType": "editor"
}
],
"date": "2017",
"ISBN": "9781259860386",
"abstractNote": "Learn to model and print 3D designs—no experience required!This easy-to-follow guide features twenty 3D printing projects for makers of all skill levels to enjoy. Written in a tutorial, step-by-step manner, 3D Printer Projects for Makerspaces shows how to use Fusion 360, SketchUp, Meshmixer, Remake, and Inkscape to create fun and useful things. Scanning, slicers, silicone molds, settings, and build plate orientation are also covered, as well as post-processing methods that will make your prints really pop!Inside, you'll learn to model, analyze, and print a:• Phone case• Coin bank• Art stencil• Cookie cutter• Cookie dunker• Personalized key fob• Lens cap holder• Lithophane night-light• Pencil cup with applied sketch• Business card with QR code• Bronze pendant• Soap mold• Hanging lampshade• Scanned Buddha charm• And more!",
"bookTitle": "3D Printer Projects for Makerspaces",
"edition": "1st Edition",
"date": "2018",
"ISBN": "9781259860225",
"abstractNote": "A complete guide to environmental regulations and remediation.This practical resource offers thorough coverage of current environmental issues and policies along with step-by-step remediation procedures. With contributions from dozens of industry-recognized experts, Handbook of Environmental Engineering features information on all segments of the market—including water and air quality and hazardous waste—and enables you to ensure compliance with all applicable regulations. You will get details about sensors, monitoring, and toxicity treatment and controls as well as waste management and safe disposal. Real-world examples demonstrate how to apply techniques and achieve compliance, while environmental impact assessments and measurement data enhance the book's utility.Coverage includes:• Environmental legislation• Environmental impact assessments• Air pollution control and management• Potable water treatment• Wastewater treatment and reuse• Solid waste management• Hazardous waste management• Emerging wastes in the environment• Environmental monitoring and measurements",
"bookTitle": "Handbook of Environmental Engineering",
"language": "en",
"libraryCatalog": "www.accessengineeringlibrary.com",
"publisher": "McGraw-Hill Education",
"shortTitle": "PROJECT 12",
"url": "https://www.accessengineeringlibrary.com/content/book/9781259860386/chapter/chapter12",
"url": "https://www.accessengineeringlibrary.com/content/book/9781259860225/toc-chapter/chapter3/section/section1",
"attachments": [
{
"title": "Snapshot",
@ -200,24 +256,19 @@ var testCases = [
},
{
"type": "web",
"url": "https://www.accessengineeringlibrary.com/content/video/V4768153299001",
"url": "https://www.accessengineeringlibrary.com/content/video/V4005352521001",
"items": [
{
"itemType": "videoRecording",
"title": "10% Infill and a Bridge",
"creators": [
{
"firstName": "Lydia",
"lastName": "Cline",
"creatorType": "author"
}
],
"date": "2016",
"abstractNote": "This video shows an item being printed with a 10% infill and includes a bridge.",
"title": "123D Design: Cut Text Through a Plane",
"creators": [],
"date": "2014",
"abstractNote": "This video shows how to cut text through a plane with Combine/Subtract.",
"language": "en",
"libraryCatalog": "www.accessengineeringlibrary.com",
"shortTitle": "123D Design",
"studio": "McGraw-Hill Education",
"url": "https://www.accessengineeringlibrary.com/content/video/V4768153299001",
"url": "https://www.accessengineeringlibrary.com/content/video/V4005352521001",
"attachments": [
{
"title": "Snapshot",
@ -232,23 +283,23 @@ var testCases = [
},
{
"type": "web",
"url": "https://www.accessengineeringlibrary.com/content/calculator/S0018_Analysis_of_AC_and_DC_Circuits_Basic_Calculations",
"url": "https://www.accessengineeringlibrary.com/content/calculator/S0071_Basic_Transformer_Calculations",
"items": [
{
"itemType": "journalArticle",
"title": "Analysis of A.C. and D.C. Circuits - Basic Calculations",
"title": "Basic Transformer Calculations",
"creators": [
{
"firstName": "William",
"lastName": "Prudhomme",
"firstName": "Bhagyalakshmi",
"lastName": "Kerekare",
"creatorType": "author"
}
],
"date": "2018/12/13/",
"abstractNote": "Software simulation programs are generally used for modeling and designing complex electronic circuits and applications, but frequently only a basic calculation is needed to solve an immediate design problem or to calculate the value of a specific circuit element. This Excel workbook addresses this need by automating the calculation of over 70 basic electronics formulas in direct current (d.c.) and alternating current (a.c.) circuits and applications.",
"date": "2022/06/25/",
"abstractNote": "This Excel workbook contains four worksheets. The first worksheet covers the basic concepts of single phase transformer such as turns ratio, primary current, secondary current, primary voltage, secondary voltage, and transformer ratio calculations. The second worksheet covers the basic concepts of power, efficiency, primary/secondary EMF and transformer rating calculations. The third worksheet covers the basic concepts of three phase transformers, highlighting the star and delta connections. Calculations are done for phase voltage, phase current, line voltage, and line current for star and delta connections. The fourth worksheet covers the basic concepts kVA Ratings, 3-phase primary, and secondary full load current 3-phase voltage calculations.",
"language": "en",
"libraryCatalog": "www.accessengineeringlibrary.com",
"url": "https://www.accessengineeringlibrary.com/content/calculator/S0018_Analysis_of_AC_and_DC_Circuits_Basic_Calculations",
"url": "https://www.accessengineeringlibrary.com/content/calculator/S0071_Basic_Transformer_Calculations",
"attachments": [
{
"title": "Snapshot",
@ -295,23 +346,23 @@ var testCases = [
},
{
"type": "web",
"url": "https://www.accessengineeringlibrary.com/content/tutorial/T0002_Open_Channel_Flow_Calculations_with_the_Manning_Equation",
"url": "https://www.accessengineeringlibrary.com/content/tutorial/T0004_Partially_Full_Pipe_Flow_Calculations_Using_Excel_Spreadsheets",
"items": [
{
"itemType": "journalArticle",
"title": "Open Channel Flow Calculations with the Manning Equation using Excel Spreadsheets",
"title": "Partially Full Pipe Flow Calculations Using Excel Spreadsheets",
"creators": [
{
"firstName": "Harlan",
"lastName": "H. Bengtson",
"firstName": "Harlan H.",
"lastName": "Bengtson",
"creatorType": "author"
}
],
"date": "2014-02-01",
"abstractNote": "This tutorial teaches the Manning equation and its use for uniform open channel flow calculations, including the hydraulic radius, Manning roughness coefficient, and normal depth. There are example problems and illustrations show how to use spreadsheets for the calculations.",
"date": "2014/02/01/",
"abstractNote": "This tutorial provides discussion of, and illustration by, examples for use of an Excel spreadsheet for making a variety of calculations for the flow of water in a partially full circular pipe using the Manning Equation. Equations for calculating area, wetted perimeter, and hydraulic radius for partially full pipe flow are included in this tutorial along with a brief review of the Manning Equation and discussion of its use to calculate a) the flow rate in a given pipe (given diameter, slope, &amp; Manning roughness) at a specified depth of flow, b) the required diameter for a specified flow rate at a target percent full in a given pipe, and c) the normal depth (depth of flow) for a specified flow rate in a given pipe. This includes presentation and discussion of the equations for the calculations, example calculations, and screenshots of spreadsheets to facilitate the calculations.",
"language": "en",
"libraryCatalog": "www.accessengineeringlibrary.com",
"url": "https://www.accessengineeringlibrary.com/content/tutorial/T0002_Open_Channel_Flow_Calculations_with_the_Manning_Equation",
"url": "https://www.accessengineeringlibrary.com/content/tutorial/T0004_Partially_Full_Pipe_Flow_Calculations_Using_Excel_Spreadsheets",
"attachments": [
{
"title": "Snapshot",

391
Access Science.js Normal file
View File

@ -0,0 +1,391 @@
{
"translatorID": "558330ca-3531-467a-8003-86cd9602cc48",
"label": "Access Science",
"creator": "Vinoth K - highwirepress.com",
"target": "^https?://www\\.accessscience\\.com/",
"minVersion": "5.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2023-10-17 20:19:39"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2023 Vinoth K - highwirepress.com
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
function detectWeb(doc, url) {
let title = attr(doc, 'meta[name="citation_title"]', 'content');
if (title) {
if (doc.querySelector('meta[name="citation_isbn"]')) {
let bookTitle = attr(doc, 'meta[name="citation_book_title"]', 'content');
if (!bookTitle || title == bookTitle) {
return "book";
}
else {
return "bookSection";
}
}
else if (url.includes('content/video/') || url.includes('content/video-biography')) {
return 'videoRecording';
}
else if (url.includes('content/article/')) {
return "journalArticle";
}
else if (url.includes('news') || url.includes('briefing')) {
return "magazineArticle";
}
else {
return "webpage";
}
}
else if (getSearchResults(doc, true)) {
return "multiple";
}
return false;
}
function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
var rows = doc.querySelectorAll('.search-middle-right a[href]');
for (let row of rows) {
let href = row.href;
let title = ZU.trimInternal(row.textContent);
if (!href || !title) continue;
if (checkOnly) return true;
found = true;
items[href] = title;
}
return found ? items : false;
}
function doWeb(doc, url) {
if (detectWeb(doc, url) == "multiple") {
Zotero.selectItems(getSearchResults(doc, false), function (items) {
if (items) ZU.processDocuments(Object.keys(items), scrape);
});
}
else {
scrape(doc, url);
}
}
function scrape(doc, url) {
var translator = Zotero.loadTranslator('web');
// Embedded Metadata
translator.setTranslator('951c027d-74ac-47d4-a107-9c3069ab7b48');
translator.setDocument(doc);
translator.setHandler('itemDone', function (obj, item) {
// Author
// Some of video pages having old content which does not contain the
// firstname and lastname. which is binding in a single string in
// metadata tags, So those cases we were split and mapped accordingly
if (item.itemType == 'videoRecording') {
let authorName = attr(doc, 'meta[name="citation_author"]', 'content');
if (authorName) {
item.creators = [];
if (authorName.includes(',') && authorName.split(',').length > 2) {
authorName = authorName.split(',')[0];
item.creators.push(ZU.cleanAuthor(authorName, "author", false));
}
}
}
let abstractNote = attr(doc, 'meta[name="citation_abstract"]', 'content');
item.abstractNote = abstractNote && ZU.cleanTags(abstractNote);
item.complete();
});
translator.getTranslatorObject(function (trans) {
trans.itemType = detectWeb(doc, url);
trans.doWeb(doc, url);
});
}
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "https://www.accessscience.com/content/book/9781260452297",
"items": [
{
"itemType": "book",
"title": "Casarett & Doull's Essentials of Toxicology",
"creators": [
{
"firstName": "Curtis D.",
"lastName": "Klaassen",
"creatorType": "editor"
},
{
"firstName": "John B. Watkins",
"lastName": "Iii",
"creatorType": "editor"
}
],
"date": "2022",
"ISBN": "9781260452297",
"abstractNote": "Doody9s Core Titles for 2021!\n\nFor more than 25 years, Casarett &amp; Doull9s Toxicology: The Basic Science of Poisons has set the standard for providing thorough, academic, and authoritative information in clear and engaging ways. Distilling the major principles and concepts from that renowned text, Casarett &amp; Doull9s Essentials of Toxicology delivers an accessible and highly readable introduction to the science and clinical field of medical toxicology. The book reflects the expertise of more than 60 renowned contributors.\n\nPresented in full-color, this new edition builds on the wide success of previous editions, with extensive updates that make the book more clinically relevant to students and beginners in toxicology, pharmacology, pharmacy, and environmental sciences. Chapter-ending self-assessment Q&amp;As and other features make the learning process more effective and efficient.\n\nCasarett and Doull9s Essentials of Toxicology is organized into seven units:\n\n• General Principles of Toxicology\n\n• Disposition of Toxicants\n\n• Nonorgan-directed Toxicity\n\n• Target Organ Toxicity\n\n• Toxic Agents\n\n• Environmental Toxicology\n\n• Applications of Toxicology\n\nSuccinct, yet comprehensive, the text covers essential principles, toxicokinetics, how toxic effects are passed on to succeeding generations, how each body system responds to poisons, and the specific effects of a wide range of toxic agents—from pesticides to radiation.",
"language": "en",
"libraryCatalog": "www.accessscience.com",
"publisher": "McGraw Hill",
"url": "https://www.accessscience.com/content/book/9781260452297",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.accessscience.com/content/book/9781260452297/chapter/chapter2",
"items": [
{
"itemType": "bookSection",
"title": "Principles of Toxicology",
"creators": [
{
"firstName": "Lauren M.",
"lastName": "Aleksunes",
"creatorType": "author"
},
{
"firstName": "David L.",
"lastName": "Eaton",
"creatorType": "author"
},
{
"firstName": "Curtis D.",
"lastName": "Klaassen",
"creatorType": "editor"
},
{
"firstName": "John B. Watkins",
"lastName": "Iii",
"creatorType": "editor"
}
],
"date": "2022",
"ISBN": "9781260452297",
"bookTitle": "Casarett & Doull's Essentials of Toxicology",
"language": "en",
"libraryCatalog": "www.accessscience.com",
"publisher": "McGraw Hill",
"url": "https://www.accessscience.com/content/book/9781260452297/chapter/chapter2",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.accessscience.com/content/video/V2537194263001",
"items": [
{
"itemType": "videoRecording",
"title": "Supplementary Problem 10.12",
"creators": [
{
"firstName": "Rebecca B.",
"lastName": "DeVasher",
"creatorType": "author"
}
],
"date": "2013",
"abstractNote": "This video details a problem involving unit cells and the calculation of the mass of a cell, length of a cell and radius of an atom in the unit cell based on the density of a solid.",
"language": "en",
"libraryCatalog": "www.accessscience.com",
"studio": "McGraw Hill",
"url": "https://www.accessscience.com/content/video/V2537194263001",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.accessscience.com/content/video-biography/VB0014",
"items": [
{
"itemType": "videoRecording",
"title": "Anderson, John R.",
"creators": [],
"date": "2011",
"language": "en",
"libraryCatalog": "www.accessscience.com",
"studio": "McGraw Hill",
"url": "https://www.accessscience.com/content/video-biography/VB0014",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.accessscience.com/content/article/a694300?implicit-login=true",
"items": [
{
"itemType": "journalArticle",
"title": "3D printing",
"creators": [
{
"firstName": "Wenchao",
"lastName": "Zhou",
"creatorType": "author"
}
],
"date": "2023",
"DOI": "10.1036/1097-8542.694300",
"language": "en",
"libraryCatalog": "www.accessscience.com",
"url": "https://www.accessscience.com/content/article/a694300",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.accessscience.com/content/news/aSN2301171?implicit-login=true",
"items": [
{
"itemType": "magazineArticle",
"title": "These chemists cracked the code to long-lasting Roman concrete",
"creators": [
{
"firstName": "Carolyn",
"lastName": "Gramling",
"creatorType": "author"
}
],
"date": "2023",
"extra": "DOI: 10.1036/1097-8542.SN0000000",
"language": "en",
"libraryCatalog": "www.accessscience.com",
"url": "https://www.accessscience.com/content/news/aSN2301171",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.accessscience.com/content/video/an600010",
"items": [
{
"itemType": "videoRecording",
"title": "Henrietta Leavitt: The Woman Who Measured the Universe",
"creators": [],
"abstractNote": "Born in 1868, Henrietta Leavitt was an astronomer ahead of her time, whose work helped to revolutionize our understanding of the universe. While working at Harvard Observatory, Leavitt began to study stars of fluctuating brightness. This video describes her crucial observation about variable stars, which gave astronomers a new way to measure distances, ultimately leading to such impactful discoveries as the expansion of the universe.\n\nCredit: ESA Hubble Videos; Hubblecast 116: Henrietta Leavitt — ahead of her time; Directed by: Mathias Jäger; Visual design and editing: Martin Kornmesser; Written by: Sara Rigby; Narration: Sara Mendes da Costa; Images: ESA/Hubble and NASA, ESO, Hubble Heritage Team (STScI/AURA), Library of Congress Prints and Photographs Division Washington, Harvard College Observatory, Huntington Library, California Institute of Technology, Digitized Sky Survey 2, M. Kornmesser, R. Gendler, Arnold Reinhold, Davide De Martin; Videos: NASA, ESA, M. Kornmesser, Luis Calcada; Music: Johan B. Monell; Web and technical support: Mathias André and Raquel Yumi Shida; Executive producer: Lars Lindberg Christensen",
"language": "en",
"libraryCatalog": "www.accessscience.com",
"shortTitle": "Henrietta Leavitt",
"studio": "McGraw Hill",
"url": "https://www.accessscience.com/content/video/an600010",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.accessscience.com/content/biography/m0073908",
"items": [
{
"itemType": "webpage",
"title": "Abbe, Cleveland (18381916)",
"creators": [],
"language": "en",
"url": "https://www.accessscience.com/content/biography/m0073908",
"websiteTitle": "McGraw Hill's AccessScience",
"websiteType": "text",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.accessscience.com/search?query=&items_per_page=10",
"items": "multiple"
}
]
/** END TEST CASES **/

723
Airiti.js

File diff suppressed because one or more lines are too long

View File

@ -9,7 +9,7 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2021-08-04 18:27:28"
"lastUpdated": "2023-07-24 02:21:59"
}
/*
@ -43,7 +43,11 @@ function detectWeb(doc, url) {
if (urlRe.test(url)) {
return "magazineArticle";
}
else if (getSearchResults(doc, true)) {
let appElem = doc.querySelector("app-root");
if (appElem) {
Z.monitorDOMChanges(appElem);
}
if (getSearchResults(doc, true)) {
return "multiple";
}
return false;
@ -52,11 +56,9 @@ function detectWeb(doc, url) {
function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
var rows = doc.querySelectorAll('td > a[href*="/Articles/"]');
var rows = doc.querySelectorAll('td > a[href^="/Articles/"], th > a[href^="/Articles/"]');
for (let row of rows) {
// TODO: check and maybe adjust
let href = row.href;
// TODO: check and maybe adjust
let title = ZU.trimInternal(row.textContent);
if (!href || !title) continue;
if (checkOnly) return true;
@ -66,45 +68,47 @@ function getSearchResults(doc, checkOnly) {
return found ? items : false;
}
function doWeb(doc, url) {
async function doWeb(doc, url) {
if (detectWeb(doc, url) == "multiple") {
Zotero.selectItems(getSearchResults(doc, false), function (items) {
if (items) ZU.processDocuments(Object.keys(items), scrape);
});
let items = await Z.selectItems(getSearchResults(doc));
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(null, url);
}
}
else {
scrape(doc, url);
await scrape(doc, url);
}
}
function scrape(doc, url) {
async function scrape(doc, url) {
let item = new Zotero.Item('magazineArticle');
let [, MID, IID, AID] = url.match(urlRe);
ZU.doGet(`${apiBase}/Search/IssueHInfo?MID=${MID}&IID=${IID}`, function (respText) {
let issue = JSON.parse(respText);
ZU.doGet(`${apiBase}/Search/ArticleHInfo?AID=${AID}`, function (respText) {
let article = JSON.parse(respText);
let issue = await requestJSON(`${apiBase}/Search/IssueHInfo?MID=${MID}&IID=${IID}`);
let article = await requestJSON(`${apiBase}/Search/ArticleHInfo?AID=${AID}`);
item.title = article.articleTitle.replace(' : ', ": ");
item.pages = article.pageNo;
item.creators.push(ZU.cleanAuthor(article.articleAuthor, 'author'));
item.publicationTitle = issue.magazineArabicName;
item.place = issue.countryName;
item.issue = issue.issuenumber || issue.issueName;
item.date = ZU.strToISO(arabicToEnglishDate(issue.newIssueDate));
item.url = url;
item.attachments.push({
title: 'Snapshot',
document: doc
});
item.complete();
});
});
item.title = article.articleTitle.replace(' : ', ": ");
item.pages = article.pageNo;
item.creators.push(ZU.cleanAuthor(article.articleAuthor, 'author'));
item.publicationTitle = issue.magazineArabicName;
item.place = issue.countryName;
item.issue = issue.issuenumber || issue.issueName;
item.date = ZU.strToISO(arabicToEnglishDate(issue.newIssueDate));
item.url = url;
let attachment = { title: "Snapshot" };
if (doc) {
attachment.document = doc;
}
else {
attachment.url = url;
}
item.attachments.push(attachment);
item.complete();
}
// just so we get months on non-Arabic locales
@ -226,6 +230,12 @@ var testCases = [
{
"type": "web",
"url": "https://archive.alsharekh.org/contents/174/19785",
"defer": true,
"items": "multiple"
},
{
"type": "web",
"url": "https://archive.alsharekh.org/AuthorArticles/124",
"items": "multiple"
}
]

View File

@ -9,7 +9,7 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2022-12-15 05:18:20"
"lastUpdated": "2025-03-20 15:38:12"
}
function detectWeb(doc, _url) {
@ -279,8 +279,10 @@ function scrape(doc, url) {
)];
}
if (!role) role = 'author';
name = ZU.trimInternal(ZU.xpathText(authors[i], './span/a[contains(@class, "a-link-normal")]|./a[contains(@class, "a-link-normal")]'))
.replace(/\s*\([^)]+\)/, '').replace(/,\s*$/, '');
name = ZU.trimInternal(
ZU.xpathText(authors[i], './span/a[contains(@class, "a-link-normal")]|./a[contains(@class, "a-link-normal")]')
|| text(authors[i], ':scope > span > a[data-a-component="text-link"]')
).replace(/\s*\([^)]+\)/, '').replace(/,\s*$/, '');
if (item.itemType == 'audioRecording') {
item.creators.push({
lastName: name,
@ -464,7 +466,6 @@ function scrape(doc, url) {
}
}
/** BEGIN TEST CASES **/
var testCases = [
{
@ -869,7 +870,7 @@ var testCases = [
"numPages": 1328,
"publisher": "Vintage",
"shortTitle": "1Q84",
"place": "London",
"place": "London",
"attachments": [
{
"title": "Amazon.com Link",

382
Anarchist Library.js Normal file
View File

@ -0,0 +1,382 @@
{
"translatorID": "1a31e4c5-22ed-4b5b-a75f-55476db29a44",
"label": "Anarchist Library",
"creator": "Sister Baæ'l",
"target": "https://theanarchistlibrary\\.org/(latest|library|stats/popular|category/topic|category/author|special/index|search)",
"minVersion": "7.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2025-10-25 01:31:43"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2025 Dandelion Good and the righteous Anti Toil Theologians at Iliff
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
/*
***** BEGIN ATTRIBUTION BLOCK *****
This translator was developed by Dandelion Good.
If you do any work on this translator, please add yourself here <3.
*/
var allAttachmentTypes = {
"Plain PDF": { ext: ".pdf", mimeType: "application/pdf" },
"A4 PDF": { ext: ".a4.pdf", mimeType: "application/pdf" },
"Letter PDF": { ext: ".lt.pdf", mimeType: "application/pdf" },
EPub: { ext: ".epub", mimeType: "application/epub+zip" },
"Printer-friendly HTML": { ext: ".html", mimeType: "text/html" },
LaTeX: { ext: ".tex", mimeType: "application/x-tex" },
"Plain Text": { ext: ".muse", mimeType: "text/plain" },
"Source Zip:": { ext: ".zip", mimeType: "application/zip" },
Snapshot: { ext: "snapshot", mimeType: "text/html" }
};
function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
var rows = doc.querySelectorAll("a.list-group-item");
for (let row of rows) {
let href = row.href;
let title = ZU.trimInternal(text(row, "strong"));
if (!href || !title) continue;
if (checkOnly) return true;
found = true;
items[href] = title;
}
return found ? items : false;
}
async function scrape(doc, url = doc.location.href) {
// ToDo: get fancier here, allow other types
let item = new Zotero.Item('manuscript');
// These may be expanded on in the future
let attachmentTypes = {
PDF: allAttachmentTypes["Plain PDF"],
};
item.url = url;
item.language = attr(doc, "html", "lang");
let itemType = attr(doc, '[property~="og:type"]', 'content');
let tagNodeList = doc.querySelectorAll(`[property~="og:${itemType}:tag"]`);
let description = attr(doc, '[property~="og:description"]', 'content');
let author = attr(doc, `[property~="og:${itemType}:author"]`, 'content');
item.creators.push(ZU.cleanAuthor(author, "author"));
if (description) {
item.description = description;
// misses https://theanarchistlibrary.org/library/leo-tolstoy-the-complete-works-of-count-tolstoy-volume-12
let re = /(?<=[Tt]ranslated(?: +to [Ee]nglish)? +by ).*$/u;
let translatedMatch = description.match(re);
if (translatedMatch) {
item.creators.push(ZU.cleanAuthor(translatedMatch[0], "translator", translatedMatch[0].includes(",")));
}
}
let date = getPreambleVal(doc, "textdate");
let notes = getPreambleVal(doc, "preamblenotes");
// misses link here: https://theanarchistlibrary.org/library/margaret-killjoy-it-s-time-to-build-resilient-communities
let source = getPreambleVal(doc, "preamblesrc");
for (let tagNode of tagNodeList) {
item.tags.push({ tag: tagNode.content });
}
let title = attr(doc.head, '[property~="og:title"][content]', 'content');
item.title = title;
item.date = date;
if (notes) {
item.notes.push({ note: ZU.trimInternal(notes) });
}
if (source) {
item.notes.push({ note: `Source: ${ZU.trimInternal(source)}` });
}
for (let [typeName, typeInfo] of Object.entries(attachmentTypes)) {
let attachment = {
title: typeName,
url: `${doc.location.href}${typeInfo.ext}`,
mimeType: typeInfo.mimeType
};
if (typeInfo.ext == "snapshot") {
attachment.document = doc;
}
item.attachments.push(attachment);
}
item.complete();
}
var libraryRe = /library\//;
function detectWeb(doc, url) {
if (libraryRe.test(url)) {
return 'manuscript';
}
else if (getSearchResults(doc, true)) {
return 'multiple';
}
return false;
}
function getPreambleVal(doc, id) {
let preamble = doc.body.querySelector("div#preamble");
return text(preamble, `div#${id}`).slice(text(preamble, `span#${id}-label`).length);
}
async function doWeb(doc, url) {
if (detectWeb(doc, url) == 'multiple') {
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(await requestDocument(url));
}
}
else {
await scrape(doc, url);
}
}
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "https://theanarchistlibrary.org/library/abel-paz-durruti-in-the-spanish-revolution",
"items": [
{
"itemType": "manuscript",
"title": "Durruti in the Spanish Revolution",
"creators": [
{
"creatorType": "author",
"firstName": "Abel",
"lastName": "Paz"
},
{
"creatorType": "translator",
"firstName": "Chuck",
"lastName": "Morse"
}
],
"date": "1996",
"url": "https://theanarchistlibrary.org/library/abel-paz-durruti-in-the-spanish-revolution",
"language": "en",
"attachments": [
{
"title": "PDF",
"mimeType": "application/pdf"
}
],
"tags": [
{
"tag": "Buenaventura Durruti"
},
{
"tag": "Spanish Revolution"
},
{
"tag": "biography"
}
],
"notes": [
{
"note": "Translated to English by Chuck Morse"
},
{
"note": "Source: Published by AK Press in 2006 (please support the publisher!). Retrieved on 19th September 2020 from https://libcom.org/library/durruti-spanish-revolution"
}
],
"seeAlso": [],
"libraryCatalog": "Anarchist Library"
}
]
},
{
"type": "web",
"url": "https://theanarchistlibrary.org/library/errico-malatesta-the-general-strike-and-the-insurrection-in-italy",
"items": [
{
"itemType": "manuscript",
"title": "The General Strike and the Insurrection in Italy",
"creators": [
{
"creatorType": "author",
"firstName": "Errico",
"lastName": "Malatesta"
}
],
"date": "1914",
"language": "en",
"url": "https://theanarchistlibrary.org/library/errico-malatesta-the-general-strike-and-the-insurrection-in-italy",
"libraryCatalog": "Anarchist Library",
"attachments": [
{
"title": "PDF",
"mimeType": "application/pdf"
}
],
"tags": [
{
"tag": "General Strike"
},
{
"tag": "Italy"
},
{
"tag": "history"
},
{
"tag": "insurrection"
}
],
"notes": [
{
"note": "Freedom (London) 28, no. 303 (July 1914). In the article, written shortly after his escape from Italy and return to London, Malatesta provides an account of the Red Week, which broke out on 7 June 1914 in Ancona, where Malatesta lived."
},
{
"note": "Source: The Method of Freedom: An Errico Malatesta Reader, edited by Davide Turcato, translated by Paul Sharkey."
}
],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://theanarchistlibrary.org/library/ulrika-holgersson-britta-grondahl",
"items": [
{
"title": "Britta Gröndahl",
"itemType": "manuscript",
"creators": [
{
"firstName": "Ulrika",
"lastName": "Holgersson",
"creatorType": "author"
},
{
"firstName": "Alexia",
"lastName": "Grosjean",
"creatorType": "translator"
}
],
"notes": [
{
"note": "Translated by Alexia Grosjean."
},
{
"note": "Source: Retrieved on 11th March 2025 from www.skbl.se"
}
],
"tags": [
{
"tag": "Sweden"
},
{
"tag": "biography"
}
],
"date": "2018-03-08",
"seeAlso": [],
"libraryCatalog": "Anarchist Library",
"attachments": [
{
"title": "PDF",
"mimeType": "application/pdf"
}
],
"url": "https://theanarchistlibrary.org/library/ulrika-holgersson-britta-grondahl",
"language": "en"
}
]
},
{
"type": "web",
"url": "https://theanarchistlibrary.org/library/emile-armand-the-forerunners-of-anarchism",
"items": [
{
"itemType": "manuscript",
"title": "The Forerunners of Anarchism",
"creators": [
{
"creatorType": "author",
"firstName": "Emile",
"lastName": "Armand"
},
{
"creatorType": "translator",
"firstName": "",
"lastName": "Reddebrek"
}
],
"notes": [
{
"note": "Translated by Reddebrek."
},
{
"note": "Source: Provided by the translator."
}
],
"tags": [
{
"tag": "history"
},
{
"tag": "individualism"
},
{
"tag": "proto-anarchism"
}
],
"date": "1933",
"seeAlso": [],
"libraryCatalog": "Anarchist Library",
"attachments": [
{
"title": "PDF",
"mimeType": "application/pdf"
}
],
"url": "https://theanarchistlibrary.org/library/emile-armand-the-forerunners-of-anarchism",
"language": "en"
}
]
},
{
"type": "web",
"url": "https://theanarchistlibrary.org/search?query=kropotkin",
"items": "multiple"
},
{
"type": "web",
"url": "https://theanarchistlibrary.org/search?query=spirit",
"items": "multiple"
}
]
/** END TEST CASES **/

390
AquaDocs.js Normal file
View File

@ -0,0 +1,390 @@
{
"translatorID": "97b65138-71b7-424f-b305-4a2161e90661",
"label": "AquaDocs",
"creator": "Sebastian Karcher",
"target": "^https?://aquadocs\\.org/(handle|discover|browse)",
"minVersion": "5.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2023-08-24 02:41:29"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2023 Sebastian Karcher
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
function detectWeb(doc, url) {
if (url.includes('/handle/') && attr(doc, 'meta[name="DC.type"]', 'content')) {
let type = attr(doc, 'meta[name="DC.type"]', 'content');
// Z.debug(type);
return getType(type);
}
else if (getSearchResults(doc, true)) {
return 'multiple';
}
return false;
}
function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
var rows = doc.querySelectorAll('.main-content .description-content a');
for (let row of rows) {
let href = row.href;
let title = ZU.trimInternal(row.textContent);
if (!href || !title) continue;
if (checkOnly) return true;
found = true;
items[href] = title;
}
return found ? items : false;
}
async function doWeb(doc, url) {
if (detectWeb(doc, url) == 'multiple') {
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(url);
}
}
else {
await scrape(url);
}
}
function getType(string) {
string = string.toLowerCase();
if (string.includes("book_section") || string.includes("chapter")) {
return "bookSection";
}
else if (string.includes("book") || string.includes("monograph")) {
return "book";
}
else if (string.includes("report")) {
return "report";
}
else if (string.includes("proceedings") || string.includes("conference")) {
return "conferencePaper";
}
else {
return "journalArticle"; // default -- most of the catalog
}
}
async function scrape(url) {
let xmlURL = url.replace("/handle/", "/metadata/handle/").replace(/[?#].*$/, "") + "/mets.xml";
// Z.debug(xmlURL);
let xmlText = await requestText(xmlURL);
// Z.debug(xmlText)
let translator = Zotero.loadTranslator('import');
translator.setTranslator('2c05e2d1-a533-448f-aa20-e919584864cb'); // DIM
translator.setString(xmlText);
translator.setHandler('itemDone', (_obj, item) => {
for (let attachment of item.attachments) {
if (attachment.url && !attachment.url.startsWith("http")) {
attachment.url = "https://aquadocs.org" + attachment.url;
}
}
item.complete();
});
await translator.translate();
}
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "https://aquadocs.org/handle/1834/42391",
"items": [
{
"itemType": "journalArticle",
"title": "Upwelling phenomenon in the marine regions of Southern Central of Vietnam: a review",
"creators": [
{
"firstName": "Hong Long",
"lastName": "Bui",
"creatorType": "author"
},
{
"firstName": "Minh Thu",
"lastName": "Phan",
"creatorType": "author"
}
],
"date": "2022",
"ISSN": "1859-3097",
"abstractNote": "Upwelling is an oceanographic phenomenon that involves the physical process and contributes to changes in chemistry, biology, and natural resources. So, systematically, it is the particular ecosystems of whole marine regions with the upwelling. The strong upwelling waters in South Central Regions of Vietnam have uncertain features of the East Vietnam Sea (Bien Dong) and special characteristics of a coastal upwelling area, recorded in international scientific papers in the twentieth century. Their first signals were discovered in the early 1930s through conceptual ideas. The upwelling phenomenon is officially confirmed by scientific results of marine investigations of the NAGA Expedition (19591961). The paper aims to review and discuss the physical from Vietnamese investigation and results since 1990s. The following factors are the most contributing to forming and developing the strong upwelling in Southern Central Waters: (1) Influence scale (Mezo- and micro-scale); (2) Forming causes and developing mechanism of upwelling phenomenon, such as monsoon, morphography, shoreline, and western boundary current system of the East Vietnam Sea; (3) Influence of the water-mass from Mekong River on the upwelling area; (4) Ecological environmental consequences; (5) Impacts of the atmospheric-oceanic interaction processes on the western EVS on upwelling. Additionally, the review has targeted findings of upwelling phenomenon mainly in Vietnamese waters based on remote sensing analysis and reanalysis data series to simulate their forming, mechanizing, fluctuating models and the impacts of upwelling in the EVS on resources and ecosystems. The coupled atmosphere-ocean models resulted the upwelling mechanisms and formation. The long-time series of upwelling phenomenon (Macroscale) were evaluated by remote sensing and reanalyzed data series. It is also providing the supplementing and detailing causes and mechanisms of upwelling formation; impacts and interactions of upwelling on marine physics and hydrodynamics (ocean vortexes, seawater temperature), biochemical (nutrients, plankton organisms), and resources (fish, seafood). Within the framework of strong upwelling waters in the Southern Central Regions (Vietnam), the review has not only mentioned partly clarified scientific results but also indicates the limitations and challenges which were faced and encountered in the forecasters of upwelling phenomena in the future.",
"issue": "2",
"language": "en",
"libraryCatalog": "AquaDocs",
"pages": "103-122",
"publicationTitle": "Vietnam of Journal Marine Science and Technology",
"shortTitle": "Upwelling phenomenon in the marine regions of Southern Central of Vietnam",
"url": "http://hdl.handle.net/1834/42391",
"volume": "22",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [
{
"tag": "Natural resources"
},
{
"tag": "Upwelling phenomenon"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://aquadocs.org/handle/1834/20117?show=full",
"items": [
{
"itemType": "book",
"title": "M/V CONNECTED Coral Reef Restoration Monitoring Report, Monitoring Events 2004-2005. Florida Keys National Marine Sanctuary Monroe County, Florida",
"creators": [
{
"firstName": "Joe",
"lastName": "Schittone",
"creatorType": "author"
},
{
"firstName": "Erik C.",
"lastName": "Franklin",
"creatorType": "author"
},
{
"firstName": "J. Harold",
"lastName": "Hudson",
"creatorType": "author"
},
{
"firstName": "Jeff",
"lastName": "Anderson",
"creatorType": "author"
}
],
"date": "2006",
"abstractNote": "This document presents the results of the monitoring of a repaired coral reef injured by the M/V Connected vessel grounding incident of March 27, 2001. This groundingoccurred in Florida state waters within the boundaries of the Florida Keys National Marine Sanctuary (FKNMS). The National Oceanic and Atmospheric Administration (NOAA) and the Board of Trustees of the Internal Improvement Trust Fund of the State of Florida, (“State of Florida” or “state”) are the co-trustees for the natural resourceswithin the FKNMS and, thus, are responsible for mediating the restoration of the damaged marine resources and monitoring the outcome of the restoration actions. Therestoration monitoring program tracks patterns of biological recovery, determines the success of restoration measures, and assesses the resiliency to environmental andanthropogenic disturbances of the site over time.The monitoring program at the Connected site was to have included an assessment of the structural stability of installed restoration modules and biological condition of reattached corals performed on the following schedule: immediately (i.e., baseline), 1, 3, and 6 years after restoration and following a catastrophic event. Restoration of this site was completed on July 20, 2001. Due to unavoidable delays in the settlement of the case, the“baseline” monitoring event for this site occurred in July 2004. The catastrophic monitoring event occurred on August 31, 2004, some 2 ½ weeks after the passage of Hurricane Charley which passed nearby, almost directly over the Dry Tortugas. In September 2005, the year one monitoring event occurred shortly after the passage of Hurricane Katrina, some 70 km to the NW. This report presents the results of all three monitoring events. (PDF contains 37 pages.)",
"language": "en",
"libraryCatalog": "AquaDocs",
"place": "Silver Spring, MD",
"publisher": "NOAA/National Ocean Service/National Marine Sanctuary Program",
"series": "Marine Sanctuaries Conservation Series",
"url": "http://hdl.handle.net/1834/20117",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [
{
"tag": "Acropora palmata"
},
{
"tag": "Coral"
},
{
"tag": "Ecology"
},
{
"tag": "Environment"
},
{
"tag": "Florida Keys National Marine Sanctuary"
},
{
"tag": "Grounding"
},
{
"tag": "Hurricane Charley"
},
{
"tag": "Hurricane Katrina"
},
{
"tag": "Management"
},
{
"tag": "Monitoring"
},
{
"tag": "Restoration"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://aquadocs.org/discover",
"items": "multiple"
},
{
"type": "web",
"url": "https://aquadocs.org/browse?type=subject&value=A.+gueldenstaedtii",
"items": "multiple"
},
{
"type": "web",
"url": "https://aquadocs.org/handle/1834/30052?show=full",
"items": [
{
"itemType": "bookSection",
"title": "Ecological Attribute Alteration: Measurement and Evaluation: Activity Assessment Routine: Ecological Systems Component, Ecological Systems Component Handbook",
"creators": [],
"date": "1978-08",
"abstractNote": "This technical paper is intended to provide a more complete treatment of implicit principles and assumptions contained in the user's manual for the ecological systems component of the activity assessment routine. The ecological systems component (ESC) defines a method for evaluating changes in an ecosystem which may result from resource use and consumption. This paper begins by characterizing an ecosystem as an organized collection of attributes mutually dependent on energy exchange. The magnitude matrix with which altered energy flows are scaled is described in Chapter 4. The magnitude of an alteration is assessed somewhat differently for the two categories of attributes: discussion of conventions relevant to this distinction is provided in Chapter 5. However, effects on attributes are variable through time, and additional remarks concerning duration are included in Chapter 6. Finally, possible exceptions to the general guidelines for designating the direction of an effect are introduced in Chapter 7.",
"bookTitle": "Ecological Systems Component Handbook",
"language": "en",
"libraryCatalog": "AquaDocs",
"place": "Austin, TX",
"publisher": "RPC, Inc.",
"series": "Technical Paper",
"shortTitle": "Ecological Attribute Alteration",
"url": "http://hdl.handle.net/1834/30052",
"attachments": [],
"tags": [
{
"tag": "Ecology"
},
{
"tag": "Management"
},
{
"tag": "coastal zone management"
},
{
"tag": "ecological assessment"
},
{
"tag": "evaluation"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://aquadocs.org/handle/1834/970?show=full",
"items": [
{
"itemType": "conferencePaper",
"title": "Report from the WPB on the Data Situation for Billfish",
"creators": [],
"date": "2000",
"conferenceName": "IOTC 3",
"language": "en",
"libraryCatalog": "AquaDocs",
"pages": "102-103",
"proceedingsTitle": "IOTC Proceedings no. 3",
"publisher": "IOTC",
"url": "http://hdl.handle.net/1834/970",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [
{
"tag": "Billfisheries"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://aquadocs.org/handle/1834/31638?show=full",
"items": [
{
"itemType": "conferencePaper",
"title": "Introduction",
"creators": [
{
"firstName": "Caroline M.",
"lastName": "Isaacs",
"creatorType": "author"
}
],
"date": "1997",
"abstractNote": "The Thirteenth Annual PACLIM Workshop was held at the Asilomar Conference Center on April 14-17, 1996. Attended by about 100 registered participants, the workshop included 27 talks and 26 poster presentations. The talks consisted of a one-day theme session of seven 45-minute talks and two featured evening talks. Throughout the remainder of the meeting were nearly 20 shorter, 20-minute presentations. Poster presenters gave a short 1-2 minute introduction to their posters, which were displayed during the entire meeting.All presenters were invited to expand their abstracts into a manuscript for inclusion in the Proceedings volume, and nearly all presentations are included in manuscript or abstract form. In this Proceedings volume, manuscripts are presented first, and abstracts of talks and then posters follow.",
"conferenceName": "Thirteenth Annual Pacific Climate (PACLIM) Workshop",
"language": "en",
"libraryCatalog": "AquaDocs",
"pages": "1-8",
"url": "http://hdl.handle.net/1834/31638",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [
{
"tag": "Atmospheric Sciences"
},
{
"tag": "Earth Sciences"
},
{
"tag": "Ecology"
},
{
"tag": "Limnology"
},
{
"tag": "Oceanography"
},
{
"tag": "PACLIM"
},
{
"tag": "hydrology"
}
],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

View File

@ -2,21 +2,21 @@
"translatorID": "5ed5ab01-899f-4a3b-a74c-290fb2a1c9a4",
"label": "AustLII and NZLII",
"creator": "Justin Warren, Philipp Zumstein",
"target": "^https?://www\\d?\\.(austlii\\.edu\\.au|nzlii\\.org)",
"target": "^https?://(www\\d?|classic)\\.(austlii\\.edu\\.au|nzlii\\.org)",
"minVersion": "3.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2018-03-02 09:46:09"
"lastUpdated": "2024-11-21 18:54:11"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2018 Justin Warren, Philipp Zumstein
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
@ -35,15 +35,9 @@
***** END LICENSE BLOCK *****
*/
// attr()/text() v2
function attr(docOrElem,selector,attr,index){var elem=index?docOrElem.querySelectorAll(selector).item(index):docOrElem.querySelector(selector);return elem?elem.getAttribute(attr):null;}function text(docOrElem,selector,index){var elem=index?docOrElem.querySelectorAll(selector).item(index):docOrElem.querySelector(selector);return elem?elem.textContent:null;}
function detectWeb(doc, url) {
var classes = attr(doc, 'body', 'class');
// Z.debug(classes);
if (classes.includes('case')) {
return "case";
}
@ -59,9 +53,13 @@ function detectWeb(doc, url) {
if (url.includes('austlii.edu.au/cgi-bin/sinodisp/au/cases/') && url.includes('.html')) {
return "case";
}
if (url.includes('classic.austlii.edu.au') && url.includes('.html')) {
return "case";
}
if (getSearchResults(doc, true)) {
return "multiple";
}
return false;
}
@ -69,7 +67,7 @@ function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
var rows = doc.querySelectorAll('#page-main ul>li>a');
for (let i=0; i<rows.length; i++) {
for (let i = 0; i < rows.length; i++) {
let href = rows[i].href;
let title = ZU.trimInternal(rows[i].textContent);
if (!href || !title) continue;
@ -82,49 +80,111 @@ function getSearchResults(doc, checkOnly) {
}
function doWeb(doc, url) {
var type = detectWeb(doc, url);
if (type == "multiple") {
Zotero.selectItems(getSearchResults(doc, false), function (items) {
if (!items) {
return true;
}
var articles = [];
for (var i in items) {
articles.push(i);
}
ZU.processDocuments(articles, scrape);
});
} else {
async function doWeb(doc, url) {
if (detectWeb(doc, url) == "multiple") {
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (!items) return;
for (let url of Object.keys(items)) {
scrape(await requestDocument(url), url);
}
}
else if (new URL(url).hostname === 'classic.austlii.edu.au') {
let urlObj = new URL(url);
urlObj.hostname = 'www.austlii.edu.au';
url = urlObj.toString();
scrape(await requestDocument(url), url);
}
else {
scrape(doc, url);
}
}
/*
* Adjust some jurisdiction abbreviations
*/
var jurisdictionAbbrev = {
"Commonwealth": "Cth",
"CTH": "Cth",
"Australian Capital Territory": "ACT",
"New South Wales": "NSW",
"Northern Territory": "NT",
"Queensland": "Qld",
"QLD": "Qld",
"South Australia": "SA",
"Tasmania": "Tas",
"TAS": "Tas",
"Victoria": "Vic",
"VIC": "Vic",
"Western Australia": "WA"
};
/*
* ZU.capitalizeTitle doesn't cope with Act Names (With Parenthetical Names) Acts
* so we give it a bit of help.
*/
function capitalizeWithPunctuation(string) {
const actNameDelimRegex = /( \(|\) )/;
var words = string.split(actNameDelimRegex);
var newString = "";
var lastWordIndex = words.length - 1;
for (var i = 0; i <= lastWordIndex; i++) {
if (actNameDelimRegex.test(words[i])) {
newString += words[i];
}
else {
newString += ZU.capitalizeTitle(words[i].toLowerCase(), true);
}
}
return newString;
}
/*
* AustLII includes the date on the end of all Acts
*/
function parseActName(nameOfAct) {
// Split at the last space before the year
const parsed = nameOfAct.split(/\s(\d{4})/);
// Zotero.debug(parsed);
let actName = parsed[0], actYear = parsed[1];
actName = capitalizeWithPunctuation(actName);
return { actName, actYear };
}
function scrape(doc, url) {
var type = detectWeb(doc, url);
var newItem = new Zotero.Item(type);
var jurisdiction = text(doc, 'li.ribbon-jurisdiction>a>span');
if (jurisdiction) {
newItem.extra = "jurisdiction: " + jurisdiction;
var fullJurisdiction = text(doc, 'li.ribbon-jurisdiction > a > span');
var jurisdiction = jurisdictionAbbrev[fullJurisdiction] || fullJurisdiction;
if (jurisdiction && ZU.fieldIsValidForType('code', type)) {
newItem.code = jurisdiction;
}
var citation = text(doc, 'li.ribbon-citation>a>span');
var voliss;
var m;
if (text(doc, '#ribbon')) {
if (type == "case") {
var voliss = text(doc, 'head>title');
voliss = text(doc, 'head>title');
// e.g. C & M [2006] FamCA 212 (20 January 2006)
newItem.caseName = voliss.replace(/\s?\[.*$/, '');
newItem.title = newItem.caseName;
var lastParenthesis = voliss.match(/\(([^\)]*)\)$/);
var lastParenthesis = voliss.match(/\(([^)]*)\)$/);
if (lastParenthesis) {
newItem.dateDecided = ZU.strToISO(lastParenthesis[1]);
} else {
}
else {
newItem.dateDecided = text(doc, 'li.ribbon-year>a>span');
}
newItem.court = text(doc, 'li.ribbon-database>a>span');
var courtAbbrevInURL = url.match(/\/cases\/[^/]+\/([^/]+)\//);
if (courtAbbrevInURL) {
newItem.court = decodeURIComponent(courtAbbrevInURL[1]);
}
else {
// Full court name
newItem.court = text(doc, 'li.ribbon-database > a > span');
}
if (citation) {
var lastNumber = citation.match(/(\d+)$/);
if (lastNumber) {
@ -133,49 +193,56 @@ function scrape(doc, url) {
}
}
if (type == "statute") {
// title
newItem.nameOfAct = citation.trim();
// All AustLII Act titles end in the year the Act was passed
const actInfo = parseActName(citation);
newItem.nameOfAct = actInfo.actName;
newItem.dateEnacted = actInfo.actYear;
// section
newItem.section = text(doc, 'li.ribbon-subject>a>span');
if (newItem.section) newItem.section = newItem.section.replace(/^SECT /, '');
}
if (type == "journalArticle") {
var title = text(doc, 'title');
var m = title.match(/(.*) --- "([^"]*)"/);
m = title.match(/(.*) --- "([^"]*)"/);
if (m) {
newItem.title = m[2];
var authors = m[1].split(';');
for (let i=0; i<authors.length; i++) {
for (let i = 0; i < authors.length; i++) {
newItem.creators.push(ZU.cleanAuthor(authors[i], 'author', authors[i].includes(',')));
}
} else {
}
else {
newItem.title = title;
}
newItem.publicationTitle = text(doc, 'li.ribbon-database>a>span');
newItem.date = text(doc, 'li.ribbon-year>a>span');
}
} else {
var voliss = text(doc, 'head>title');
}
else {
voliss = text(doc, 'head>title');
// e.g. C & M [2006] FamCA 212 (20 January 2006)
var m = voliss.match(/^([^[]*)\[(\d+)\](.*)\(([^\)]*)\)$/);
m = voliss.match(/^([^[]*)\[(\d+)\](.*)\(([^)]*)\)$/);
if (m) {
newItem.title = m[1];
newItem.dateDecided = ZU.strToISO(m[4]);
var courtNumber = m[3].trim().split(' ');
if (courtNumber.length>=2) {
if (courtNumber.length >= 2) {
newItem.court = courtNumber[0];
newItem.docketNumber = courtNumber[1].replace(/[^\w]*$/, '');
}
} else {
}
else {
newItem.title = voliss;
}
}
newItem.url = url;
newItem.url = url
.replace(/^http:\/\//, 'https://')
.replace(/^(https:\/\/www)\d/, '$1');
newItem.attachments = [{
document: doc,
title: "Snapshot",
mimeType:"text/html"
mimeType: "text/html"
}];
newItem.complete();
}
@ -184,17 +251,16 @@ function scrape(doc, url) {
var testCases = [
{
"type": "web",
"url": "http://www7.austlii.edu.au/cgi-bin/viewdoc/au/cases/cth/FamCA/2006/212.html",
"url": "http://www.austlii.edu.au/cgi-bin/viewdoc/au/cases/cth/FamCA/2006/212.html",
"items": [
{
"itemType": "case",
"caseName": "C & M",
"creators": [],
"dateDecided": "2006-01-20",
"court": "Family Court of Australia",
"court": "FamCA",
"docketNumber": "212",
"extra": "jurisdiction: Commonwealth",
"url": "http://www7.austlii.edu.au/cgi-bin/viewdoc/au/cases/cth/FamCA/2006/212.html",
"url": "https://www.austlii.edu.au/cgi-bin/viewdoc/au/cases/cth/FamCA/2006/212.html",
"attachments": [
{
"title": "Snapshot",
@ -209,17 +275,16 @@ var testCases = [
},
{
"type": "web",
"url": "http://www8.austlii.edu.au/cgi-bin/viewdoc/au/cases/cth/FCA/2010/1.html",
"url": "http://www.austlii.edu.au/cgi-bin/viewdoc/au/cases/cth/FCA/2010/1.html",
"items": [
{
"itemType": "case",
"caseName": "Yeo, in the matter of AES Services (Aust) Pty Ltd (ACN 111 306 543) (Administrators Appointed)",
"creators": [],
"dateDecided": "2010-01-05",
"court": "Federal Court of Australia",
"court": "FCA",
"docketNumber": "1",
"extra": "jurisdiction: Commonwealth",
"url": "http://www8.austlii.edu.au/cgi-bin/viewdoc/au/cases/cth/FCA/2010/1.html",
"url": "https://www.austlii.edu.au/cgi-bin/viewdoc/au/cases/cth/FCA/2010/1.html",
"attachments": [
{
"title": "Snapshot",
@ -243,7 +308,7 @@ var testCases = [
"dateDecided": "2008-02-08",
"court": "NZSC",
"docketNumber": "1",
"url": "http://www.nzlii.org/nz/cases/NZSC/2008/1.html",
"url": "https://www.nzlii.org/nz/cases/NZSC/2008/1.html",
"attachments": [
{
"title": "Snapshot",
@ -258,22 +323,21 @@ var testCases = [
},
{
"type": "web",
"url": "http://www8.austlii.edu.au/cgi-bin/viewtoc/au/cases/act/ACTSC/2010/",
"url": "http://www.austlii.edu.au/cgi-bin/viewtoc/au/cases/act/ACTSC/2010/",
"items": "multiple"
},
{
"type": "web",
"url": "http://www8.austlii.edu.au/cgi-bin/viewdoc/au/cases/cth/AICmr/2017/134.html",
"url": "http://www.austlii.edu.au/cgi-bin/viewdoc/au/cases/cth/AICmr/2017/134.html",
"items": [
{
"itemType": "case",
"caseName": "'NM' and Department of Human Services (Freedom of information)",
"creators": [],
"dateDecided": "2017-12-08",
"court": "Australian Information Commissioner",
"court": "AICmr",
"docketNumber": "134",
"extra": "jurisdiction: Commonwealth",
"url": "http://www8.austlii.edu.au/cgi-bin/viewdoc/au/cases/cth/AICmr/2017/134.html",
"url": "https://www.austlii.edu.au/cgi-bin/viewdoc/au/cases/cth/AICmr/2017/134.html",
"attachments": [
{
"title": "Snapshot",
@ -288,15 +352,16 @@ var testCases = [
},
{
"type": "web",
"url": "http://www8.austlii.edu.au/cgi-bin/viewdoc/au/legis/cth/consol_act/foia1982222/s24ab.html",
"url": "http://www.austlii.edu.au/cgi-bin/viewdoc/au/legis/cth/consol_act/foia1982222/s24ab.html",
"items": [
{
"itemType": "statute",
"nameOfAct": "Freedom of Information Act 1982",
"nameOfAct": "Freedom of Information Act",
"creators": [],
"extra": "jurisdiction: Commonwealth",
"dateEnacted": "1982",
"code": "Cth",
"section": "24AB",
"url": "http://www8.austlii.edu.au/cgi-bin/viewdoc/au/legis/cth/consol_act/foia1982222/s24ab.html",
"url": "https://www.austlii.edu.au/cgi-bin/viewdoc/au/legis/cth/consol_act/foia1982222/s24ab.html",
"attachments": [
{
"title": "Snapshot",
@ -311,14 +376,15 @@ var testCases = [
},
{
"type": "web",
"url": "http://www8.austlii.edu.au/cgi-bin/viewdb/au/legis/cth/consol_act/foia1982222/",
"url": "http://www.austlii.edu.au/cgi-bin/viewdb/au/legis/cth/consol_act/foia1982222/",
"items": [
{
"itemType": "statute",
"nameOfAct": "Freedom of Information Act 1982",
"nameOfAct": "Freedom of Information Act",
"creators": [],
"extra": "jurisdiction: CTH",
"url": "http://www8.austlii.edu.au/cgi-bin/viewdb/au/legis/cth/consol_act/foia1982222/",
"dateEnacted": "1982",
"code": "Cth",
"url": "https://www.austlii.edu.au/cgi-bin/viewdb/au/legis/cth/consol_act/foia1982222/",
"attachments": [
{
"title": "Snapshot",
@ -333,7 +399,53 @@ var testCases = [
},
{
"type": "web",
"url": "http://www9.austlii.edu.au/cgi-bin/viewdoc/au/journals/AdminRw//2010/9.html",
"url": "https://www.austlii.edu.au/cgi-bin/viewdb/au/legis/cth/consol_act/antsasta1999402/",
"items": [
{
"itemType": "statute",
"nameOfAct": "A New Tax System (Goods and Services Tax) Act",
"creators": [],
"dateEnacted": "1999",
"code": "Cth",
"url": "https://www.austlii.edu.au/cgi-bin/viewdb/au/legis/cth/consol_act/antsasta1999402/",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.austlii.edu.au/cgi-bin/viewdb/au/legis/cth/consol_act/caca2010265/",
"items": [
{
"itemType": "statute",
"nameOfAct": "Competition and Consumer Act",
"creators": [],
"dateEnacted": "2010",
"code": "Cth",
"url": "https://www.austlii.edu.au/cgi-bin/viewdb/au/legis/cth/consol_act/caca2010265/",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "http://www.austlii.edu.au/cgi-bin/viewdoc/au/journals/AdminRw//2010/9.html",
"items": [
{
"itemType": "journalArticle",
@ -353,7 +465,7 @@ var testCases = [
"date": "2010",
"libraryCatalog": "AustLII and NZLII",
"publicationTitle": "Administrative Review Council - Admin Review",
"url": "http://www9.austlii.edu.au/cgi-bin/viewdoc/au/journals/AdminRw//2010/9.html",
"url": "https://www.austlii.edu.au/cgi-bin/viewdoc/au/journals/AdminRw//2010/9.html",
"attachments": [
{
"title": "Snapshot",
@ -368,12 +480,12 @@ var testCases = [
},
{
"type": "web",
"url": "http://www7.austlii.edu.au/cgi-bin/sinosrch.cgi?mask_path=;method=auto;query=adam%20smith;view=relevance&mask_path=au/cases/act/ACTCA",
"url": "http://www.austlii.edu.au/cgi-bin/sinosrch.cgi?mask_path=;method=auto;query=adam%20smith;view=relevance&mask_path=au/cases/act/ACTCA",
"items": "multiple"
},
{
"type": "web",
"url": "http://www8.austlii.edu.au/cgi-bin/sinodisp/au/cases/cth/AICmr/2017/20.html",
"url": "http://www6.austlii.edu.au/cgi-bin/viewdoc/au/cases/cth/AICmr/2017/20.html",
"items": [
{
"itemType": "case",
@ -382,7 +494,100 @@ var testCases = [
"dateDecided": "2017-03-10",
"court": "AICmr",
"docketNumber": "20",
"url": "http://www8.austlii.edu.au/cgi-bin/sinodisp/au/cases/cth/AICmr/2017/20.html",
"url": "https://www.austlii.edu.au/cgi-bin/viewdoc/au/cases/cth/AICmr/2017/20.html",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.austlii.edu.au/cgi-bin/viewdb/au/legis/qld/consol_act/pla1974179/",
"items": [
{
"itemType": "statute",
"nameOfAct": "Property Law Act",
"creators": [],
"dateEnacted": "1974",
"code": "Qld",
"url": "https://www.austlii.edu.au/cgi-bin/viewdb/au/legis/qld/consol_act/pla1974179/",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.austlii.edu.au/cgi-bin/viewdb/au/legis/vic/consol_act/ca195882/",
"items": [
{
"itemType": "statute",
"nameOfAct": "Crimes Act",
"creators": [],
"dateEnacted": "1958",
"code": "Vic",
"url": "https://www.austlii.edu.au/cgi-bin/viewdb/au/legis/vic/consol_act/ca195882/",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.austlii.edu.au/cgi-bin/viewdb/au/legis/nsw/consol_act/leara2002451/",
"items": [
{
"itemType": "statute",
"nameOfAct": "Law Enforcement (Powers and Responsibilities) Act",
"creators": [],
"dateEnacted": "2002",
"code": "NSW",
"url": "https://www.austlii.edu.au/cgi-bin/viewdb/au/legis/nsw/consol_act/leara2002451/",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www8.austlii.edu.au/cgi-bin/viewdoc/au/cases/cth/FedCFamC1A/2024/214.html",
"items": [
{
"itemType": "case",
"caseName": "Dimitrova & Carman",
"creators": [],
"dateDecided": "2024-11-15",
"court": "FedCFamC1A",
"docketNumber": "214",
"url": "https://www.austlii.edu.au/cgi-bin/viewdoc/au/cases/cth/FedCFamC1A/2024/214.html",
"attachments": [
{
"title": "Snapshot",

View File

@ -9,7 +9,7 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2021-06-07 16:44:19"
"lastUpdated": "2024-06-18 20:46:45"
}
/*
@ -41,13 +41,7 @@ function detectWeb(_doc, _url) {
function doWeb(doc, url) {
scrape(doc, url);
}
function getMetaTag(doc, attr, value, contentattr) {
const tag = Array.from(doc.getElementsByTagName("meta")).filter(m => m.attributes[attr] && m.attributes[attr].value == value)[0];
if (tag && tag.attributes[contentattr]) {
return tag.attributes[contentattr].value;
}
return null;
}
function scrape(doc, _url) {
const translator = Zotero.loadTranslator('web');
// Embedded Metadata
@ -57,12 +51,15 @@ function scrape(doc, _url) {
translator.setHandler('itemDone', function (obj, item) {
// Add data for fields that are not covered by Embedded Metadata
// Author name is stored as firstname lastname
const authorName = getMetaTag(doc, "property", "cXenseParse:author", "content");
let authorName = attr(doc, "meta[name='lead:author']", "content");
if (!authorName) {
authorName = text(doc, '.info-opinion .columnnist-name a');
}
if (authorName) {
item.creators = [ZU.cleanAuthor(authorName, "author", false)];
}
// Date is stored as a timestamp like 2020-09-07T17:37:00+07:00, just extract the YYYY-MM-DD at start
const date = getMetaTag(doc, "name", "cXenseParse:recs:publishtime", "content");
const date = attr(doc, "meta[name='lead:published_at']", "content");
if (date) {
item.date = date.substr(0, 10);
}
@ -73,7 +70,9 @@ function scrape(doc, _url) {
item.complete();
});
translator.translate();
}/** BEGIN TEST CASES **/
}
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
@ -91,6 +90,7 @@ var testCases = [
],
"date": "2020-09-07",
"abstractNote": "A general debate without a vote in the House of Representatives has been scheduled for Wednesday for MPs to question the government on the current economic and political crises and suggest ways of solving related problems.",
"language": "en",
"libraryCatalog": "www.bangkokpost.com",
"publicationTitle": "Bangkok Post",
"url": "https://www.bangkokpost.com/thailand/politics/1981267/house-general-debate-set-for-wednesday",
@ -121,7 +121,7 @@ var testCases = [
},
{
"type": "web",
"url": "https://www.bangkokpost.com/tech/1979315/air-force-satellite-napa-1-launched",
"url": "https://www.bangkokpost.com/life/tech/1979315/air-force-satellite-napa-1-launched",
"items": [
{
"itemType": "newspaperArticle",
@ -135,9 +135,10 @@ var testCases = [
],
"date": "2020-09-03",
"abstractNote": "The Royal Thai Air Forces first security satellite, Napa-1, was successfully launched on a European rocket from French Guiana on Thursday morning.",
"language": "en",
"libraryCatalog": "www.bangkokpost.com",
"publicationTitle": "Bangkok Post",
"url": "https://www.bangkokpost.com/tech/1979315/air-force-satellite-napa-1-launched",
"url": "https://www.bangkokpost.com/life/tech/1979315/air-force-satellite-napa-1-launched",
"attachments": [
{
"title": "Snapshot",
@ -181,7 +182,8 @@ var testCases = [
}
],
"date": "2020-09-08",
"abstractNote": "Southeast Asia relies heavily on tourism. In 2019, the travel and tourism industry contributed 12.1% of the region's GDP and approximately one in 10 people are employed within and around it, according to the World Travel and Tourism Council (WTTC).",
"abstractNote": "Southeast Asia relies heavily on tourism. In 2019, the travel and tourism industry contributed 12.1% of the region",
"language": "en",
"libraryCatalog": "www.bangkokpost.com",
"publicationTitle": "Bangkok Post",
"url": "https://www.bangkokpost.com/opinion/opinion/1981587/tech-is-key-to-rebooting-tourism",

View File

@ -1,13 +1,11 @@
{
"translatorID": "b6e39b57-8942-4d11-8259-342c46ce395f",
"translatorType": 2,
"label": "BibLaTeX",
"creator": "Simon Kornblith, Richard Karnesky and Anders Johansson",
"target": "bib",
"minVersion": "2.1.9",
"maxVersion": "null",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"configOptions": {
"getCollections": true
},
@ -17,7 +15,9 @@
"exportFileData": false,
"useJournalAbbreviation": false
},
"lastUpdated": "2022-10-12 19:26:00"
"inRepository": true,
"translatorType": 2,
"lastUpdated": "2024-03-25 14:49:42"
}
/*
@ -371,7 +371,7 @@ var numberRe = /^[0-9]+/;
// it includes the indefinite articles of English, German, French and Spanish, as well as a small set of English prepositions whose
// force is more grammatical than lexical, i.e. which are likely to strike many as 'insignificant'.
// The assumption is that most who want a title word in their key would prefer the first word of significance.
var citeKeyTitleBannedRe = /\b(a|an|the|some|from|on|in|to|of|do|with|der|die|das|ein|eine|einer|eines|einem|einen|un|une|la|le|l'|el|las|los|al|uno|una|unos|unas|de|des|del|d')(\s+|\b)|(<\/?(i|b|sup|sub|sc|span style="small-caps"|span)>)/g;
var citeKeyTitleBannedRe = /\b(a|an|the|some|from|on|in|to|of|do|with|der|die|das|ein|eine|einer|eines|einem|einen|un|une|la|le|l'|les|el|las|los|al|uno|una|unos|unas|de|des|del|d')(\s+|\b)|(<\/?(i|b|sup|sub|sc|span style="small-caps"|span)>)/g;
var citeKeyConversionsRe = /%([a-zA-Z])/;
var citeKeyConversions = {
@ -882,3 +882,7 @@ function doExport() {
Zotero.write("\n");
}
/** BEGIN TEST CASES **/
var testCases = [
]
/** END TEST CASES **/

View File

@ -18,7 +18,7 @@
},
"inRepository": true,
"translatorType": 3,
"lastUpdated": "2023-04-09 18:35:07"
"lastUpdated": "2024-03-25 14:51:02"
}
/*
@ -1242,7 +1242,7 @@ var numberRe = /^[0-9]+/;
// force is more grammatical than lexical, i.e. which are likely to strike many as 'insignificant'.
// The assumption is that most who want a title word in their key would prefer the first word of significance.
// Also remove markup
var citeKeyTitleBannedRe = /\b(a|an|the|some|from|on|in|to|of|do|with|der|die|das|ein|eine|einer|eines|einem|einen|un|une|la|le|l\'|el|las|los|al|uno|una|unos|unas|de|des|del|d\')(\s+|\b)|(<\/?(i|b|sup|sub|sc|span style=\"small-caps\"|span)>)/g;
var citeKeyTitleBannedRe = /\b(a|an|the|some|from|on|in|to|of|do|with|der|die|das|ein|eine|einer|eines|einem|einen|un|une|la|le|l\'|les|el|las|los|al|uno|una|unos|unas|de|des|del|d\')(\s+|\b)|(<\/?(i|b|sup|sub|sc|span style=\"small-caps\"|span)>)/g;
var citeKeyConversionsRe = /%([a-zA-Z])/;
var citeKeyConversions = {
@ -2896,8 +2896,8 @@ var reversemappingTable = {
"{\\c l}" : "\u013C", // LATIN SMALL LETTER L WITH CEDILLA
"{\\v L}" : "\u013D", // LATIN CAPITAL LETTER L WITH CARON
"{\\v l}" : "\u013E", // LATIN SMALL LETTER L WITH CARON
"{\\L }" : "\u0141", //LATIN CAPITAL LETTER L WITH STROKE
"{\\l }" : "\u0142", //LATIN SMALL LETTER L WITH STROKE
"{\\L}" : "\u0141", //LATIN CAPITAL LETTER L WITH STROKE
"{\\l}" : "\u0142", //LATIN SMALL LETTER L WITH STROKE
"{\\'N}" : "\u0143", // LATIN CAPITAL LETTER N WITH ACUTE
"{\\'n}" : "\u0144", // LATIN SMALL LETTER N WITH ACUTE
"{\\c N}" : "\u0145", // LATIN CAPITAL LETTER N WITH CEDILLA
@ -4202,6 +4202,35 @@ var testCases = [
"seeAlso": []
}
]
},
{
"type": "import",
"input": "@book{derbis1998poczucie,\r\ntitle={Poczucie jako{\\'s}ci {\\.z}ycia a swoboda dzia{\\l}ania i odpowiedzialno{\\'s}{\\'c}},\r\nauthor={Derbis, Romuald and Ba{\\'n}ka, Augustyn},\r\nyear={1998},\r\npublisher={Stowarzyszenie Psychologia i Architektura}\r\n}",
"items": [
{
"itemType": "book",
"title": "Poczucie jakości życia a swoboda działania i odpowiedzialność",
"creators": [
{
"firstName": "Romuald",
"lastName": "Derbis",
"creatorType": "author"
},
{
"firstName": "Augustyn",
"lastName": "Bańka",
"creatorType": "author"
}
],
"date": "1998",
"itemID": "derbis1998poczucie",
"publisher": "Stowarzyszenie Psychologia i Architektura",
"attachments": [],
"tags": [],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

View File

@ -9,26 +9,31 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2021-07-28 15:50:57"
"lastUpdated": "2024-01-09 03:40:58"
}
/*
* Bibliothèque nationale de France Translator
* Copyright (C) 2010 Florian Ziche, ziche@noos.fr
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
***** BEGIN LICENSE BLOCK *****
Copyright © 2010-2024 Florian Ziche, Sylvain Machefert
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
/* Bnf namespace. */
@ -472,12 +477,8 @@ var BnfClass = function () {
for (var i = 0; i < rows.length; i++) {
var title = "";
var href = attr(rows[i], 'div[class="notice-synthese"] a', "href");
try {
title = ZU.trim(text(rows[i], 'div[class="notice-synthese"] a h2'));
}
catch (x) {
title = ZU.trim(text(rows[i], 'div[class="notice-synthese"] a'));
}
title = ZU.trim(text(rows[i], 'div[class="notice-synthese"] a'));
var documentYear = text(rows[i], 'span[class="notice-ordre"]');
if (documentYear.length == 6) {
title += " / " + documentYear;

195
Bluesky.js Normal file
View File

@ -0,0 +1,195 @@
{
"translatorID": "3bba003a-ad42-457e-9ea1-547df39d9d00",
"label": "Bluesky",
"creator": "Stephan Hügel",
"target": "^https://bsky\\.app/",
"minVersion": "5.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2025-03-26 14:26:25"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2024 Stephan Hügel <urschrei@gmail.com>
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
let handleRe = /(?:\/profile\/)(([^/]+))/;
let postIdRe = /(?:\/post\/)([a-zA-Z0-9]+)/;
function detectWeb(doc, url) {
if (url.includes('/post/') && handleRe.test(url) && postIdRe.test(url)) {
return 'forumPost';
}
return false;
}
async function doWeb(doc, url) {
await scrapeAPI(doc, url);
}
async function scrapeAPI(doc, url) {
let foundHandle = url.match(handleRe)[1];
let foundPostId = url.match(postIdRe)[1];
let apiUrl = `https://public.api.bsky.app/xrpc/app.bsky.feed.getPostThread?uri=at://${foundHandle}/app.bsky.feed.post/${foundPostId}`;
let data = await ZU.requestJSON(apiUrl);
if (!(data.thread && data.thread.post)) {
throw new Error("Couldn't save post due to missing metadata");
}
else {
let post = data.thread.post;
let item = new Zotero.Item("forumPost");
// Main post details
// remove newlines and extra whitespace
let titleCleaned = post.record.text.replace(/\s+/g, ' ');
// Ensure that full post text is always available
item.abstractNote = titleCleaned;
// Tidy if necessary
if (titleCleaned.length < 140) {
item.title = titleCleaned;
}
else {
item.title = ZU.ellipsize(titleCleaned, 140, true);
}
item.forumTitle = "Bluesky";
item.type = "Post";
item.url = url;
item.date = post.record.createdAt;
// Add author information
if (post.author) {
if (post.author.displayName !== "") {
item.creators.push(Zotero.Utilities.cleanAuthor(post.author.displayName, "author"));
}
else if (post.author.handle !== "handle.invalid") {
item.creators.push(Zotero.Utilities.cleanAuthor(post.author.handle, "author"));
}
// we've got a blank display name and an invalid handle, so we can't add an author: bail out
else {
throw new Error("Couldn't save post due to missing author data: neither display name nor handle are available");
}
if (post.author.handle !== "handle.invalid") {
item.setExtra("Author Handle", post.author.handle);
}
// DID is the creator's unique id in the ATProto network
item.setExtra("DID", post.author.did);
}
// Add metadata for likes, reposts, etc.
item.setExtra("Likes", post.likeCount);
item.setExtra("Reposts", post.repostCount);
item.setExtra("Quotes", post.quoteCount);
// Handle embedded quote records (if any)
if (post.embed && post.embed.record && post.embed.record.value) {
let embeddedPost = post.embed.record.value;
item.notes.push({ note: `This post is quoting a post by @${post.embed.record.author.handle}: "${embeddedPost.text}"` });
}
// Handle replies (if any)
if (data.thread.replies && data.thread.replies.length > 0) {
item.notes.push({ note: `This post had ${data.thread.replies.length} direct replies when it was saved` });
}
item.attachments.push({ document: doc, title: "Snapshot" });
item.complete();
}
}
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "https://bsky.app/profile/watershedlab.bsky.social/post/3lcl3glmdx226",
"defer": true,
"items": [
{
"itemType": "forumPost",
"title": "My first and only job in media was as a reporter on a small newspaper in England in 2002. My salary was £8700. Per year.",
"creators": [
{
"firstName": "Dan",
"lastName": "Shugar",
"creatorType": "author"
}
],
"date": "2024-12-05T16:25:35.749Z",
"abstractNote": "My first and only job in media was as a reporter on a small newspaper in England in 2002. My salary was £8700. Per year.",
"extra": "Author Handle: watershedlab.bsky.social\nDID: did:plc:ufufhaxc74cfl7fpjccykkyh\nLikes: 8\nReposts: 0\nQuotes: 0",
"forumTitle": "Bluesky",
"postType": "Post",
"url": "https://bsky.app/profile/watershedlab.bsky.social/post/3lcl3glmdx226",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [
{
"note": "This post is quoting a post by @ericwickham.ca: \"Told the guy replacing my car window how much I made at my first job in radio and I feel like it deeply changed what he thought about people in media.\""
},
{
"note": "This post had 1 direct replies when it was saved"
}
],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://bsky.app/profile/did:plc:cxq4zxu7soi67juyvxml46zs/post/3ldr6ebdz5c24",
"defer": true,
"items": [
{
"itemType": "forumPost",
"title": "💚 Site of the Day - Rain Delay Media Love that menu! ⚙️ SplitText 🛠️ Webflow site → raindelaymedia.com showcase → gsap.com/showcase",
"creators": [
{
"firstName": "",
"lastName": "GSAP",
"creatorType": "author"
}
],
"date": "2024-12-20T19:59:08.958Z",
"abstractNote": "💚 Site of the Day - Rain Delay Media Love that menu! ⚙️ SplitText 🛠️ Webflow site → raindelaymedia.com showcase → gsap.com/showcase",
"extra": "Author Handle: gsap-greensock.bsky.social\nDID: did:plc:cxq4zxu7soi67juyvxml46zs\nLikes: 6\nReposts: 0\nQuotes: 0",
"forumTitle": "Bluesky",
"postType": "Post",
"url": "https://bsky.app/profile/did:plc:cxq4zxu7soi67juyvxml46zs/post/3ldr6ebdz5c24",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,496 @@
{
"translatorID": "b2d07a2a-c8c6-4426-ba6b-35f094a4d916",
"label": "Bosworth Toller's Anglo-Saxon Dictionary Online",
"creator": "Zoë C. Ma",
"target": "^https://bosworthtoller\\.com/",
"minVersion": "5.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2023-08-18 07:39:58"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2023 Zoë C. Ma
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
function detectWeb(doc) {
// The logic is that "a page's type is determined by its content", because
// the current implementation of the dictionary web app may not be able to
// sync URL correctly all the time.
if (getSearchResults(doc, true/* checkOnly */)) {
return "multiple";
}
if (doc.querySelector("#btd--entry-single")) {
return "dictionaryEntry";
}
return false;
}
function getSearchResults(doc, checkOnly = false) {
let items = {};
let found = false;
let rows = doc.querySelectorAll(".btd--search-entry");
for (let row of rows) {
// Don't retrieve the "similar entry" links
let href = attr(row, ".btd--search-entry-header a", "href");
let title = ZU.trimInternal(text(row, ".btd--entry-grammar").trim());
if (!title) {
title = text(row, ".btd--search-entry-header a"); // fallback
}
if (!href || !title) continue;
if (checkOnly) return true;
found = true;
items[href] = title;
}
return found ? items : false;
}
async function doWeb(doc, url) {
if (detectWeb(doc) === 'multiple') {
let items = await Z.selectItems(getSearchResults(doc));
if (!items) return;
for (let url of Object.keys(items)) {
scrape(await requestDocument(url));
}
}
else {
scrape(doc, url);
}
}
const BOSWORTH_TOLLER_INFO = {
dictionaryTitle: "An Anglo-Saxon Dictionary Online",
language: "en",
place: "Prague",
publisher: "Faculty of Arts, Charles University",
date: "2014",
creators: [
{ firstName: "Joseph", lastName: "Bosworth", creatorType: "author" },
{ firstName: "Thomas Northcote", lastName: "Toller", creatorType: "editor" },
{ firstName: "Christ", lastName: "Sean", creatorType: "editor" },
{ firstName: "Ondřej", lastName: "Tichy", creatorType: "editor" },
],
};
function scrape(doc, url = doc.location.href) {
let item = new Z.Item("dictionaryEntry");
// "Constant" fields
Object.assign(item, BOSWORTH_TOLLER_INFO);
// Page-specific data
item.url = url;
// Word entry
item.title = normalizeLemma(doc) || "[Unknown entry]";
// Original publication and page number in it, if any, as extra
item.extra = getExtraInfo(doc);
// Snapshot
item.attachments = [{
document: doc,
title: "Snapshot",
mimeType: "text/html"
}];
item.complete();
}
// See https://bosworthtoller.com/images-dictionary/frontback_matter.pdf
var BOOK_ORIG_INFO = {
b: "Original Dictionary Title: An Anglo-Saxon Dictionary, Based on the Manuscript Collections of the Late Joseph Bosworth, D.D., F.R.S.\nOriginal Date: 1898\nOriginal Publisher: Oxford University Press\nOriginal Place: London",
d: "Original Dictionary Title: An Anglo-Saxon Dictionary, Based on the Manuscript Collections of the Late Joseph Bosworth; Supplement\nOriginal Date: 1921\nOriginal Publisher: Oxford University Press\nOriginal Place: London",
};
// Get the extra info including original volume info and page number by parsing
// the URL of the scanned page linked to the article. Returns a string where
// each extra entry occupies one line in `key: value` format, or empty string
// if the original book and page cannot be determined.
function getExtraInfo(doc) {
let imageURL = attr(doc, ".btd--image-pin-pan > img", "src");
if (!imageURL) {
return "";
}
// "b" for main book (1898), "d" for supplement (1912)
let pageMatch = imageURL.match(/^\/images-dictionary\/bt_([bd])(\d+)\..+$/);
if (!pageMatch) {
return "";
}
let [, bookKey, page] = pageMatch;
return BOOK_ORIG_INFO[bookKey] // static original publication info
+ "\nOriginal Page: " + page.replace(/^0*/, ""); // trim leading zero
}
// Normalize the lemma's vowel display-form, following the original book's
// orthography (acute for long vowel).
// Why is this necessary? Because the lemma prominently displayed on the page
// main body can be configured by the user (by clicking on the icons: acute,
// macron, and none). But we want the form used in our item data normalized, no
// matter the display option, in order to not lose information and avoid
// duplication.
// NOTE that the letter case is not normalized -- the display on the page
// corresponds to the lemma in the original book.
function normalizeLemma(doc) {
// The key is to apply the correct vowel length even if the user disables
// its display. This "canonical" form (which corresponds to the original
// form in the print book) can be found either in the metadata or in the
// "citation" block under "entry information" in the doc, no matter the
// citation style in use on the page.
let titleRaw = text(doc, "#btd--entry-lemma").trim();
let titleNormalized = removeDiacritics(titleRaw);
// lemma from the meta field, not normally amenable to client-side
// modification
let metaTitle = attr(doc, 'meta[property="og:title"]', "content").trim();
let metaTitleNormalized = removeDiacritics(metaTitle);
if (metaTitle && titleNormalized === metaTitleNormalized) {
return metaTitle;
}
return null;
}
// Utility functions
// Remove the acute accent and macron if any.
function removeDiacritics(str) {
return str.normalize("NFD").replace(/[\u0301\u0304]/g, "");
}
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "https://bosworthtoller.com/search?q=heorte",
"defer": true,
"items": "multiple"
},
{
"type": "web",
"url": "https://bosworthtoller.com/search/advanced?q=%7B%22minFields%22%3A1,%22fields%22%3A%5B%7B%22query%22%3A%22diacon%22,%22field%22%3A%22headword%22,%22is_regex%22%3Afalse%7D,%7B%22query%22%3A%22%22,%22field%22%3A%22headword%22,%22condition%22%3A%22and%22,%22is_regex%22%3Afalse%7D%5D,%22wordclass%22%3A%7B%22include%22%3A%5B%221%22%5D,%22exclude%22%3A%5B%5D%7D,%22gender%22%3A%7B%22include%22%3A%5B%221%22%5D,%22exclude%22%3A%5B%5D%7D,%22subcategory%22%3A%7B%22include%22%3A%5B%5D,%22exclude%22%3A%5B%5D%7D,%22volume%22%3Anull%7D",
"defer": true,
"items": "multiple"
},
{
"type": "web",
"url": "https://bosworthtoller.com/23205",
"items": [
{
"itemType": "dictionaryEntry",
"title": "mucg-wyrt",
"creators": [
{
"firstName": "Joseph",
"lastName": "Bosworth",
"creatorType": "author"
},
{
"firstName": "Thomas Northcote",
"lastName": "Toller",
"creatorType": "editor"
},
{
"firstName": "Christ",
"lastName": "Sean",
"creatorType": "editor"
},
{
"firstName": "Ondřej",
"lastName": "Tichy",
"creatorType": "editor"
}
],
"date": "2014",
"dictionaryTitle": "An Anglo-Saxon Dictionary Online",
"extra": "Original Dictionary Title: An Anglo-Saxon Dictionary, Based on the Manuscript Collections of the Late Joseph Bosworth, D.D., F.R.S.\nOriginal Date: 1898\nOriginal Publisher: Oxford University Press\nOriginal Place: London\nOriginal Page: 700",
"language": "en",
"libraryCatalog": "Bosworth Toller's Anglo-Saxon Dictionary Online",
"place": "Prague",
"publisher": "Faculty of Arts, Charles University",
"url": "https://bosworthtoller.com/23205",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://bosworthtoller.com/7096",
"items": [
{
"itemType": "dictionaryEntry",
"title": "CYN",
"creators": [
{
"firstName": "Joseph",
"lastName": "Bosworth",
"creatorType": "author"
},
{
"firstName": "Thomas Northcote",
"lastName": "Toller",
"creatorType": "editor"
},
{
"firstName": "Christ",
"lastName": "Sean",
"creatorType": "editor"
},
{
"firstName": "Ondřej",
"lastName": "Tichy",
"creatorType": "editor"
}
],
"date": "2014",
"dictionaryTitle": "An Anglo-Saxon Dictionary Online",
"extra": "Original Dictionary Title: An Anglo-Saxon Dictionary, Based on the Manuscript Collections of the Late Joseph Bosworth, D.D., F.R.S.\nOriginal Date: 1898\nOriginal Publisher: Oxford University Press\nOriginal Place: London\nOriginal Page: 183",
"language": "en",
"libraryCatalog": "Bosworth Toller's Anglo-Saxon Dictionary Online",
"place": "Prague",
"publisher": "Faculty of Arts, Charles University",
"url": "https://bosworthtoller.com/7096",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://bosworthtoller.com/27305",
"items": [
{
"itemType": "dictionaryEntry",
"title": "secgan",
"creators": [
{
"firstName": "Joseph",
"lastName": "Bosworth",
"creatorType": "author"
},
{
"firstName": "Thomas Northcote",
"lastName": "Toller",
"creatorType": "editor"
},
{
"firstName": "Christ",
"lastName": "Sean",
"creatorType": "editor"
},
{
"firstName": "Ondřej",
"lastName": "Tichy",
"creatorType": "editor"
}
],
"date": "2014",
"dictionaryTitle": "An Anglo-Saxon Dictionary Online",
"extra": "Original Dictionary Title: An Anglo-Saxon Dictionary, Based on the Manuscript Collections of the Late Joseph Bosworth, D.D., F.R.S.\nOriginal Date: 1898\nOriginal Publisher: Oxford University Press\nOriginal Place: London\nOriginal Page: 855",
"language": "en",
"libraryCatalog": "Bosworth Toller's Anglo-Saxon Dictionary Online",
"place": "Prague",
"publisher": "Faculty of Arts, Charles University",
"url": "https://bosworthtoller.com/27305",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://bosworthtoller.com/23035",
"items": [
{
"itemType": "dictionaryEntry",
"title": "mód-c-wánig",
"creators": [
{
"firstName": "Joseph",
"lastName": "Bosworth",
"creatorType": "author"
},
{
"firstName": "Thomas Northcote",
"lastName": "Toller",
"creatorType": "editor"
},
{
"firstName": "Christ",
"lastName": "Sean",
"creatorType": "editor"
},
{
"firstName": "Ondřej",
"lastName": "Tichy",
"creatorType": "editor"
}
],
"date": "2014",
"dictionaryTitle": "An Anglo-Saxon Dictionary Online",
"extra": "Original Dictionary Title: An Anglo-Saxon Dictionary, Based on the Manuscript Collections of the Late Joseph Bosworth, D.D., F.R.S.\nOriginal Date: 1898\nOriginal Publisher: Oxford University Press\nOriginal Place: London\nOriginal Page: 694",
"language": "en",
"libraryCatalog": "Bosworth Toller's Anglo-Saxon Dictionary Online",
"place": "Prague",
"publisher": "Faculty of Arts, Charles University",
"url": "https://bosworthtoller.com/23035",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://bosworthtoller.com/53107",
"items": [
{
"itemType": "dictionaryEntry",
"title": "hrǽw",
"creators": [
{
"firstName": "Joseph",
"lastName": "Bosworth",
"creatorType": "author"
},
{
"firstName": "Thomas Northcote",
"lastName": "Toller",
"creatorType": "editor"
},
{
"firstName": "Christ",
"lastName": "Sean",
"creatorType": "editor"
},
{
"firstName": "Ondřej",
"lastName": "Tichy",
"creatorType": "editor"
}
],
"date": "2014",
"dictionaryTitle": "An Anglo-Saxon Dictionary Online",
"extra": "Original Dictionary Title: An Anglo-Saxon Dictionary, Based on the Manuscript Collections of the Late Joseph Bosworth; Supplement\nOriginal Date: 1921\nOriginal Publisher: Oxford University Press\nOriginal Place: London\nOriginal Page: 562",
"language": "en",
"libraryCatalog": "Bosworth Toller's Anglo-Saxon Dictionary Online",
"place": "Prague",
"publisher": "Faculty of Arts, Charles University",
"url": "https://bosworthtoller.com/53107",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://bosworthtoller.com/42878",
"items": [
{
"itemType": "dictionaryEntry",
"title": "dón",
"creators": [
{
"firstName": "Joseph",
"lastName": "Bosworth",
"creatorType": "author"
},
{
"firstName": "Thomas Northcote",
"lastName": "Toller",
"creatorType": "editor"
},
{
"firstName": "Christ",
"lastName": "Sean",
"creatorType": "editor"
},
{
"firstName": "Ondřej",
"lastName": "Tichy",
"creatorType": "editor"
}
],
"date": "2014",
"dictionaryTitle": "An Anglo-Saxon Dictionary Online",
"extra": "Original Dictionary Title: An Anglo-Saxon Dictionary, Based on the Manuscript Collections of the Late Joseph Bosworth; Supplement\nOriginal Date: 1921\nOriginal Publisher: Oxford University Press\nOriginal Place: London\nOriginal Page: 154",
"language": "en",
"libraryCatalog": "Bosworth Toller's Anglo-Saxon Dictionary Online",
"place": "Prague",
"publisher": "Faculty of Arts, Charles University",
"url": "https://bosworthtoller.com/42878",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

151
Brill.js
View File

@ -9,13 +9,13 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2021-10-21 04:55:10"
"lastUpdated": "2024-06-14 15:36:55"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2021 Abe Jellinek
Copyright © 2024 Abe Jellinek
This file is part of Zotero.
@ -41,15 +41,15 @@ function detectWeb(doc, url) {
if (url.includes('/journals/')) {
return 'journalArticle';
}
else if (url.includes('referenceworks.brillonline.com/entries/')) {
return 'encyclopediaArticle';
}
else {
return 'book';
}
}
else if (url.includes('bibliographies.brillonline.com/entries/')
&& doc.querySelector('#export-form')) {
else if (url.includes('referenceworks.brill.com/display/')) {
return 'encyclopediaArticle';
}
else if (url.includes('bibliographies.brill.com/items/')
&& doc.querySelector('form.export-item')) {
return 'journalArticle';
}
else if (getSearchResults(doc, true)) {
@ -62,9 +62,12 @@ function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
var rows = doc.querySelectorAll('#searchContent .text-headline a, .type-article .text-headline a, .result-item .book-title a');
if (!rows.length) {
rows = doc.querySelectorAll('#bibliography a.item-container');
}
for (let row of rows) {
let href = row.href;
let title = ZU.trimInternal(row.textContent);
let title = ZU.trimInternal(text(row, '.item-title span:last-child') || row.textContent);
if (!href || !title) continue;
if (checkOnly) return true;
found = true;
@ -85,20 +88,11 @@ function doWeb(doc, url) {
}
function scrape(doc, url) {
if (url.includes('bibliographies.brillonline.com/entries/')) {
scrapeBibliography(doc, url);
if (url.includes('bibliographies.brill.com/items/')) {
scrapeBibliography(doc);
return;
}
if (doc.querySelector('body > meta')) {
// Brill's HTML is structured incorrectly, and it causes some parsers
// to interpret the <meta> tags as being in the body, which breaks EM.
// We'll fix it here.
for (let meta of doc.querySelectorAll('body > meta')) {
doc.head.appendChild(meta);
}
}
var translator = Zotero.loadTranslator('web');
// Embedded Metadata
translator.setTranslator('951c027d-74ac-47d4-a107-9c3069ab7b48');
@ -116,15 +110,38 @@ function scrape(doc, url) {
if (item.itemType == 'book' && item.publicationTitle) {
delete item.publicationTitle;
}
if (item.itemType == 'encyclopediaArticle' && !item.encyclopediaTitle) {
item.encyclopediaTitle = text(doc, '.source-link a');
}
if (item.abstractNote && item.abstractNote.endsWith('by Brill.')) {
delete item.abstractNote;
}
if (!item.publisher) {
item.publisher = 'Brill';
}
if (!item.creators.length) {
// editors often don't make it into the EM
for (let editor of doc.querySelectorAll('.content-contributor-editor a')) {
item.creators.push(ZU.cleanAuthor(editor.textContent, 'editor'));
let creatorNames = [];
let creatorType = 'author';
let line = doc.querySelector('.contributor-line');
if (line) {
switch (text(line, '.creator-type-label').trim()) {
case 'Author:':
case 'Authors:':
creatorType = 'author';
break;
case 'Editor:':
case 'Editors:':
creatorType = 'editor';
break;
}
creatorNames = line.querySelectorAll('.contributor-details .contributor-unlinked, .contributor-details .contributor-details-link');
}
for (let creatorName of creatorNames) {
item.creators.push(ZU.cleanAuthor(creatorName.textContent, creatorType));
}
}
@ -137,21 +154,30 @@ function scrape(doc, url) {
});
translator.getTranslatorObject(function (trans) {
if (url.includes('referenceworks.brillonline.com/entries/')) {
if (url.includes('referenceworks.brill.com/display/entries/')) {
trans.itemType = 'encyclopediaArticle';
}
else if (url.includes('brill.com/edcollbook/')) {
// Delete citation_inbook_title if this is actually a book, not a book section
// Prevents EM from mis-detecting as a bookSection in a way that even setting
// trans.itemType can't override
let bookTitleMeta = doc.querySelector('meta[name="citation_inbook_title"]');
if (bookTitleMeta) {
bookTitleMeta.remove();
}
trans.itemType = 'book';
}
trans.doWeb(doc, url);
});
}
function scrapeBibliography(doc, url) {
function scrapeBibliography(doc) {
let params = new URLSearchParams({
entryId: attr(doc, 'input[name="entryId"]', 'value'),
dest: attr(doc, 'input[name="dest"]', 'value')
keys: attr(doc, 'input[name="keys"]', 'value'),
}).toString();
ZU.doPost('/export/exportRis', params, function (ris) {
ZU.doGet('/BSLO/export/?' + params, function (ris) {
var translator = Zotero.loadTranslator("import");
translator.setTranslator("32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7"); // RIS
translator.setString(ris);
@ -256,7 +282,7 @@ var testCases = [
"ISSN": "0085-2376, 1570-064x",
"abstractNote": "Abstract The Marquis de Fénelons internationally popular didactic narrative, Les aventures de Télémaque, went through a remarkable number of metamorphoses in the Nahḍah, the Arab worlds cultural revival movement of the long nineteenth century. This article examines two early manuscript translations by Syrian Christian writers in the 1810s, the rhymed prose version by Rifāʿah Rāfiʿ al-Ṭahṭāwī in the 1860s; its rewriting by Shāhīn ʿAṭiyyah in 1885; and Saʿdallāh al-Bustānīs musical drama of 1869, the basis for performances later in the century by the famous actor Salāmah Ḥijāzī. Placing Télémaques Arabic trajectory within its global vogue in the Enlightenment suggests ways of reading the Nahḍah between theories of world literature and transnational mass-texts, and more specific local histories of translation and literary adaptation. The ambiguity of Télémaque, its hybrid and transitional form, was important to its success in milieux facing analogous kinds of hybridity and transition—among them those of the Arab Nahḍah.",
"issue": "3",
"language": "en",
"language": "eng",
"libraryCatalog": "brill.com",
"pages": "171-203",
"publicationTitle": "Journal of Arabic Literature",
@ -305,7 +331,7 @@ var testCases = [
},
{
"type": "web",
"url": "https://brill.com/view/title/58302",
"url": "https://brill.com/edcollbook/title/58302",
"items": [
{
"itemType": "book",
@ -342,7 +368,7 @@ var testCases = [
"language": "en",
"libraryCatalog": "brill.com",
"publisher": "Brill",
"url": "https://brill.com/view/title/58302",
"url": "https://brill.com/edcollbook/title/58302",
"attachments": [
{
"title": "Snapshot",
@ -369,7 +395,7 @@ var testCases = [
},
{
"type": "web",
"url": "https://referenceworks.brillonline.com/entries/encyclopaedia-iranica-online/abaev-vasilii-ivanovich-COM_362360",
"url": "https://referenceworks.brill.com/display/entries/EIRO/COM-362360.xml",
"items": [
{
"itemType": "encyclopediaArticle",
@ -381,12 +407,11 @@ var testCases = [
"creatorType": "author"
}
],
"date": "2021-05-10",
"encyclopediaTitle": "Encyclopaedia Iranica Online",
"extra": "DOI: 10.1163/2330-4804_EIRO_COM_362360",
"language": "en",
"libraryCatalog": "referenceworks.brillonline.com",
"publisher": "Brill",
"url": "https://referenceworks.brillonline.com/entries/encyclopaedia-iranica-online/abaev-vasilii-ivanovich-COM_362360",
"libraryCatalog": "referenceworks.brill.com",
"url": "https://referenceworks.brill.com/display/entries/EIRO/COM-362360.xml",
"attachments": [
{
"title": "Snapshot",
@ -401,58 +426,8 @@ var testCases = [
},
{
"type": "web",
"url": "https://referenceworks.brillonline.com/browse/encyclopaedia-iranica-online/alpha/e",
"items": "multiple"
},
{
"type": "web",
"url": "https://bibliographies.brillonline.com/entries/bibliography-of-slavic-linguistics/perspektive-proucavanja-alhamijado-pismenosti-projekt-transkripcije-i-transliteracije-alhamijado-tekstova-lb900000427509?s.num=0&s.f.s2_parent=s.f.book.bibliography-of-slavic-linguistics&s.keywords=%22Abjad%22",
"items": [
{
"itemType": "journalArticle",
"title": "Perspektive proučavanja alhamijado pismenosti : projekt transkripcije i transliteracije alhamijado tekstova",
"creators": [
{
"lastName": "Kalajdžija",
"firstName": "Alen",
"creatorType": "author"
}
],
"date": "2014",
"language": "English",
"libraryCatalog": "Brill",
"pages": "421-430",
"publicationTitle": "Prilozi za orijentalnu filologiju = Contributions to Oriental Philology = Revue de Philologie Orientale",
"shortTitle": "Perspektive proučavanja alhamijado pismenosti",
"url": "https://bibliographies.brillonline.com/entries/bibliography-of-slavic-linguistics/perspektive-proucavanja-alhamijado-pismenosti-projekt-transkripcije-i-transliteracije-alhamijado-tekstova-lb900000427509",
"volume": "64",
"attachments": [],
"tags": [
{
"tag": "Abjad"
},
{
"tag": "Script, orthography"
},
{
"tag": "Serbo-Croatian (Serbian, Croatian, Bosnian)"
},
{
"tag": "Transliteration"
}
],
"notes": [
{
"note": "<p>E. ab.</p>"
}
],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://bibliographies.brillonline.com/search?s.num=0&s.f.s2_parent=s.f.book.bibliography-of-slavic-linguistics&s.keywords=%22Abjad%22",
"url": "https://bibliographies.brill.com/BSLO/items/",
"defer": true,
"items": "multiple"
}
]

153
Brukerhandboken.js Normal file
View File

@ -0,0 +1,153 @@
{
"translatorID": "6c94ba9a-8639-4f58-bea3-076f774cf3a1",
"label": "Brukerhåndboken",
"creator": "Sondre Bogen-Straume",
"target": "https://brukerhandboken\\.miraheze\\.org/",
"minVersion": "5",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2024-06-27 16:03:43"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2024 Sondre Bogen-Straume
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
function detectWeb(doc, url) {
if (url.includes('/wiki/') && doc.querySelector('.printfooter a[href*="oldid="]')) {
return 'encyclopediaArticle';
}
return false;
}
async function doWeb(doc, url) {
await scrape(doc, url);
}
async function scrape(doc, url = doc.location.href) {
let translator = Zotero.loadTranslator('web');
// Wikipedia
translator.setTranslator('e5dc9733-f8fc-4c00-8c40-e53e0bb14664');
translator.setDocument(doc);
translator.setHandler('itemDone', (_obj, item) => {
item.encyclopediaTitle = 'Brukerhåndboken';
item.rights = 'Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International';
item.complete();
});
await translator.translate();
}
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "https://brukerhandboken.miraheze.org/wiki/Brukermedvirkning",
"items": [
{
"itemType": "encyclopediaArticle",
"title": "Brukermedvirkning",
"creators": [],
"date": "2024-05-01T08:31:53Z",
"abstractNote": "Informasjon om brukermedvirkning her.",
"encyclopediaTitle": "Brukerhåndboken",
"extra": "Page Version ID: 912",
"language": "nb",
"libraryCatalog": "Brukerhåndboken",
"rights": "Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International",
"url": "https://brukerhandboken.miraheze.org/wiki/Brukermedvirkning?oldid=912",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html",
"snapshot": true
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://brukerhandboken.miraheze.org/wiki/Forside",
"items": [
{
"itemType": "encyclopediaArticle",
"title": "Forside",
"creators": [],
"date": "2024-05-04T17:20:37Z",
"encyclopediaTitle": "Brukerhåndboken",
"extra": "Page Version ID: 933",
"language": "nb",
"libraryCatalog": "Brukerhåndboken",
"rights": "Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International",
"url": "https://brukerhandboken.miraheze.org/wiki/Forside?oldid=933",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html",
"snapshot": true
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://brukerhandboken.miraheze.org/wiki/Ord_og_forkortelser",
"items": [
{
"itemType": "encyclopediaArticle",
"title": "Ord og forkortelser",
"creators": [],
"date": "2024-06-13T18:54:19Z",
"abstractNote": "Databaseoppføring: Ord og forkortelser - For brukerrepresentanter i helsetjenesten (Q1)\nOrd og forkortelser er en ordbok for brukerrepresentanter i helsetjenesten. Den inneholder ord og forkortelser som brukes hyppig i helsevesenet, og som er som er nyttig å kunne for brukerrepresentanter i helse- og omsorgstjenesten. Innholdet er kurert fra ulike nettsider, dokumenter og liknende. Det er altså ikke jeg som har skrevet alle forklaringene. Henvisning til kildene for tekstene (hvor de er hentet fra) ble når jeg startet på listen ikke tatt med da jeg ikke planla å gjøre den offentlig. Jeg tar nå med kilde i nye oppføringer der det er relevant.\n\nListen er sortert alfabetisk og ment brukt elektronisk da det finnes lenker i tekstene.\nVed forslag til nye ord og forkortelser bruk dette skjemaet: Send inn nytt ord (Airtable) eller e-post. \nVed forslag til endringer eller du har spørsmål ta gjerne kontakt med meg på e-post.\n\nLista er sortert alfabetisk og ment brukt elektronisk da det finnes lenker i tekstene. Noen forkortelser er det brukt punktum.\nLast ned som PDF her.\n\n{{#unlinkedwikibase| id=Q1 }}\n\nOpprettet:\nMal:History-user",
"encyclopediaTitle": "Brukerhåndboken",
"extra": "Page Version ID: 1640",
"language": "nb",
"libraryCatalog": "Brukerhåndboken",
"rights": "Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International",
"url": "https://brukerhandboken.miraheze.org/wiki/Ord_og_forkortelser?oldid=1640",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html",
"snapshot": true
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

439
CBC.js Normal file
View File

@ -0,0 +1,439 @@
{
"translatorID": "03c4b906-8cb2-4850-a771-697cbd92c2a1",
"label": "CBC",
"creator": "Geoff Banh",
"target": "^https?:\\/\\/www\\.cbc\\.ca/",
"minVersion": "5.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2024-03-14 20:55:10"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2024 Geoff Banh
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
function detectWeb(doc, url) {
let path = new URL(url).pathname;
if (path.includes("/search?") && getSearchResults(doc, true)) {
return 'multiple';
}
else if ((/(news|sports|radio|books|arts|music|life|television|archives)\//.test(path)) && getLD(doc)) {
return "newspaperArticle";
}
else if (path.includes("/player/")) {
return "videoRecording";
}
return false;
}
function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
// Adjust the CSS Selectors
var rows = doc.querySelectorAll('.card.cardListing');
for (const row of rows) {
var href = row.href;
var title = text(row, 'h3.headline');
if (!href || !title) continue;
if (checkOnly) return true;
found = true;
items[href] = title;
}
return found ? items : false;
}
function getLD(doc) {
let ldScript = text(doc, "script[type='application/ld+json']");
if (ldScript) return JSON.parse(ldScript);
return null;
}
function getMetaContent(doc, attribute, text) {
return attr(doc.head, 'meta[' + attribute + '="' + text + '"]', 'content');
}
async function scrape(doc, url = doc.location.href) {
let translator = Zotero.loadTranslator('web');
// Embedded Metadata
translator.setTranslator('951c027d-74ac-47d4-a107-9c3069ab7b48');
translator.setDocument(doc);
translator.setHandler('itemDone', (_obj, item) => {
item.language = "en-CA";
let ld = getLD(doc);
// only do processing if page has ld
if (ld) {
item.url = getMetaContent(doc, 'property', "og:url");
item.title = ld.headline ? ld.headline : ld.name;
if (item.itemType == "videoRecording") {
item.date = ZU.strToISO(ld.uploadDate);
}
else {
item.date = ZU.strToISO(ld.datePublished);
}
item.abstractNote = ld.description;
item.creators = []; // clear existing authors
// ignore organization authors
if (ld.hasOwnProperty("author") && ld.author[0]['@type'] != "Organization") {
// either single author or multiple comma separated in one entry
if (ld.author.length == 1) {
let authors = ld.author[0].name;
if (authors.includes(',')) {
let authorsList = authors.split(',');
for (const a of authorsList) {
item.creators.push(ZU.cleanAuthor(a, "author"));
}
}
else {
item.creators.push(ZU.cleanAuthor(authors, "author"));
}
}
else {
for (const a of ld.author) {
item.creators.push(ZU.cleanAuthor(a.name, "author"));
}
}
}
let siteName = "CBC";
if (item.itemType != "videoRecording") {
// get department (e.g. News, Sports, Radio)
// remove .ca/ manually, as regex lookbehind doesn't seem to work
let dept = (/\.ca\/\w+(?=\/)/.exec(item.url))[0].replace(".ca/", "");
// capitalize department
dept = dept[0].toUpperCase() + dept.slice(1);
siteName += " " + dept;
}
item.publicationTitle = siteName;
item.libraryCatalog = "CBC.ca";
}
item.complete();
});
let em = await translator.getTranslatorObject();
em.itemType = detectWeb(doc, url);
await em.doWeb(doc, url);
}
async function doWeb(doc, url) {
if (detectWeb(doc, url) == 'multiple') {
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(await requestDocument(url));
}
}
else {
await scrape(doc, url);
}
}
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "https://www.cbc.ca/news/canada/online-groups-pressuring-youth-self-harm-1.7107885",
"items": [
{
"itemType": "newspaperArticle",
"title": "Violent online groups are pressuring youth into harming themselves, authorities warn",
"creators": [
{
"firstName": "Ioanna",
"lastName": "Roumeliotis",
"creatorType": "author"
},
{
"firstName": "Laurence",
"lastName": "Mathieu-Leger",
"creatorType": "author"
},
{
"firstName": "Andrew",
"lastName": "Culbert",
"creatorType": "author"
}
],
"date": "2024-02-09",
"abstractNote": "Authorities in Canada and the U.S. are warning the public about violent online groups that deliberately target vulnerable minors and pressure them into recording or livestreaming self-harm and producing child sexual abuse material.",
"language": "en-CA",
"libraryCatalog": "CBC.ca",
"publicationTitle": "CBC News",
"url": "https://www.cbc.ca/news/canada/online-groups-pressuring-youth-self-harm-1.7107885",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.cbc.ca/sports/hockey/nhl/elias-pettersson-contract-extension-canucks-nhl-1.7132138",
"items": [
{
"itemType": "newspaperArticle",
"title": "Canucks star forward Elias Pettersson signs 8-year contract extension",
"creators": [
{
"firstName": "Nick",
"lastName": "Wells",
"creatorType": "author"
}
],
"date": "2024-03-02",
"abstractNote": "The Vancouver Canucks and star centre Elias Pettersson have agreed to an eight-year contract extension, the team announced Saturday. He is second in team scoring this season with 75 points on 29 goals and 46 assists.",
"language": "en-CA",
"libraryCatalog": "CBC.ca",
"publicationTitle": "CBC Sports",
"url": "https://www.cbc.ca/sports/hockey/nhl/elias-pettersson-contract-extension-canucks-nhl-1.7132138",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.cbc.ca/player/play/2313671747656",
"items": [
{
"itemType": "videoRecording",
"title": "If you get pulled over by police this month in Regina, expect to take a breathalyzer test",
"creators": [],
"date": "2024-03-02",
"abstractNote": "Everyone who gets pulled over for any reason will get a test. SGI and police are telling people about the plan because not everyone is aware of a 2018 federal law that allows it. CBC's Darla Ponace has more on what you need to know about mandatory roadside alcohol tests.",
"language": "en-CA",
"libraryCatalog": "CBC.ca",
"runningTime": "82.849",
"url": "https://www.cbc.ca/player/play/2313671747656",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.cbc.ca/radio/thecurrent/airport-facial-recognition-biometrics-1.7130000",
"items": [
{
"itemType": "newspaperArticle",
"title": "Airports want to scan your face to make travelling easier. Privacy experts caution it's not ready for takeoff",
"creators": [
{
"firstName": "Jason",
"lastName": "Vermes",
"creatorType": "author"
}
],
"date": "2024-03-03",
"abstractNote": "While airlines and airports say facial recognition can make air travel — an often tedious experience — more efficient and seamless, privacy advocates argue the use of biometric data is fraught and open to abuse.",
"language": "en-CA",
"libraryCatalog": "CBC.ca",
"publicationTitle": "CBC Radio",
"url": "https://www.cbc.ca/radio/thecurrent/airport-facial-recognition-biometrics-1.7130000",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.cbc.ca/radio/frequency",
"detectedItemType": false,
"items": []
},
{
"type": "web",
"url": "https://www.cbc.ca/news/politics/trudeau-meloni-pro-palestinian-protesters-toronto-1.7132378",
"items": [
{
"itemType": "newspaperArticle",
"title": "Trudeau's Toronto event with Italy PM Meloni cancelled due to pro-Palestinian protest",
"creators": [
{
"firstName": "Justin",
"lastName": "Li",
"creatorType": "author"
},
{
"firstName": "Christian",
"lastName": "Paas-Lang",
"creatorType": "author"
}
],
"date": "2024-03-03",
"abstractNote": "A Toronto event where Canadian Prime Minister Justin Trudeau was scheduled to host his Italian counterpart was cancelled on Saturday due to security concerns as hundreds of pro-Palestinian protesters gathered outside the venue, a spokesperson for the Prime Minister's Office said.",
"language": "en-CA",
"libraryCatalog": "CBC.ca",
"publicationTitle": "CBC News",
"url": "https://www.cbc.ca/news/politics/trudeau-meloni-pro-palestinian-protesters-toronto-1.7132378",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.cbc.ca/music/canadian-reggae-songs-record-labels-1.7116717",
"items": [
{
"itemType": "newspaperArticle",
"title": "Canadian reggae's past, present and future",
"creators": [
{
"firstName": "Kelsey",
"lastName": "Adams",
"creatorType": "author"
}
],
"date": "2024-02-23",
"abstractNote": "From the 1st recording on Canadian soil to the newcomers pushing the genre forward today.",
"language": "en-CA",
"libraryCatalog": "CBC.ca",
"publicationTitle": "CBC Music",
"url": "https://www.cbc.ca/music/canadian-reggae-songs-record-labels-1.7116717",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.cbc.ca/life/culture/the-best-card-games-to-play-with-a-standard-deck-1.5836447",
"items": [
{
"itemType": "newspaperArticle",
"title": "The best card games to play with a standard deck",
"creators": [
{
"firstName": "Sebastian",
"lastName": "Yūe",
"creatorType": "author"
}
],
"date": "2020-12-10",
"abstractNote": "This list will have you suggesting card night every chance you get!",
"language": "en-CA",
"libraryCatalog": "CBC.ca",
"publicationTitle": "CBC Life",
"url": "https://www.cbc.ca/life/culture/the-best-card-games-to-play-with-a-standard-deck-1.5836447",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.cbc.ca/television/he-landed-a-sitcom-role-on-his-first-audition-i-was-really-hyped-says-scarborough-teen-1.7101522",
"items": [
{
"itemType": "newspaperArticle",
"title": "He landed a sitcom role on his first audition. 'I was really hyped,' says Scarborough teen",
"creators": [
{
"firstName": "Russ",
"lastName": "Martin",
"creatorType": "author"
}
],
"date": "2024-02-05",
"abstractNote": "The new CBC workplace comedy One More Time follows the manager of a second-hand sporting goods shop, DJ, played by comedian D.J. Demers, and the hijinks of his beloved gang of oddball employees. Among the motley crew is Keeran Devkar, a very green first-time associate played by 15-year-old Seran Sathiyaseelan.",
"language": "en-CA",
"libraryCatalog": "CBC.ca",
"publicationTitle": "CBC Television",
"url": "https://www.cbc.ca/television/he-landed-a-sitcom-role-on-his-first-audition-i-was-really-hyped-says-scarborough-teen-1.7101522",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.cbc.ca/search?q=Windows%2011&section=arts&sortOrder=relevance&media=all",
"items": "multiple"
}
]
/** END TEST CASES **/

170
CFF References.js Normal file
View File

@ -0,0 +1,170 @@
{
"translatorID": "99A6641F-A8C2-4923-9BBB-0DA87F1E5187",
"label": "CFF References",
"creator": "Sebastian Karcher, Dave Bunten",
"target": "cff",
"minVersion": "5.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 2,
"lastUpdated": "2024-05-17 20:02:13"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2024 Sebastian Karcher, Dave Bunten
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
// set a global for spacing purposes under the references key of a citation.cff file
var referencesSpacing = ' ';
function writeArray(array) {
if (!array.length) return false;
let output = "\n";
for (let elem of array) {
if (!elem) continue;
output += referencesSpacing + " - " + elem + "\n";
}
return output.replace(/\n$/, "");
}
function writeDOI(itemDOI) {
if (!itemDOI) return false;
let doi = "\n" + referencesSpacing + " - type: doi\n" + referencesSpacing + " value: " + itemDOI;
return doi;
}
function writeCreators(itemCreators, creatorType="") {
let itemAuthors = [];
for (let creator of itemCreators) {
if (creatorType != "" && ZU.getCreatorsForType(creator.itemType)[0] == creatorType) {
itemAuthors.push(creator);
}
else {
itemAuthors.push(creator);
}
}
if (!itemAuthors.length) return false;
let authors = "\n";
for (let author of itemAuthors) {
authors += referencesSpacing + " - family-names: " + author.lastName + "\n";
if (author.firstName) {
authors += referencesSpacing + " given-names: " + author.firstName + "\n";
}
}
return authors.replace(/\n$/, "");
}
function doExport() {
var item;
Zotero.write('# This CITATION.cff reference content was generated from Zotero.\n');
Zotero.write('references:\n');
while ((item = Zotero.nextItem())) {
var cff = {};
cff.title = ">-\n" + referencesSpacing + " " + item.title + "\n";
cff.abstract = item.abstractNote;
cff.type = item.itemType;
cff.license = item.rights;
cff.version = item.versionNumber;
cff.collection_title = item.proceedingsTitle;
cff.conference = item.conferenceName;
cff.copyright = item.rights;
cff.database = item.libraryCatalog;
cff.date_accessed = item.accessDate;
cff.edition = item.edition;
cff.editors_series = item.series
cff.format = item.format;
cff.institution = item.institution;
cff.isbn = item.ISBN;
cff.issn = item.ISSN;
cff.issue = item.issue;
cff.issue_date = item.issueDate;
cff.journal = item.journalAbbreviation;
cff.languages = writeArray([item.language]);
cff.location = item.archiveLocation;
cff.medium = item.medium;
cff.number = item.number;
cff.number_volumes = item.numberOfVolumes;
cff.pages = item.pages;
// match for pmcid within extras content
if (item.extra && /^pmcid:/i.test(item.extra)) {
cff.pmcid = item.extra.match(/pmcid:\s*(\S+)/);
}
cff.publisher = item.publisher;
cff.repository = item.repository;
cff.section = item.section;
cff.thesis_type = item.thesisType;
cff.volume = item.volume;
cff.url = item.url;
cff.keywords = writeArray(item.tags.map(tag => tag.tag || tag));
if (["letter", "email", "instantMessage"].includes(item.itemType)) {
cff.senders = writeCreators(item.creators, "author");
}
else {
cff.authors = writeCreators(item.creators, ZU.getCreatorsForType(item.itemType)[0]);
}
cff.editors = writeCreators(item.creators, "editor");
cff.recipients = writeCreators(item.creators, "recipient");
cff.translators = writeCreators(item.creators, "translator");
if (item.date) {
// if we have a dataset or software, use date-released field
if (item.itemType == "dataset" || item.itemType == "computerProgram") {
cff["date-released"] = ZU.strToISO(item.date);
}
// include date published for any item types
cff["date-published"] = ZU.strToISO(item.date);
}
// get DOI from Extra for software; this will stop running automatically once software supports DOI
if (!ZU.fieldIsValidForType('DOI', item.itemType) && /^doi:/im.test(item.extra)) {
item.DOI = ZU.cleanDOI(item.extra);
}
cff.identifiers = writeDOI(item.DOI);
// prep the entry as a new item
Zotero.write(' - ');
// loop through the cff elements and write output
for (let field in cff) {
if (!cff[field]) continue;
if (field == "title") {
// rely on prep dash for item start above for titles
Zotero.write(field + ": " + cff[field]);
}
else if (field == "abstract") {
// multiline
Zotero.write(referencesSpacing + field + ": |" + cff[field].replace(/^|\n/g, "\n" + referencesSpacing + " ") + "\n");
}
else {
Zotero.write(referencesSpacing + field.replace("_", "-") + ": " + cff[field] + "\n");
}
}
}
}
/** BEGIN TEST CASES **/
var testCases = [
]
/** END TEST CASES **/

388
CNKI.js
View File

@ -9,7 +9,7 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2023-03-08 12:33:13"
"lastUpdated": "2023-11-27 05:30:22"
}
/*
@ -38,47 +38,35 @@
// Fetches RefWorks records for provided IDs and calls onDataAvailable with resulting text
// ids should be in the form [{dbname: "CDFDLAST2013", filename: "1013102302.nh"}]
function getRefWorksByID(ids, onDataAvailable) {
if (!ids.length) return;
var { dbname, filename, url } = ids.shift();
let postData = "filename=" + filename +
"&displaymode=Refworks&orderparam=0&ordertype=desc&selectfield=&dbname=" +
dbname + "&random=0.2111567532240084";
ZU.doPost('https://kns.cnki.net/KNS8/manage/ShowExport', postData,
function (text) {
let data = text
.replace("<ul class='literature-list'><li>", "")
.replace("<br></li></ul>", "")
.replace("</li><li>", "") // divide results
.replace(/<br>|\r/g, "\n")
.replace(/vo (\d+)\n/, "VO $1\n") // Divide VO and IS to different line
.replace(/IS 0(\d+)\n/g, "IS $1\n") // Remove leading 0
.replace(/VO 0(\d+)\n/g, "VO $1\n")
.replace(/\n+/g, "\n")
.replace(/\n([A-Z][A-Z1-9]\s)/g, "<br>$1")
.replace(/\n/g, "")
.replace(/<br>/g, "\n")
.replace(/\t/g, "") // \t in abstract
.replace(
/^RT\s+Conference Proceeding/gim,
"RT Conference Proceedings"
)
.replace(/^RT\s+Dissertation\/Thesis/gim, "RT Dissertation")
.replace(/^(A[1-4]|U2)\s*([^\r\n]+)/gm, function (m, tag, authors) {
authors = authors.split(/\s*[;,]\s*/); // that's a special comma
if (!authors[authors.length - 1].trim()) authors.pop();
return tag + " " + authors.join("\n" + tag + " ");
})
.trim();
// Z.debug(data);
onDataAvailable(data, url);
// If more results, keep going
if (ids.length) {
getRefWorksByID(ids, onDataAvailable);
}
}
);
function toStdRef(reftext) {
return reftext
.body
.replace("<ul class='literature-list'><li>", "")
.replace("<br></li></ul>", "")
.replace("</li><li>", "") // divide results
.replace(/<br>|\r/g, "\n")
.replace(/vo (\d+)\n/, "VO $1\n") // Divide VO and IS to different line
.replace(/IS (\d+)\nvo/, "IS $1\nVO")// Uppercase VO
.replace(/IS 0(\d+)\n/g, "IS $1\n")// Remove leading 0
.replace(/VO 0(\d+)\n/g, "VO $1\n")
.replace(/\n+/g, "\n")
.replace(/\n([A-Z][A-Z1-9]\s)/g, "<br>$1")
.replace(/\n/g, "")
.replace(/<br>/g, "\n")
.replace(/(K1 .*[\u4e00-\u9fa5]) ([a-zA-Z])/g, "$1;$2")// cn keywwords and en keywords
.replace(/\t/g, "") // \t in abstract
.replace(
/^RT\s+Conference Proceeding/gim,
"RT Conference Proceedings"
)
.replace(/^RT\s+Dissertation\/Thesis/gim, "RT Dissertation")
.replace(/^(A[1-4]|U2)\s*([^\r\n]+)/gm, function (m, tag, authors) {
authors = authors.split(/\s*[;,]\s*/); // that's a special comma
if (!authors[authors.length - 1].trim()) authors.pop();
return tag + " " + authors.join("\n" + tag + " ");
})
.replace(/LA 中文;?/g, "LA zh-CN")
.trim();
}
function getIDFromURL(url) {
@ -96,7 +84,12 @@ function getIDFromURL(url) {
function getIDFromRef(doc, url) {
let database = attr(doc, '#paramdbname', 'value');
let filename = attr(doc, '#paramfilename', 'value');
return { dbname: database, filename: filename, url: url };
if (database && filename) {
return { dbname: database, filename: filename, url: url };
}
else {
return false;
}
}
// Get dbname and filename from the link target on the "take note" button in
@ -107,7 +100,7 @@ function getIDFromRef(doc, url) {
// required info. The note-taking button appears more stable across the CNKI
// domains.
function getIDFromNoteTakerLink(doc, url) {
const noteURLString = doc.querySelector("li.btn-note a").href;
const noteURLString = attr(doc, "li.btn-note a", "href");
if (!noteURLString) return false;
const urlParams = new URLSearchParams(new URL(noteURLString).search);
@ -119,6 +112,17 @@ function getIDFromNoteTakerLink(doc, url) {
return { dbname: dbnameValue, filename: filenameValue, url: url };
}
function getIDFromSearchRow(row) {
var dbcode = attr(row, "a.icon-collect", "data-dbname");
var filename = attr(row, "a.icon-collect", "data-filename");
if (dbcode && filename) {
return { dbcode: dbcode, dbname: dbcode, filename: filename };
}
else {
return false;
}
}
function getIDFromPage(doc, url) {
return getIDFromURL(url)
|| getIDFromRef(doc, url)
@ -130,14 +134,21 @@ function getTypeFromDBName(dbname) {
CJFQ: "journalArticle",
CJFD: "journalArticle",
CAPJ: "journalArticle",
SJES: "journalArticle",
SJPD: "journalArticle",
SSJD: "journalArticle",
CCJD: "journalArticle",
CDMD: "journalArticle",
CYFD: "journalArticle",
CDFD: "thesis",
CMFD: "thesis",
CLKM: "thesis",
CCND: "newspaperArticle",
CPFD: "conferencePaper",
IPFD: "conferencePaper",
SCPD: "patent"
};
var db = dbname.substr(0, 4).toUpperCase();
var db = dbname.substring(0, 4).toUpperCase();
if (dbType[db]) {
return dbType[db];
}
@ -161,7 +172,6 @@ function getItemsFromSearchResults(doc, url, itemInfo) {
links = ZU.xpath(doc, '//table[@class="GridTableContent"]/tbody/tr[./td[2]/a]');
aXpath = './td[2]/a';
}
if (!links.length) {
return false;
}
@ -171,7 +181,7 @@ function getItemsFromSearchResults(doc, url, itemInfo) {
var a = ZU.xpath(links[i], aXpath)[0];
var title = ZU.xpathText(a, './node()[not(name()="SCRIPT")]', null, '');
if (title) title = ZU.trimInternal(title);
var id = getIDFromURL(a.href);
var id = getIDFromURL(a.href) || getIDFromSearchRow(links[i]);
// pre-released item can not get ID from URL, try to get ID from element.value
if (!id) {
var td1 = ZU.xpath(links[i], './td')[0];
@ -191,6 +201,10 @@ function detectWeb(doc, url) {
// Z.debug(doc);
var id = getIDFromPage(doc, url);
var items = getItemsFromSearchResults(doc, url);
var searchResult = doc.querySelector("#ModuleSearchResult");
if (searchResult) {
Z.monitorDOMChanges(searchResult, { childList: true, subtree: true });
}
if (id) {
return getTypeFromDBName(id.dbname);
}
@ -202,99 +216,96 @@ function detectWeb(doc, url) {
}
}
function doWeb(doc, url) {
async function doWeb(doc, url) {
if (detectWeb(doc, url) == "multiple") {
var itemInfo = {};
var items = getItemsFromSearchResults(doc, url, itemInfo);
Z.selectItems(items, function (selectedItems) {
if (!selectedItems) return;
var itemInfoByTitle = {};
var ids = [];
for (var url in selectedItems) {
ids.push(itemInfo[url].id);
itemInfoByTitle[selectedItems[url]] = itemInfo[url];
itemInfoByTitle[selectedItems[url]].url = url;
let selectItems = await Z.selectItems(items);
if (selectItems) {
for (let url in selectItems) {
await scrape(itemInfo[url].id, doc, { url: url });
}
scrape(ids, doc, url, itemInfoByTitle);
});
}
}
else {
scrape([getIDFromPage(doc, url)], doc, url);
await scrape(getIDFromPage(doc, url), doc);
}
}
function scrape(ids, doc, url, itemInfo) {
getRefWorksByID(ids, function (text) {
var translator = Z.loadTranslator('import');
translator.setTranslator('1a3506da-a303-4b0a-a1cd-f216e6138d86'); // RefWorks Tagged
text = text.replace(/IS (\d+)\nvo/, "IS $1\nVO");
translator.setString(text);
translator.setHandler('itemDone', function (obj, newItem) {
// split names
for (var i = 0, n = newItem.creators.length; i < n; i++) {
var creator = newItem.creators[i];
if (creator.firstName) continue;
var lastSpace = creator.lastName.lastIndexOf(' ');
var lastMiddleDot = creator.lastName.lastIndexOf('·');
if (creator.lastName.search(/[A-Za-z]/) !== -1 && lastSpace !== -1) {
// western name. split on last space
creator.firstName = creator.lastName.substr(0, lastSpace);
creator.lastName = creator.lastName.substr(lastSpace + 1);
}
else if (lastMiddleDot !== -1) {
// translated western name with · as separator
creator.firstName = creator.lastName.substr(0, lastMiddleDot);
creator.lastName = creator.lastName.substr(lastMiddleDot + 1);
}
else {
// Chinese name. first character is last name, the rest are first name
creator.firstName = creator.lastName.substr(1);
creator.lastName = creator.lastName.charAt(0);
}
async function scrape(id, doc, extraData) {
var { dbname, filename } = id;
var postData = `FileName=${dbname}!${filename}!1!0&DisplayMode=Refworks&OrderParam=0&OrderType=desc&SelectField=&PageIndex=1&PageSize=20&language=&uniplatform=NZKPT&random=0.30585230060685187`;
var refer = `https://kns.cnki.net/dm/manage/export.html?filename=${dbname}!${filename}!1!0&displaymode=NEW&uniplatform=NZKPT`;
var reftext = await request(
'https://kns.cnki.net/dm/api/ShowExport',
{
method: "POST",
body: postData,
headers: {
Referer: refer
}
}
);
var translator = Z.loadTranslator('import');
translator.setTranslator('1a3506da-a303-4b0a-a1cd-f216e6138d86'); // RefWorks Tagged
translator.setString(toStdRef(reftext));
translator.setHandler('itemDone', function (obj, newItem) {
// split names
for (var i = 0, n = newItem.creators.length; i < n; i++) {
var creator = newItem.creators[i];
if (creator.firstName) continue;
if (newItem.abstractNote) {
newItem.abstractNote = newItem.abstractNote.replace(/\s*[\r\n]\s*/g, '\n');
var lastSpace = creator.lastName.lastIndexOf(' ');
var lastMiddleDot = creator.lastName.lastIndexOf('·');
if (/[A-Za-z]/.test(creator.lastName) && lastSpace !== -1) {
// western name. split on last space
creator.firstName = creator.lastName.substring(0, lastSpace);
creator.lastName = creator.lastName.substring(lastSpace + 1);
}
// clean up tags. Remove numbers from end
for (var j = 0, l = newItem.tags.length; j < l; j++) {
newItem.tags[j] = newItem.tags[j].replace(/:\d+$/, '');
}
newItem.title = ZU.trimInternal(newItem.title);
if (itemInfo) {
var info = itemInfo[newItem.title];
if (!info) {
Z.debug('No item info for "' + newItem.title + '"');
}
else {
newItem.url = info.url;
}
else if (lastMiddleDot !== -1) {
// translated western name with · as separator
creator.firstName = creator.lastName.substring(0, lastMiddleDot);
creator.lastName = creator.lastName.substring(lastMiddleDot + 1);
}
else {
newItem.url = url;
// Chinese name. first character is last name, the rest are first name
creator.firstName = creator.lastName.substring(1);
creator.lastName = creator.lastName.charAt(0);
}
// CN 中国刊物编号非refworks中的callNumber
// CN in CNKI refworks format explains Chinese version of ISSN
if (newItem.callNumber) {
// newItem.extra = 'CN ' + newItem.callNumber;
newItem.callNumber = "";
}
// don't download PDF/CAJ on searchResult(multiple)
var webType = detectWeb(doc, url);
if (webType && webType != 'multiple') {
newItem.attachments = getAttachments(doc, newItem);
}
newItem.complete();
});
}
translator.translate();
if (newItem.abstractNote) {
newItem.abstractNote = newItem.abstractNote.replace(/\s*[\r\n]\s*/g, '\n');
}
// clean up tags. Remove numbers from end
for (var j = 0, l = newItem.tags.length; j < l; j++) {
newItem.tags[j] = newItem.tags[j].replace(/:\d+$/, '');
}
newItem.title = ZU.trimInternal(newItem.title);
if (extraData) {
newItem.url = extraData.url;
}
else {
newItem.url = id.url;
}
// CN 中国刊物编号非refworks中的callNumber
// CN in CNKI refworks format explains Chinese version of ISSN
if (newItem.callNumber) {
// newItem.extra = 'CN ' + newItem.callNumber;
newItem.callNumber = "";
}
// don't download PDF/CAJ on searchResult(multiple)
var webType = detectWeb(doc, id.url);
if (webType && webType != 'multiple') {
newItem.attachments = getAttachments(doc, newItem);
}
newItem.complete();
});
translator.translate();
}
// get pdf download link
@ -351,6 +362,7 @@ var testCases = [
{
"type": "web",
"url": "https://kns.cnki.net/KCMS/detail/detail.aspx?dbcode=CJFQ&dbname=CJFDLAST2015&filename=SPZZ201412003&v=MTU2MzMzcVRyV00xRnJDVVJMS2ZidVptRmkva1ZiL09OajNSZExHNEg5WE5yWTlGWjRSOGVYMUx1eFlTN0RoMVQ=",
"defer": true,
"items": [
{
"itemType": "journalArticle",
@ -391,29 +403,19 @@ var testCases = [
"ISSN": "1000-8713",
"abstractNote": "来自中药的水溶性多糖具有广谱治疗和低毒性特点,是天然药物及保健品研发中的重要组成部分。针对中药多糖结构复杂、难以表征的问题,本文以中药黄芪中的多糖为研究对象,采用\"自下而上\"法完成对黄芪多糖的表征。首先使用部分酸水解方法水解黄芪多糖,分别考察了水解时间、酸浓度和温度的影响。在适宜条件(4 h、1.5mol/L三氟乙酸、80℃)下,黄芪多糖被水解为特征性的寡糖片段。接下来,采用亲水作用色谱与质谱联用对黄芪多糖部分酸水解产物进行分离和结构表征。结果表明,提取得到的黄芪多糖主要为1→4连接线性葡聚糖,水解得到聚合度4~11的葡寡糖。本研究对其他中药多糖的表征具有一定的示范作用。",
"issue": "12",
"language": "中文;",
"language": "zh-CN",
"libraryCatalog": "CNKI",
"pages": "1306-1312",
"publicationTitle": "色谱",
"url": "https://kns.cnki.net/KCMS/detail/detail.aspx?dbcode=CJFQ&dbname=CJFDLAST2015&filename=SPZZ201412003&v=MTU2MzMzcVRyV00xRnJDVVJMS2ZidVptRmkva1ZiL09OajNSZExHNEg5WE5yWTlGWjRSOGVYMUx1eFlTN0RoMVQ=",
"volume": "32",
"attachments": [],
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [
{
"tag": "Astragalus"
},
{
"tag": "characterization"
},
{
"tag": "hydrophilic interaction liquid chromatography(HILIC)mass spectrometry(MS)"
},
{
"tag": "partial acid hydrolysis"
},
{
"tag": "polysaccharides"
},
{
"tag": "亲水作用色谱"
},
@ -441,6 +443,7 @@ var testCases = [
{
"type": "web",
"url": "https://kns.cnki.net/KCMS/detail/detail.aspx?dbcode=CMFD&dbname=CMFD201701&filename=1017045605.nh&v=MDc3ODZPZVorVnZGQ3ZrV3JyT1ZGMjZHYk84RzlmTXFwRWJQSVI4ZVgxTHV4WVM3RGgxVDNxVHJXTTFGckNVUkw=",
"defer": true,
"items": [
{
"itemType": "thesis",
@ -452,27 +455,15 @@ var testCases = [
"creatorType": "author"
}
],
"date": "2015",
"abstractNote": "黄瓜(Cucumis sativus L.)是我国最大的保护地栽培蔬菜作物,也是植物性别发育和维管束运输研究的重要模式植物。黄瓜基因组序列图谱已经构建完成,并且在此基础上又完成了全基因组SSR标记开发和涵盖330万个变异位点变异组图谱,成为黄瓜功能基因研究的重要平台和工具,相关转录组研究也有很多报道,不过共表达网络研究还是空白。本实验以温室型黄瓜9930为研究对象,选取10个不同组织,进行转录组测序,获得10份转录组原始数据。在对原始数据去除接头与低质量读段后,将高质量读段用Tophat2回贴到已经发表的栽培黄瓜基因组序列上。用Cufflinks对回贴后的数据计算FPKM值,获得10份组织的2...",
"language": "中文;",
"date": "2017",
"abstractNote": "黄瓜(Cucumis sativus L.)是我国最大的保护地栽培蔬菜作物,也是植物性别发育和维管束运输研究的重要模式植物。黄瓜基因组序列图谱已经构建完成,并且在此基础上又完成了全基因组SSR标记开发和涵盖330万个变异位点变异组图谱,成为黄瓜功能基因研究的重要平台和工具,相关转录组研究也有很多报道,不过共表达网络研究还是空白。本实验以温室型黄瓜9930为研究对象,选取10个不同组织,进行转录组测序,获得10份转录组原始数据。在对原始数据去除接头与低质量读段后,将高质量读段用Tophat2回贴到已经发表的栽培黄瓜基因组序列上。用Cufflinks对回贴后的数据计算FPKM值,获得10份组织的24274基因的表达量数据。计算结果中的回贴率比较理想,不过有些基因的表达量过低。为了防止表达量低的基因对结果的影响,将10份组织中表达量最大小于5的基因去除,得到16924个基因,进行下一步分析。共表达网络的构建过程是将上步获得的表达量数据,利用R语言中WGCNA(weighted gene co-expression network analysis)包构建共表达网络。结果得到的共表达网络包括1134个模块。这些模块中的基因表达模式类似,可以认为是共表达关系。不过结果中一些模块内基因间相关性同其他模块相比比较低,在分析过程中,将模块中基因相关性平均值低于0.9的模块都去除,最终得到839个模块,一共11,844个基因。共表达的基因因其表达模式类似而聚在一起,这些基因可能与10份组织存在特异性关联。为了计算模块与组织间的相关性,首先要对每个模块进行主成分分析(principle component analysis,PCA),获得特征基因(module eigengene,ME),特征基因可以表示这个模块所有基因共有的表达趋势。通过计算特征基因与组织间的相关性,从而挑选出组织特异性模块,这些模块一共有323个。利用topGO功能富集分析的结果表明这些特异性模块所富集的功能与组织相关。共表达基因在染色体上的物理位置经常是成簇分布的。按照基因间隔小于25kb为标准。分别对839个模块进行分析,结果发现在71个模块中共有220个cluster,这些cluster 一般有25个基因,cluster中的基因在功能上也表现出一定的联系。共表达基因可能受到相同的转录调控,这些基因在启动子前2kb可能会存在有相同的motif以供反式作用元...",
"language": "zh-CN",
"libraryCatalog": "CNKI",
"thesisType": "硕士",
"university": "南京农业大学",
"url": "https://kns.cnki.net/KCMS/detail/detail.aspx?dbcode=CMFD&dbname=CMFD201701&filename=1017045605.nh&v=MDc3ODZPZVorVnZGQ3ZrV3JyT1ZGMjZHYk84RzlmTXFwRWJQSVI4ZVgxTHV4WVM3RGgxVDNxVHJXTTFGckNVUkw=",
"attachments": [],
"tags": [
{
"tag": "co-expression"
},
{
"tag": "cucumber"
},
{
"tag": "network"
},
{
"tag": "transcriptome"
},
{
"tag": "共表达"
},
@ -494,6 +485,7 @@ var testCases = [
{
"type": "web",
"url": "https://kns.cnki.net/kcms/detail/detail.aspx?dbcode=CCJD&dbname=CCJDLAST2&filename=ZKSF202002010&uniplatform=NZKPT&v=RM9dl7WiC7a9v7FVB6ov3OwJSXCWzsWIng_BWXok2rj4YFWz9tZ20FRZxDaeDPCm",
"defer": true,
"items": [
{
"itemType": "journalArticle",
@ -511,16 +503,21 @@ var testCases = [
}
],
"date": "2020",
"abstractNote": "&lt;正&gt;一、简介近来再次对俄罗斯(1993)和西班牙(1995)陪审团审判模式进行介绍的原因有两个方面。第一,在废除传统陪审团审判的情况下,要么采取仅由职业法官组成的法院审理案件,要么由职业法官和审讯顾问合议来判断所有的事实问题、法律问题并作出相应判决,这是一种令人惊闻的倒退。",
"issue": "02",
"language": "中文;",
"abstractNote": "<正>一、简介近来再次对俄罗斯(1993)和西班牙(1995)陪审团审判模式进行介绍的原因有两个方面。第一,在废除传统陪审团审判的情况下,要么采取仅由职业法官组成的法院审理案件,要么由职业法官和审讯顾问合议来判断所有的事实问题、法律问题并作出相应判决,这是一种令人惊闻的倒退。",
"issue": "2",
"language": "zh-CN",
"libraryCatalog": "CNKI",
"pages": "193-212",
"publicationTitle": "司法智库",
"shortTitle": "欧洲陪审团制度新发展",
"url": "https://kns.cnki.net/kcms/detail/detail.aspx?dbcode=CCJD&dbname=CCJDLAST2&filename=ZKSF202002010&uniplatform=NZKPT&v=RM9dl7WiC7a9v7FVB6ov3OwJSXCWzsWIng_BWXok2rj4YFWz9tZ20FRZxDaeDPCm",
"volume": "3",
"attachments": [],
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [
{
"tag": "俄罗斯"
@ -545,7 +542,8 @@ var testCases = [
},
{
"type": "web",
"url": "https://kns.cnki.net/kcms2/article/abstract?v=3uoqIhG8C44YLTlOAiTRKibYlV5Vjs7ioT0BO4yQ4m_mOgeS2ml3UHGnAz_wirMwf-b2NsjH_IkCCqUvvwsK8DOvNyxMAxbu&uniplatform=NZKPT",
"url": "https://kns.cnki.net/kcms2/article/abstract?v=aGn3Ey0ZxcAi0XeGEjt5HeH9QvBBKaMwsES4SuFJjIdiexE2qhU8bX2aGBIHriUe6WrMOFyCz6TIuYJGlA_YQUO9h2FJwGt_gZfkHkLHnqVgNK8uMWo5lKYMqxvBPfO6_0Zy21140lIwEFrUw-cJtw==&uniplatform=NZKPT",
"defer": true,
"items": [
{
"itemType": "journalArticle",
@ -559,31 +557,21 @@ var testCases = [
],
"date": "2022",
"ISSN": "1001-2397",
"abstractNote": "我国绿色产品认证标识制度框架已初步形成。作为一项法律制度,绿色产品标识及认证中形成了两组法律关系:一是就产品认可认证,在行政主体、认证机构与申请人之间构成公私混合的规制关系;二是就绿色产品标识授权使用,在上述法律关系主体间构成的商业许可关系。两组法律关系的搭建,形成了我国绿色产品认证标识制度的基本格局。制度的具体完善路径是将现行同类环保产品认证标识纳入绿色产品标识与绿色属性产品标识的二元框架内,或吸收,或拆解,或由市场逐步淘汰,最终形成统一的绿色产品认证标识体系。在制度构建过程中,对第三方认证机构的规制成为制度有效运行的关键。参考域外经验,我国应当通过强化认证机构的独立性,平衡认证机构与申请人...",
"issue": "06",
"language": "中文;",
"abstractNote": "我国绿色产品认证标识制度框架已初步形成。作为一项法律制度,绿色产品标识及认证中形成了两组法律关系:一是就产品认可认证,在行政主体、认证机构与申请人之间构成公私混合的规制关系;二是就绿色产品标识授权使用,在上述法律关系主体间构成的商业许可关系。两组法律关系的搭建,形成了我国绿色产品认证标识制度的基本格局。制度的具体完善路径是将现行同类环保产品认证标识纳入绿色产品标识与绿色属性产品标识的二元框架内,或吸收,或拆解,或由市场逐步淘汰,最终形成统一的绿色产品认证标识体系。在制度构建过程中,对第三方认证机构的规制成为制度有效运行的关键。参考域外经验,我国应当通过强化认证机构的独立性,平衡认证机构与申请人之间的制约关系,以及通过加强行政监管与社会监督,防止认证权力寻租,充分发挥绿色产品认证标识制度的实践效果。",
"issue": "6",
"language": "zh-CN",
"libraryCatalog": "CNKI",
"pages": "133-145",
"publicationTitle": "现代法学",
"url": "https://kns.cnki.net/kcms2/article/abstract?v=3uoqIhG8C44YLTlOAiTRKibYlV5Vjs7ioT0BO4yQ4m_mOgeS2ml3UHGnAz_wirMwf-b2NsjH_IkCCqUvvwsK8DOvNyxMAxbu&uniplatform=NZKPT",
"url": "https://kns.cnki.net/kcms2/article/abstract?v=aGn3Ey0ZxcAi0XeGEjt5HeH9QvBBKaMwsES4SuFJjIdiexE2qhU8bX2aGBIHriUe6WrMOFyCz6TIuYJGlA_YQUO9h2FJwGt_gZfkHkLHnqVgNK8uMWo5lKYMqxvBPfO6_0Zy21140lIwEFrUw-cJtw==&uniplatform=NZKPT",
"volume": "44",
"attachments": [],
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [
{
"tag": "certification trade mark"
},
{
"tag": "green product certification"
},
{
"tag": "green product identification"
},
{
"tag": "green products"
},
{
"tag": "third party certification"
},
{
"tag": "第三方认证"
},
@ -607,7 +595,8 @@ var testCases = [
},
{
"type": "web",
"url": "https://kns.cnki.net/kcms2/article/abstract?v=ARuSRxW-FQHH_OEY6X72RuJIsrP2RHAQAacVbC9CGuvOv08ETIP-MqQO5E296beGN9e8BXVfYGR6l0qfpFxS9gdAPZ5URHqiAY8WVPwSYoF6MXeqOgFQfX5vrMMS_wZaK3j5TPxvx-nDGPfIMtrXBlDrWr9SVlAl&uniplatform=NZKPT",
"url": "https://kns.cnki.net/kcms2/article/abstract?v=aGn3Ey0ZxcCQMiRSLWzbqHFLmF0YiAvOI33I1RqvSIDdZeLKl7q3QL7ioYjCbxuMHo1CSBSG2LYUjI9r30yPonoox-iGbCfgn-YF7W2h79KqPswOTOxrzPV94p2evWa1-zchF2wLCag2WcjSEGNUdSNYdPlVmcGt&uniplatform=NZKPT",
"defer": true,
"items": [
{
"itemType": "journalArticle",
@ -621,15 +610,20 @@ var testCases = [
],
"date": "2022",
"ISSN": "1671-7287",
"abstractNote": "我国对常规污染物的治理取得了显著成效,但以有毒有害化学物质的生产和使用为主要来源的新污染物的环境风险仍然较为严峻。当前我国相关环境法律法规和标准中缺乏对新污染物环境风险管控的要求,对于现有化学物质的环境风险管控还存在较为严重的不足。未来环境法典中新污染物环境风险管控立法应当坚持风险预防原则,但风险预防原则并不以追求“零风险”为目标。新污染物环境风险管控立法总体上应当遵循“风险筛查→风险评估→风险管控”的思路。环境风险评估应当聚焦于从科学角度评估新污染物对公众健康和生态环境带来的“风险”本身,不考虑与环境风险无关的经济、社会等因素。确定什么是“不合理的风险”,除了科学判断之外,也需要“正当程序”...",
"issue": "05",
"language": "中文;",
"abstractNote": "我国对常规污染物的治理取得了显著成效,但以有毒有害化学物质的生产和使用为主要来源的新污染物的环境风险仍然较为严峻。当前我国相关环境法律法规和标准中缺乏对新污染物环境风险管控的要求,对于现有化学物质的环境风险管控还存在较为严重的不足。未来环境法典中新污染物环境风险管控立法应当坚持风险预防原则,但风险预防原则并不以追求“零风险”为目标。新污染物环境风险管控立法总体上应当遵循“风险筛查→风险评估→风险管控”的思路。环境风险评估应当聚焦于从科学角度评估新污染物对公众健康和生态环境带来的“风险”本身,不考虑与环境风险无关的经济、社会等因素。确定什么是“不合理的风险”,除了科学判断之外,也需要“正当程序”的加持。风险无法确定时,比照“存在不合理风险”进行管控。在选择风险管控措施时,应当考虑新污染物对公众健康和生态环境的影响程度以及经济、社会等因素。对于新化学物质,应当秉承“除非能证明无害,否则都应当进行适当风险管控”的理念。",
"issue": "5",
"language": "zh-CN",
"libraryCatalog": "CNKI",
"pages": "18-30+115",
"publicationTitle": "南京工业大学学报(社会科学版)",
"url": "https://kns.cnki.net/kcms2/article/abstract?v=ARuSRxW-FQHH_OEY6X72RuJIsrP2RHAQAacVbC9CGuvOv08ETIP-MqQO5E296beGN9e8BXVfYGR6l0qfpFxS9gdAPZ5URHqiAY8WVPwSYoF6MXeqOgFQfX5vrMMS_wZaK3j5TPxvx-nDGPfIMtrXBlDrWr9SVlAl&uniplatform=NZKPT",
"url": "https://kns.cnki.net/kcms2/article/abstract?v=aGn3Ey0ZxcCQMiRSLWzbqHFLmF0YiAvOI33I1RqvSIDdZeLKl7q3QL7ioYjCbxuMHo1CSBSG2LYUjI9r30yPonoox-iGbCfgn-YF7W2h79KqPswOTOxrzPV94p2evWa1-zchF2wLCag2WcjSEGNUdSNYdPlVmcGt&uniplatform=NZKPT",
"volume": "21",
"attachments": [],
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [
{
"tag": "新污染物风险管控"
@ -654,11 +648,12 @@ var testCases = [
},
{
"type": "web",
"url": "https://kns.cnki.net/kcms/detail/detail.aspx?doi=10.13863/j.issn1001-4454.2022.01.030",
"url": "https://kns.cnki.net/kcms2/article/abstract?v=aGn3Ey0ZxcBuyOSvEQLm_QauzuszuNvOETrZkPfTUVjXy6wyG6-n2nHmyA70y6TC3IN6i68HMAN2clvthsV7F1ypcjao4RepuYmOZSEVhLK8lN1UAkOxmQkqtJdHoHI1N1gKQDPjuaEbdR6APIJ1sA==&uniplatform=NZKPT&language=CHS",
"defer": true,
"items": [
{
"itemType": "journalArticle",
"title": "Box-Behnken Design-响应面法优化碱水解人参茎叶三醇皂苷制备人参皂苷Rg_2工艺研究",
"title": "Box-Behnken Design-响应面法优化碱水解人参茎叶三醇皂苷制备人参皂苷Rg2工艺研究",
"creators": [
{
"lastName": "史",
@ -699,21 +694,26 @@ var testCases = [
"date": "2022",
"DOI": "10.13863/j.issn1001-4454.2022.01.030",
"ISSN": "1001-4454",
"abstractNote": "目的利用Box-Behnken Design-响应面法优选制备人参皂苷Rg_2的最佳工艺参数。方法以碱解反应的碱度、温度、时间作为考察因素人参茎叶三醇皂苷中人参皂苷Rg_2含量作为评价指标运用Design-Expert 8.0.5b软件对工艺参数进行优化并获得最佳工艺参数。结果经优化得到碱水解人参茎叶三醇皂苷制备人参皂苷Rg_2的最佳工艺参数反应碱度7.4%、反应温度187℃、反应时间5 h。验证试验表明在此工艺参数下可将人参皂苷Rg_2含量提高至9.84%,且工艺稳定。结论经过优化的工艺可有效提高人参茎叶三醇皂苷中人参皂苷Rg_2含量。",
"issue": "01",
"language": "中文;",
"abstractNote": "目的利用Box-Behnken Design-响应面法优选制备人参皂苷Rg<sub>2</sub>的最佳工艺参数。方法以碱解反应的碱度、温度、时间作为考察因素人参茎叶三醇皂苷中人参皂苷Rg<sub>2</sub>含量作为评价指标运用Design-Expert 8.0.5b软件对工艺参数进行优化并获得最佳工艺参数。结果经优化得到碱水解人参茎叶三醇皂苷制备人参皂苷Rg<sub>2</sub>的最佳工艺参数反应碱度7.4%、反应温度187℃、反应时间5 h。验证试验表明在此工艺参数下可将人参皂苷Rg<sub>2</sub>含量提高至9.84%,且工艺稳定。结论经过优化的工艺可有效提高人参茎叶三醇皂苷中人参皂苷Rg<sub>2</sub>含量。",
"issue": "1",
"language": "zh-CN",
"libraryCatalog": "CNKI",
"pages": "173-176",
"publicationTitle": "中药材",
"url": "https://kns.cnki.net/kcms/detail/detail.aspx?doi=10.13863/j.issn1001-4454.2022.01.030",
"url": "https://kns.cnki.net/kcms2/article/abstract?v=aGn3Ey0ZxcBuyOSvEQLm_QauzuszuNvOETrZkPfTUVjXy6wyG6-n2nHmyA70y6TC3IN6i68HMAN2clvthsV7F1ypcjao4RepuYmOZSEVhLK8lN1UAkOxmQkqtJdHoHI1N1gKQDPjuaEbdR6APIJ1sA==&uniplatform=NZKPT&language=CHS",
"volume": "45",
"attachments": [],
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [
{
"tag": "Box-Behnken Design-响应面法"
},
{
"tag": "人参皂苷Rg_2"
"tag": "人参皂苷Rg2"
},
{
"tag": "人参茎叶三醇皂苷"

1945
COBISS.js Normal file

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,7 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2022-05-31 18:42:02"
"lastUpdated": "2023-10-23 08:08:57"
}
/*
@ -80,11 +80,9 @@ function getSearchResults(doc, checkOnly) {
async function doWeb(doc, url) {
if (await detectWeb(doc, url) == 'multiple') {
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (items) {
await Promise.all(
Object.keys(items)
.map(url => requestDocument(url).then(scrape))
);
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(await requestDocument(url));
}
}
else {
@ -125,7 +123,7 @@ async function scrape(doc) {
if (pdfLink) {
item.attachments.push({
url: pdfLink.href,
url: pdfLink,
title: 'Full Text PDF',
mimeType: 'application/pdf'
});

View File

@ -0,0 +1,842 @@
{
"translatorID": "cdb5c893-ab69-4e96-9b5c-f4456d49ddd8",
"label": "Câmara Brasileira do Livro ISBN",
"creator": "Abe Jellinek",
"target": "",
"minVersion": "5.0",
"maxVersion": "",
"priority": 98,
"inRepository": true,
"translatorType": 8,
"lastUpdated": "2023-09-26 16:11:18"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2023 Abe Jellinek
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
function detectSearch(items) {
items = cleanData(items);
return !!items.length;
}
async function doSearch(items) {
items = cleanData(items);
for (let { ISBN } of items) {
let search = ISBN;
if (ISBN.length == 10) {
search += ' OR ' + ZU.toISBN13(ISBN);
}
let body = {
count: true,
facets: [],
filter: '',
orderby: null,
queryType: 'full',
search,
searchFields: 'FormattedKey,RowKey',
searchMode: 'any',
select: '*',
skip: 0,
top: 1
};
let response = await requestJSON('https://isbn-search-br.search.windows.net/indexes/isbn-index/docs/search?api-version=2016-09-01', {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=UTF-8',
'api-key': '100216A23C5AEE390338BBD19EA86D29',
Origin: 'https://www.cblservicos.org.br',
Referer: 'https://www.cblservicos.org.br/'
},
body: JSON.stringify(body)
});
let results = response.value;
for (let result of results) {
translateResult(result);
}
}
}
function translateResult(result) {
Z.debug(result)
let item = new Zotero.Item('book');
item.title = result.Title;
if (result.Subtitle && !item.title.includes(':') && !result.Subtitle.includes(':')) {
item.title += ': ' + result.Subtitle;
}
item.title = fixCase(item.title);
item.abstractNote = result.Sinopse;
item.series = fixCase(result.Colection);
// TODO: Need example data for:
// item.seriesNumber
// item.volume
// item.numberOfVolumes
item.edition = result.Edicao;
if (item.edition == '1') {
item.edition = '';
}
item.place = (result.Cidade || '') + (result.UF ? ', ' + result.UF : '');
item.publisher = fixCase(result.Imprint);
item.date = ZU.strToISO(result.Date);
item.numPages = result.Paginas;
if (item.numPages == '0') {
item.numPages = '';
}
item.language = (result.IdiomasObra && result.IdiomasObra[0]) || 'pt-BR';
if (item.language == 'português (Brasil)') {
item.language = 'pt-BR';
}
item.ISBN = ZU.cleanISBN(result.FormattedKey);
for (let [i, author] of result.Authors.entries()) {
if (author == author.toUpperCase()) {
author = ZU.capitalizeName(author);
}
let creatorType;
if (result.Profissoes && result.Profissoes.length === result.Authors.length) {
switch (result.Profissoes[i]) {
case 'Coordenador':
case 'Autor':
case 'Roteirista':
creatorType = 'author';
break;
case 'Revisor':
case 'Organizador':
case 'Editor':
creatorType = 'editor';
break;
case 'Tradutor':
creatorType = 'translator';
break;
case 'Ilustrador': // TODO: Used?
case 'Projeto Gráfico':
creatorType = 'illustrator';
break;
default:
// First creator is probably an author,
// even if the Profissoes string is something weird
creatorType = i == 0 ? 'author' : 'contributor';
break;
}
}
// No/mismatched-length Profissoes array, so we have to guess that this non-primary creator
// is a contributor
else if (i > 0) {
creatorType = 'contributor';
}
// No/mismatched-length Profissoes array, so we have to guess that this primary creator
// is an author
else {
creatorType = 'author';
}
// Brazilian names often contain many surnames, but determining which names are surnames
// and which are given names is outside the scope of this translator.
// Chicago indexes by the final element of the name alone, and so will we:
// https://en.wikipedia.org/wiki/Portuguese_name#Indexing
let creator = ZU.cleanAuthor(author, creatorType, author.includes(','));
if (!creator.firstName) creator.fieldMode = 1;
// That said, we will handle name suffixes, which should be combined with the last "middle"
// name particle in the last name
if (creator.firstName && creator.lastName
&& ['filho', 'junior', 'neto', 'sobrinho', 'segundo', 'terceiro']
.includes(ZU.removeDiacritics(creator.lastName.toLowerCase()))) {
let firstNameSplit = creator.firstName.split(/\s+/);
if (firstNameSplit.length) {
let lastParticleFirstName = firstNameSplit[firstNameSplit.length - 1];
creator.lastName = lastParticleFirstName + ' ' + creator.lastName;
creator.firstName = firstNameSplit.slice(0, firstNameSplit.length - 1).join(' ');
}
}
item.creators.push(creator);
}
if (result.Subject) {
item.tags.push({ tag: result.Subject });
}
for (let tag of result.PalavrasChave) {
item.tags.push({ tag });
}
item.complete();
}
function fixCase(s) {
if (s && s == s.toUpperCase()) {
s = ZU.capitalizeTitle(s, true);
}
return s;
}
function cleanData(items) {
if (!Array.isArray(items)) {
items = [items];
}
return items
.map((item) => {
if (typeof item === 'string') {
item = { ISBN: item };
}
if (item.ISBN) {
item.ISBN = ZU.cleanISBN(item.ISBN);
}
return item;
})
.filter(item => item.ISBN && (
item.ISBN.startsWith('97865')
|| item.ISBN.startsWith('65')
|| item.ISBN.startsWith('97885')
|| item.ISBN.startsWith('85')));
}
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "search",
"input": {
"ISBN": "9786599594755"
},
"items": [
{
"itemType": "book",
"title": "Mercadores da Insegurança: conjuntura e riscos do hacking governamental no Brasil",
"creators": [
{
"firstName": "André",
"lastName": "Ramiro",
"creatorType": "author"
},
{
"firstName": "Pedro",
"lastName": "Amaral",
"creatorType": "contributor"
},
{
"firstName": "Mariana",
"lastName": "Canto",
"creatorType": "contributor"
},
{
"firstName": "Marcos César M.",
"lastName": "Pereira",
"creatorType": "contributor"
},
{
"firstName": "Raquel",
"lastName": "Saraiva",
"creatorType": "contributor"
},
{
"firstName": "Clara",
"lastName": "Guimarães",
"creatorType": "contributor"
}
],
"date": "2022-10-11",
"ISBN": "9786599594755",
"abstractNote": "Em políticas públicas, o debate sobre como as técnicas de investigações criminais devem responder à digitalização das dinâmicas sociais tem se sobressaído e caminha em uma linha tênue entre otimização dos processos administrativos e possíveis transgressões em relação aos direitos fundamentais. Nesse sentido, técnicas de hacking governamental, ou seja, de superação de recursos de segurança em dispositivos pessoais, vem ganhando uma escalabilidade crescente e envolve a ampliação de fabricantes, revendedores e contratos com a administração pública, ao passo em que seus efeitos colaterais aos direitos fundamentais, sobretudo em relação à sociedade civil, vêm sendo denunciados internacionalmente.",
"language": "pt-BR",
"libraryCatalog": "Câmara Brasileira do Livro ISBN",
"place": "Recife, PE",
"publisher": "IP.rec",
"shortTitle": "Mercadores da Insegurança",
"attachments": [],
"tags": [
{
"tag": "Digital"
},
{
"tag": "Direito"
},
{
"tag": "Governamental"
},
{
"tag": "Insegurança"
},
{
"tag": "dados"
},
{
"tag": "hacking"
},
{
"tag": "vazamento"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "search",
"input": {
"ISBN": "8532511015"
},
"items": [
{
"itemType": "book",
"title": "Harry Potter E a Pedra Filosofal",
"creators": [
{
"firstName": "J. K.",
"lastName": "Rowling",
"creatorType": "author"
}
],
"date": "2000-05-29",
"ISBN": "9788532511010",
"language": "pt-BR",
"libraryCatalog": "Câmara Brasileira do Livro ISBN",
"publisher": "Rocco",
"attachments": [],
"tags": [
{
"tag": "Biblioteconomia e ciência da informação"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "search",
"input": {
"ISBN": "9786555320275"
},
"items": [
{
"itemType": "book",
"title": "Harry Potter e o Prisioneiro de Azkaban",
"creators": [
{
"firstName": "J. K.",
"lastName": "Rowling",
"creatorType": "author"
},
{
"firstName": "Lia",
"lastName": "Wyler",
"creatorType": "contributor"
},
{
"firstName": "Arch",
"lastName": "Apolar",
"creatorType": "contributor"
}
],
"date": "2020-03-04",
"ISBN": "9786555320275",
"language": "pt-BR",
"libraryCatalog": "Câmara Brasileira do Livro ISBN",
"publisher": "Rocco",
"series": "Harry Potter",
"attachments": [],
"tags": [
{
"tag": "Harry-Potter"
},
{
"tag": "Literatura infanto-juvenil"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "search",
"input": {
"ISBN": "9786587233956"
},
"items": [
{
"itemType": "book",
"title": "Einstein Socialista: Entrevistas, manifestos e artigos do maior cientista do século XX",
"creators": [
{
"firstName": "Albert",
"lastName": "Einstein",
"creatorType": "author"
},
{
"firstName": "Hugo",
"lastName": "Albuquerque",
"creatorType": "editor"
},
{
"firstName": "Lígia Magalhães",
"lastName": "Marinho",
"creatorType": "translator"
}
],
"date": "2023-04-12",
"ISBN": "9786587233956",
"abstractNote": "Por serem supostamente purgadas da “ideologia”, as ciências exatas alcançaram entre nós um status de demasiada confiabilidade, objetividade e verdade, Entretanto, Albert Einstein, o maior físico do século XX, não compactuava com essa crença e defendia abertamente os valores socialistas, colocando a própria narrativa cientificista, quase sempre favorável à ordem capitalista, em curto-circuito.\n\nEinstein era um militante e não se calou diante das falaciosas equiparações entre a Alemanha Nazista e a União Soviética. Nem se calou, como judeu, diante das violências cometidas contra os palestinos, pouco depois do Holocausto, pelos colonos judeus no nascente Estado de Israel. Tampouco poupou críticas à segregação racial nos Estados Unidos, onde foi lecionar em seus últimos anos.\n\nQuando a Guerra Fria estava a todo vapor, Einstein escreveu “Por que o Socialismo?” , um de seus artigos mais conhecidos sobre política e frequentemente esquecido e dissociado de sua imagem. Não à toa, este texto, vez ou outra, é apresentado como “novidade” e não cansa de surpreender geração após geração. E que não se diga que era uma forma atenuada de socialismo que Einstein estava falando:\n\n“Numa economia planificada, em que a produção é ajustada às necessidades da comunidade, o trabalho a ser feito seria distribuído entre todas as pessoas aptas ao trabalho e garantiria condições de vida a todo homem, mulher e criança.”\n\nOu mesmo que, especificamente sobre a Revolução Russa, ele tenha confessado a Viereck que: \n\n“O bolchevismo é uma experiência extraordinária. Não é impossível que a deriva da evolução social daqui para a frente seja em direção ao comunismo. O experimento bolchevista talvez valha a pena.”\n\nCom uma certa dose de utopismo e um enorme enigma de como o socialismo pode ser alcançado e mantido, Einstein Socialista nos apresenta uma série de artigos, entrevistas e manifestos que revelam um lado muitas vezes negligenciado e “esquecido” de um dos maiores cientistas do mundo.",
"language": "pt-BR",
"libraryCatalog": "Câmara Brasileira do Livro ISBN",
"numPages": "96",
"place": "São Paulo, SP",
"publisher": "Autonomia Literaria",
"shortTitle": "Einstein Socialista",
"attachments": [],
"tags": [
{
"tag": "Ciências sociais"
},
{
"tag": "einstein"
},
{
"tag": "nazismo"
},
{
"tag": "relatividade"
},
{
"tag": "socialismo"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "search",
"input": {
"ISBN": "9788565053082"
},
"items": [
{
"itemType": "book",
"title": "State of the Art in Health and Knowledge",
"creators": [
{
"firstName": "Sociedade Beneficente Israelita Brasileira Albert",
"lastName": "Einstein",
"creatorType": "author"
},
{
"firstName": "Juliana",
"lastName": "Samel",
"creatorType": "translator"
}
],
"date": "2023-02-02",
"ISBN": "9788565053082",
"abstractNote": "The book presents the Albert Einstein Teaching and Research Center - Campus Cecilia and Abram Szajman, an architectural work in the city of São Paulo, created to be one of the most advanced teaching and research centers in the world. Students and researchers interact in this building to generate knowledge, with the aim of boosting Brazilian research and all this in an environment integrated with greenery, with the use of natural light and renewable energy technology.",
"language": "Inglês (EUA)",
"libraryCatalog": "Câmara Brasileira do Livro ISBN",
"numPages": "58",
"place": "São Paulo, SP",
"publisher": "Sociedade Beneficente Israelita Brasileira Albert Einstein",
"attachments": [],
"tags": [
{
"tag": "Arquitetura"
},
{
"tag": "Landscaping"
},
{
"tag": "architecture"
},
{
"tag": "health"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "search",
"input": {
"ISBN": "9786580341221"
},
"items": [
{
"itemType": "book",
"title": "Filipson: Memórias de uma menina na primeira colônia judaica no Rio Grande do Sul (1904-1920)",
"creators": [
{
"firstName": "Frida",
"lastName": "Alexandr",
"creatorType": "author"
},
{
"firstName": "Regina",
"lastName": "Zilberman",
"creatorType": "contributor"
}
],
"date": "2023-05-11",
"ISBN": "9786580341221",
"abstractNote": "“Já ouviram falar de Filipson? Um nome esquisito. Nem parece brasileiro. Mas, dentro do Brasil imenso, constituía um pontinho minúsculo que ficava lá nas bandas do Sul, perdido no meio de diversas colônias prósperas compostas em sua maioria de imigrantes espanhóis, italianos e alemães e uma ou outra fazenda de brasileiros.”\n\nDesde a primeira linha, Frida Alexandr surpreende o leitor, interpelando-o com uma pergunta. Mesmo em 1967, quando suas memórias foram publicadas em edição restrita, provavelmente poucos responderiam afirmativamente à sua questão.\n\nFilipson foi a primeira colônia judaica oficial do Brasil, formada por imigrantes judeus provenientes da Bessarábia (na região onde atualmente se localiza a Moldávia). Os pais e irmãos mais velhos de Frida chegaram ao Brasil com o grupo pioneiro, em 1904, e em \"Filipson: memórias de uma menina na primeira colônia judaica no Rio Grande do Sul (1904-1920)\". Frida deixa um registro que vai dos primeiros dias da colônia à melancólica despedida, em 1920, quando sua família decide partir novamente.\n\nEntre os dois pontos, desliza a memória de Frida, que organiza os fatos sem a preocupação de ordená-los no tempo. O importante é como essas cenas — que envolvem seus familiares, sua passagem pela escola, as dificuldades financeiras da família, as ameaças representadas por uma natureza nem sempre hospitaleira — repercutem em sua sensibilidade. Frida se vale da linguagem para transmitir a emoção na forma como a vivenciou.\n\n\"Filipson\", com posfácio da pesquisadora e escritora Regina Zilberman, é um testemunho de uma etapa do processo de adaptação e preservação dos judeus do leste da Europa no Brasil. Mas esse caráter documental é acompanhado pela recuperação sensível daqueles momentos fundadores, como se a autora, à maneira de Proust, fosse em busca das vivências daquele tempo, para transmiti-lo a um leitor que pouco conhece sobre o período.",
"language": "pt-BR",
"libraryCatalog": "Câmara Brasileira do Livro ISBN",
"numPages": "360",
"place": "SÃO PAULO, SP",
"publisher": "Chão Editora",
"shortTitle": "Filipson",
"attachments": [],
"tags": [
{
"tag": "Biografias"
},
{
"tag": "judeus"
},
{
"tag": "memórias"
},
{
"tag": "mulheres"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "search",
"input": {
"ISBN": "9786555250053"
},
"items": [
{
"itemType": "book",
"title": "Ilíada = Ἰλιάς",
"creators": [
{
"firstName": "",
"lastName": "Homero",
"creatorType": "author",
"fieldMode": 1
},
{
"firstName": "Trajano",
"lastName": "Vieira",
"creatorType": "translator"
}
],
"date": "2020-03-23",
"ISBN": "9786555250053",
"abstractNote": "Composta no século VIII a.C., a Ilíada é considerada o marco inaugural da literatura ocidental. Tradicionalmente atribuída a Homero, a obra aborda o período de algumas semanas no último ano da Guerra de Troia, durante o cerco final dos contingentes gregos à cidadela do rei Príamo, na Ásia Menor. Com seus mais de 15 mil versos, a Ilíada ganha agora uma nova tradução — das mãos de Trajano Vieira, professor livre-docente da Unicamp e premiado tradutor da Odisseia —, rigorosamente metrificada, que busca recriar em nossa língua a excelência do original, com seus símiles e invenções vocabulares. A presente edição, bilíngue, traz ainda uma série de aparatos, como um índice onomástico completo, um posfácio do tradutor, excertos da crítica, e o célebre ensaio de Simone Weil, “A Ilíada ou o poema da força”.",
"language": "pt-BR",
"libraryCatalog": "Câmara Brasileira do Livro ISBN",
"numPages": "1048",
"place": "São Paulo, SP",
"publisher": "Editora 34",
"attachments": [],
"tags": [
{
"tag": "Literatura grega"
},
{
"tag": "Literatura."
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "search",
"input": {
"ISBN": "9786556752631"
},
"items": [
{
"itemType": "book",
"title": "Manual de Sentença Trabalhista: Compreendendo a técnica da setença trabalhista para concurso",
"creators": [
{
"firstName": "Aline",
"lastName": "Leporaci",
"creatorType": "author"
},
{
"firstName": "Adriana Leandro de Sousa",
"lastName": "Freitas",
"creatorType": "contributor"
}
],
"date": "2023-03-02",
"ISBN": "9786556752631",
"abstractNote": "Nesse livro sobre sentença trabalhista, fase tão concorrida do concurso para a Magistratura do Trabalho, procuramos trazer os aspectos mais importantes a serem observados pelo candidato. O leitor poderá verificar a ordem de julgamento a seguir e a importância da fixação da prejudicialidade entre as matérias a serem analisadas. Além disso, também aprenderá as técnicas de distribuição do ônus da prova, e suas diversas teorias, sempre ressaltando qual deva ser de aplicação preferencial pelo candidato. O livro traz diversos aspectos teóricos, que são essenciais para a preparação de todos os interessados em efetivamente aprender a técnica da elaboração da sentença trabalhista, sempre com leitura fácil e direta. E não nos esquecemos dos aspectos práticos, pois o leitor terá exercícios de fixação de jornada de trabalho, e sentenças inéditas elaboradas pelas Autoras, com os respectivos gabaritos e sugestão de redação.",
"edition": "2",
"language": "pt-BR",
"libraryCatalog": "Câmara Brasileira do Livro ISBN",
"numPages": "232",
"place": "Rio de Janeiro, RJ",
"publisher": "Freitas Bastos Editora",
"shortTitle": "Manual de Sentença Trabalhista",
"attachments": [],
"tags": [
{
"tag": "Direito"
},
{
"tag": "Elaboração"
},
{
"tag": "Jornada"
},
{
"tag": "Magistratura"
},
{
"tag": "Trabalhista"
},
{
"tag": "Trabalho"
},
{
"tag": "Técnica"
},
{
"tag": "concurso"
},
{
"tag": "juiz"
},
{
"tag": "modelos"
},
{
"tag": "sentença"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "search",
"input": {
"ISBN": "9786559602513"
},
"items": [
{
"itemType": "book",
"title": "Batman",
"creators": [
{
"firstName": "John",
"lastName": "Ridley",
"creatorType": "author"
},
{
"firstName": "James Tynion",
"lastName": "IV",
"creatorType": "contributor"
},
{
"firstName": "Dandara",
"lastName": "Palankof",
"creatorType": "contributor"
},
{
"firstName": "Pedro",
"lastName": "Catarino",
"creatorType": "contributor"
},
{
"firstName": "Travel",
"lastName": "Foreman",
"creatorType": "contributor"
},
{
"firstName": "Riccardo",
"lastName": "Federici",
"creatorType": "contributor"
},
{
"firstName": "Jorge",
"lastName": "Jimenez",
"creatorType": "contributor"
}
],
"date": "2022-03-11",
"ISBN": "9786559602513",
"abstractNote": "Aventuras do Batman",
"language": "pt-BR",
"libraryCatalog": "Câmara Brasileira do Livro ISBN",
"numPages": "100",
"place": "Barueri, SP",
"publisher": "Panini Comics",
"attachments": [],
"tags": [
{
"tag": "Cartoons; caricaturas e quadrinhos"
},
{
"tag": "quadrinhos"
},
{
"tag": "super-herois"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "search",
"input": {
"ISBN": "9786559605101"
},
"items": [
{
"itemType": "book",
"title": "Superman",
"creators": [
{
"firstName": "Sean",
"lastName": "Lewis",
"creatorType": "author"
},
{
"firstName": "Phillip Kennedy",
"lastName": "Johnson",
"creatorType": "contributor"
},
{
"firstName": "Gabriel",
"lastName": "Faria",
"creatorType": "contributor"
},
{
"firstName": "Rodrigo",
"lastName": "Barros",
"creatorType": "contributor"
},
{
"firstName": "Sami",
"lastName": "Basri",
"creatorType": "contributor"
},
{
"firstName": "Phil",
"lastName": "Hester",
"creatorType": "contributor"
},
{
"firstName": "Daniel",
"lastName": "Sampere",
"creatorType": "contributor"
}
],
"date": "2022-03-10",
"ISBN": "9786559605101",
"abstractNote": "Aventuras do Superman",
"language": "pt-BR",
"libraryCatalog": "Câmara Brasileira do Livro ISBN",
"numPages": "100",
"place": "Barueri, SP",
"publisher": "Panini Comics",
"attachments": [],
"tags": [
{
"tag": "Cartoons; caricaturas e quadrinhos"
},
{
"tag": "quadrinhos"
},
{
"tag": "super-herois"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "search",
"input": {
"ISBN": "8576664984"
},
"items": [
{
"itemType": "book",
"title": "A Religião Nos Limites Da Simples Razão",
"creators": [],
"date": "2006-01-02",
"ISBN": "9788576664987",
"language": "pt-BR",
"libraryCatalog": "Câmara Brasileira do Livro ISBN",
"publisher": "Escala Educacional",
"series": "Série Filosofar",
"attachments": [],
"tags": [
{
"tag": "Literatura"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "search",
"input": {
"ISBN": "9788591597512"
},
"items": [
{
"itemType": "book",
"title": "Visões da áfrica: angola e moçambiqueJorge Alves de Lima Filho",
"creators": [
{
"firstName": "Jorge Alves de",
"lastName": "Lima Filho",
"creatorType": "author"
}
],
"date": "2015-09-29",
"ISBN": "9788591597512",
"language": "pt-BR",
"libraryCatalog": "Câmara Brasileira do Livro ISBN",
"publisher": "Jorge Alves de Lima Filho",
"shortTitle": "Visões da áfrica",
"attachments": [],
"tags": [
{
"tag": "Coleções de obras diversas sem assunto específico"
}
],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

View File

@ -9,13 +9,13 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2023-04-17 08:48:37"
"lastUpdated": "2024-11-20 15:43:05"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2016-2020 Sebastian Karcher
Copyright © 2016-2024 Sebastian Karcher
This file is part of Zotero.
@ -68,7 +68,7 @@ function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
var rows = doc.querySelectorAll(
'li.title a[href*="/article/"], li.title a[href*="/product/"], li.title a[href*="/books/"]'
'li.title a[href*="/article/"], li.title a[href*="/product/"], li.title a[href*="/books/"], div.results .product-listing-with-inputs-content a[href*="/books/"]'
);
for (let row of rows) {
var href = row.href;
@ -82,28 +82,24 @@ function getSearchResults(doc, checkOnly) {
}
function doWeb(doc, url) {
if (detectWeb(doc, url) == "multiple") {
Zotero.selectItems(getSearchResults(doc, false), function (items) {
if (!items) {
return;
}
var articles = [];
for (let i in items) {
articles.push(i);
}
ZU.processDocuments(articles, scrape);
});
async function doWeb(doc, url) {
if (detectWeb(doc, url) == 'multiple') {
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(await requestDocument(url));
}
}
else {
scrape(doc, url);
await scrape(doc, url);
}
}
function scrape(doc, url) {
async function scrape(doc, url = doc.location.href) {
// Book metadata is much better using RIS
if (detectWeb(doc, url) == "book" || detectWeb(doc, url) == "bookSection") {
let productID = url.replace(/[#?].+/, "").match(/\/([^/]+)$/)[1];
let productID = url.replace(/[#?].*/, "").match(/\/([^/]+)$/)[1];
let risURL
= "/core/services/aop-easybib/export?exportType=ris&productIds="
+ productID + "&citationStyle=apa";
@ -112,39 +108,43 @@ function scrape(doc, url) {
var pdfURL = ZU.xpathText(doc,
'//meta[contains(@name, "citation_pdf_url")]/@content'
);
if (!pdfURL) {
pdfURL = attr(doc, '.actions a[target="_blank"][href*=".pdf"]', 'href');
}
// Z.debug("pdfURL: " + pdfURL);
ZU.doGet(risURL, function (text) {
var translator = Zotero.loadTranslator(
"import");
translator.setTranslator(
"32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7");
translator.setString(text);
translator.setHandler("itemDone", function (obj,
item) {
if (pdfURL) {
item.attachments.push({
url: pdfURL,
title: "Full Text PDF",
mimeType: "application/pdf"
});
}
var text = await requestText(risURL);
var translator = Zotero.loadTranslator(
"import");
translator.setTranslator(
"32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7");
translator.setString(text);
translator.setHandler("itemDone", function (obj,
item) {
if (pdfURL) {
item.attachments.push({
title: "Snapshot",
document: doc
url: pdfURL,
title: "Full Text PDF",
mimeType: "application/pdf"
});
// don't save Cambridge Core to archive
item.archive = "";
item.complete();
}
item.attachments.push({
title: "Snapshot",
document: doc
});
translator.translate();
// don't save Cambridge Core to archive
item.archive = "";
item.complete();
});
await translator.translate();
}
// Some elements of journal citations look better with EM
else {
var translator = Zotero.loadTranslator('web');
let translator = Zotero.loadTranslator('web');
// Embedded Metadata
translator.setTranslator('951c027d-74ac-47d4-a107-9c3069ab7b48');
translator.setHandler('itemDone', function (obj, item) {
translator.setDocument(doc);
translator.setHandler('itemDone', (_obj, item) => {
item.url = url;
var abstract = ZU.xpathText(doc,
'//div[@class="abstract"]');
@ -152,6 +152,7 @@ function scrape(doc, url) {
item.abstractNote = abstract;
}
item.title = ZU.unescapeHTML(item.title);
item.publisher = ""; // don't grab the publisher
item.libraryCatalog = "Cambridge University Press";
if (item.date.includes("undefined")) {
item.date = attr('meta[name="citation_online_date"]', "content");
@ -161,18 +162,18 @@ function scrape(doc, url) {
if (titleElem.querySelector('a:last-child')) {
item.title = titleElem.firstChild.textContent;
}
item.complete();
});
translator.getTranslatorObject(function (trans) {
if (url.includes("/books")) {
trans.itemType = "book";
}
else {
trans.itemType = "journalArticle";
}
trans.doWeb(doc, url);
});
let em = await translator.getTranslatorObject();
// TODO map additional meta tags here, or delete completely
if (url.includes("/books")) {
em.itemType = "book";
}
else {
em.itemType = "journalArticle";
}
await em.doWeb(doc, url);
}
}
@ -208,10 +209,6 @@ var testCases = [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
},
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
@ -258,10 +255,6 @@ var testCases = [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
},
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [
@ -449,11 +442,6 @@ var testCases = [
"url": "https://www.cambridge.org/core/what-we-publish/books/listing?sort=canonical.date%3Adesc&aggs%5BonlyShowAvailable%5D%5Bfilters%5D=true&aggs%5BproductTypes%5D%5Bfilters%5D=BOOK%2CELEMENT&searchWithinIds=0C5182F27A492FDC81EDF8D3C53266B5",
"items": "multiple"
},
{
"type": "web",
"url": "https://www.cambridge.org/core/journals/ajs-review/firstview",
"items": "multiple"
},
{
"type": "web",
"url": "https://www.cambridge.org/core/journals/ajs-review/latest-issue",
@ -534,6 +522,59 @@ var testCases = [
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.cambridge.org/core/journals/american-political-science-review/firstview",
"items": "multiple"
},
{
"type": "web",
"url": "https://www.cambridge.org/core/books/foundations-of-probabilistic-programming/819623B1B5B33836476618AC0621F0EE",
"items": [
{
"itemType": "book",
"title": "Foundations of Probabilistic Programming",
"creators": [
{
"lastName": "Barthe",
"firstName": "Gilles",
"creatorType": "editor"
},
{
"lastName": "Katoen",
"firstName": "Joost-Pieter",
"creatorType": "editor"
},
{
"lastName": "Silva",
"firstName": "Alexandra",
"creatorType": "editor"
}
],
"date": "2020",
"ISBN": "9781108488518",
"abstractNote": "What does a probabilistic program actually compute? How can one formally reason about such probabilistic programs? This valuable guide covers such elementary questions and more. It provides a state-of-the-art overview of the theoretical underpinnings of modern probabilistic programming and their applications in machine learning, security, and other domains, at a level suitable for graduate students and non-experts in the field. In addition, the book treats the connection between probabilistic programs and mathematical logic, security (what is the probability that software leaks confidential information?), and presents three programming languages for different applications: Excel tables, program testing, and approximate computing. This title is also available as Open Access on Cambridge Core.",
"extra": "DOI: 10.1017/9781108770750",
"libraryCatalog": "Cambridge University Press",
"place": "Cambridge",
"publisher": "Cambridge University Press",
"url": "https://www.cambridge.org/core/books/foundations-of-probabilistic-programming/819623B1B5B33836476618AC0621F0EE",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
},
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

View File

@ -9,7 +9,7 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2022-12-08 18:55:55"
"lastUpdated": "2023-10-23 08:35:07"
}
/*
@ -52,7 +52,7 @@ function detectWeb(doc, url) {
function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
var rows = doc.querySelectorAll('.MatchResult > a');
var rows = doc.querySelectorAll('.MatchResult article a');
for (let row of rows) {
let href = row.href;
@ -68,11 +68,9 @@ function getSearchResults(doc, checkOnly) {
async function doWeb(doc, url) {
if (detectWeb(doc, url) == 'multiple') {
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (items) {
await Promise.all(
Object.keys(items)
.map(url => requestDocument(url).then(scrape))
);
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(await requestDocument(url));
}
}
else {
@ -89,6 +87,9 @@ async function scrape(doc, url = doc.location.href) {
translator.setHandler('itemDone', (_obj, item) => {
item.publisher = attr(doc, 'meta[property="og:site_name"]', 'content');
item.libraryCatalog = "Cambridge Engage Preprints";
if (item.date) {
item.date = ZU.strToISO(item.date);
}
item.complete();
});
@ -102,6 +103,7 @@ var testCases = [
{
"type": "web",
"url": "https://chemrxiv.org/engage/chemrxiv/search-dashboard?text=acid",
"defer": true,
"items": "multiple"
},
{
@ -123,7 +125,7 @@ var testCases = [
"creatorType": "author"
}
],
"date": "2021/10/08",
"date": "2021-10-08",
"DOI": "10.26434/chemrxiv-2021-mjpkz",
"abstractNote": "Conversion of readily available feedstocks to valuable platform chemicals via a sustainable catalytic pathway has always been one of the key focuses of synthetic chemists. Cheaper, less toxic, and more abundant base metals as a catalyst for performing such transformations provide an additional boost. In this context, herein, we report a reformation of readily available feedstock, ethylene glycol, to value-added platform molecules, glycolic acid, and lactic acid. A bench stable base metal complex {[HN(C2H4PPh2)2]Mn(CO)2Br}, Mn-I, known as Mn-PhMACHO, catalyzed the reformation of ethylene glycol to glycolic acid at 140 oC in high selectivity with a turnover number TON = 2400, surpassing previously used homogeneous catalysts for such a reaction. Pure hydrogen gas is evolved without the need for an acceptor. On the other hand, a bench stable Mn(I)-complex, {(iPrPN5P)Mn(CO)2Br}, Mn-III, with a triazine backbone, efficiently catalyzed the acceptorless dehydrogenative coupling of ethylene glycol and methanol for the synthesis of lactic acid, even at a ppm level of catalyst loading, reaching the TON of 11,500. Detailed mechanistic studies were performed to elucidate the involvements of different manganese(I)-species during the catalysis.",
"language": "en",
@ -180,7 +182,7 @@ var testCases = [
"creatorType": "author"
}
],
"date": "2019/10/02",
"date": "2019-10-03",
"DOI": "10.33774/apsa-2019-if2he-v2",
"abstractNote": "The discipline of political science has been engaged in discussion about when, why, and how to make scholarship more transparent for at least three decades. This piece argues that qualitative researchers can achieve transparency in diverse ways, using techniques and strategies that allow them to balance and optimize among competing considerations that affect the pursuit of transparency.. We begin by considering the “state of the debate,” briefly outlining the contours of the scholarship on transparency in political and other social sciences, which so far has focussed mostly on questions of “whether” and “what” to share. We investigate competing considerations that researchers have to consider when working towards transparent research. The heart of the piece considers various strategies, illustrated by exemplary applications, for making qualitative research more transparent.",
"language": "en",
@ -238,7 +240,7 @@ var testCases = [
"creatorType": "author"
}
],
"date": "2021/07/20",
"date": "2021-07-20",
"DOI": "10.33774/miir-2021-7cdx1",
"abstractNote": "This report addresses the construction of carbon fibre wing boxes and the problems associated with using carbon fibre sheets rather than individual carbon fibre tapes. In the case that the wing boxes are developable surfaces the lay up of carbon fibre sheets is straightforward, since the fibres can follow the contours of the surface without any need for shearing or extension of the fibres. To further expand the potential design space for the wing boxes, this report investigates the lay up of sheets over non-developable surfaces where some shearing of the sheet is required to achieve the desired results. In this report, three analytical approaches are considered, driven by the results from numerical studies on different surface geometries. Each of the approaches offers insights as to the type of geometric perturbations achievable when constrained by a maximum shear angle.",
"language": "en",

185
ChatGPT.js Normal file
View File

@ -0,0 +1,185 @@
{
"translatorID": "d8a83346-164a-467d-8717-eb96d4dcce6f",
"label": "ChatGPT",
"creator": "Abe Jellinek",
"target": "^https://chatgpt\\.com/",
"minVersion": "5.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2025-10-27 15:38:43"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2025 Abe Jellinek
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
// Simple translator for ChatGPT that grabs the date and model info
// for private and public chats.
// Please don't take any of the translator authorship advice that ChatGPT
// gives in the test page. It's mostly wrong.
function detectWeb(doc, url) {
if (url.includes('/c/') || url.includes('/share/')) {
return 'webpage';
}
return false;
}
async function doWeb(doc, url) {
let item = new Zotero.Item('webpage');
item.title = doc.title;
item.websiteTitle = 'ChatGPT';
item.websiteType = 'Generative AI chat';
if (url.includes('/share/')) {
item.url = url;
}
item.creators.push({
creatorType: 'author',
lastName: 'OpenAI',
fieldMode: 1
});
item.attachments.push({
title: 'Snapshot',
document: doc
});
try {
await enrichItemWithAPI(doc, url, item);
}
catch (e) {
Zotero.debug(e);
}
item.complete();
}
async function enrichItemWithAPI(doc, url, item) {
let dataScript = [...doc.querySelectorAll('script')]
.find(script => script.textContent.startsWith('window.__reactRouterContext.streamController.enqueue('))
.textContent;
let extract = (key) => {
let formattedKey = `\\"${key}\\",\\"`;
let keyIndex = dataScript.indexOf(formattedKey);
if (keyIndex === -1) return null;
return dataScript.substring(keyIndex + formattedKey.length).split('\\"')[0];
};
let language = extract('locale');
let deviceID = extract('WebAnonymousCookieID');
let accessToken = extract('accessToken');
let clientVersion = doc.documentElement.dataset.build;
let id = url.match(/\/(?:c|share)\/([^#?/]+)/)[1];
let apiSlug;
if (url.includes('/c/')) {
apiSlug = 'conversation/' + id;
}
else {
apiSlug = 'share/' + id;
}
let apiURL = '/backend-api/' + apiSlug;
let headers = {
'OAI-Language': language,
'OAI-Device-Id': deviceID,
'OAI-Client-Version': clientVersion,
};
if (accessToken) {
headers.Authorization = `Bearer ${accessToken}`;
}
let json = await requestJSON(apiURL, { headers });
item.title = json.title;
let date = new Date((json.update_time || json.create_time) * 1000);
item.date = ZU.strToISO(date.toISOString());
if (json.model) {
item.websiteTitle += ` (${json.model.title})`;
}
if (url.includes('/c/')) {
// Private conversation: Add existing share URL if available
try {
let { items: shares }
= await requestJSON('/backend-api/shared_conversations?order=created', { headers });
let share = shares.find(share => share.conversation_id === id);
if (share) {
Zotero.debug('Conversation has been shared as ' + share.id);
if (new Date(share.update_time) >= date) {
Zotero.debug('Share is up to date');
item.url = `https://chatgpt.com/share/${share.id}`;
}
else {
Zotero.debug(`Out of date: ${share.update_time} < ${date}`);
}
}
else {
Zotero.debug('Not yet shared');
}
}
catch (e) {
Zotero.debug('Unable to find share');
Zotero.debug(e);
}
}
}
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "https://chatgpt.com/share/68fa640b-9fc8-8013-a803-3d5241df6556",
"items": [
{
"itemType": "webpage",
"title": "Write Zotero translator",
"creators": [
{
"creatorType": "author",
"lastName": "OpenAI",
"fieldMode": 1
}
],
"date": "2025-10-24",
"url": "https://chatgpt.com/share/68fa640b-9fc8-8013-a803-3d5241df6556",
"websiteTitle": "ChatGPT (GPT-5)",
"websiteType": "Generative AI chat",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

View File

@ -0,0 +1,203 @@
{
"translatorID": "1e2a9aba-eb04-4398-9e3a-630e6132db13",
"label": "Chicago Journal of Theoretical Computer Science",
"creator": "Morgan Shirley",
"target": "^https?://cjtcs\\.cs\\.uchicago\\.edu/articles",
"minVersion": "5.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2025-05-14 00:10:19"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2025 Morgan Shirley
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
/**
* Volumes are at articles/year/contents.html
* Individual articles are at articles/year/#/contents.html
* Special issues at articles/[issue name]/contents.html
*/
function detectWeb(doc, url) {
var singleRe = /^https?:\/\/cjtcs\.cs\.uchicago\.edu\/articles\/\w+\/\d+\/contents.html/
var multipleRe = /^https?:\/\/cjtcs\.cs\.uchicago\.edu\/articles\/\w+\/contents.html/
if (multipleRe.test(url)) {
return getMultiple(doc, true) && "multiple";
}
else if (singleRe.test(url)) {
return "journalArticle";
}
else return false;
}
function getMultiple(doc, checkOnly) {
var items = {};
var found = false;
// We need to be specific to avoid navigating to special issues
var rows = doc.querySelectorAll('ul > li > ul > li');
for (let row of rows) {
// Only the first link in a list item is an article
let article_link = row.querySelector('a[href*="contents.html"]');
let href = article_link.href;
let title = ZU.trimInternal(row.textContent);
if (!href || !title) continue;
if (checkOnly) return true;
found = true;
items[href] = title;
}
return found ? items : false;
}
async function doWeb(doc, url) {
if (detectWeb(doc, url) == 'multiple') {
let items = await Zotero.selectItems(getMultiple(doc, false));
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(await requestDocument(url));
}
}
else {
await scrape(doc, url);
}
}
async function scrape(doc, url = doc.location.href) {
let bibUrl = doc.querySelector('a[href*=".bib"]')
let bibText = fixAuthorLine(await requestText(bibUrl.href));
let translator = Zotero.loadTranslator("import");
translator.setTranslator('9cb70025-a888-4a29-a210-93ec52da40d4');
translator.setString(bibText);
translator.setHandler('itemDone', (_obj, item) => {
//DOI is listed on page
let doiElement = doc.querySelector('a[href*="dx.doi.org"]');
item.DOI = ZU.cleanDOI(doiElement.href);
//Download PDF, or Snapshot if unavailable
let pdfElement = doc.querySelector('a[href*=".pdf"]');
if (pdfElement) {
item.attachments.push({
url: pdfElement.href,
title: 'Full Text PDF',
mimeType: 'application/pdf'
});
}
else {
item.attachments.push({
title: 'Snapshot',
document: doc
});
}
item.complete();
});
await translator.translate();
}
// Sometimes the bibtex will omit an equals sign after "author"
function fixAuthorLine(input) {
return input.split('\n').map(line => {
return line.replace(/^(\s*author)(?!\s*=)/, '$1=');
}).join('\n');
}
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "http://cjtcs.cs.uchicago.edu/articles/2010/1/contents.html",
"items": [
{
"itemType": "journalArticle",
"title": "Quantum Boolean Functions",
"creators": [
{
"firstName": "Ashley",
"lastName": "Montanaro",
"creatorType": "author"
},
{
"firstName": "Tobias J.",
"lastName": "Osborne",
"creatorType": "author"
}
],
"date": "2010-01",
"DOI": "10.4086/cjtcs.2010.001",
"issue": "1",
"itemID": "cj10-01",
"libraryCatalog": "Chicago Journal of Theoretical Computer Science",
"publicationTitle": "Chicago Journal of Theoretical Computer Science",
"volume": "2010",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "http://cjtcs.cs.uchicago.edu/articles/2010/contents.html",
"items": "multiple"
},
{
"type": "web",
"url": "http://cjtcs.cs.uchicago.edu/articles/CATS2009/1/contents.html",
"items": [
{
"itemType": "journalArticle",
"title": "On Process Complexity",
"creators": [
{
"firstName": "Adam R.",
"lastName": "Day",
"creatorType": "author"
}
],
"date": "2010-06",
"DOI": "10.4086/cjtcs.2010.004",
"issue": "4",
"itemID": "cats9-1",
"libraryCatalog": "Chicago Journal of Theoretical Computer Science",
"publicationTitle": "Chicago Journal of Theoretical Computer Science",
"volume": "2010",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

168
CiNii Research.js Normal file
View File

@ -0,0 +1,168 @@
{
"translatorID": "46291dc3-5cbd-47b7-8af4-d009078186f6",
"label": "CiNii Research",
"creator": "Michael Berkowitz, Mitsuo Yoshida and Satoshi Ando",
"target": "^https?://cir\\.nii\\.ac\\.jp/",
"minVersion": "1.0.0b4.r5",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2024-09-26 14:22:20"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2024 Michael Berkowitz, Mitsuo Yoshida and Satoshi Ando
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
function detectWeb(doc, url) {
if (url.includes("/crid/")) {
return "journalArticle";
}
else if (doc.evaluate('//a[contains(@href, "/crid/")]', doc, null, XPathResult.ANY_TYPE, null).iterateNext()) {
return "multiple";
}
return false;
}
function doWeb(doc, url) {
var arts = [];
if (detectWeb(doc, url) == "multiple") {
var items = {};
var links = doc.evaluate('//a[contains(@href, "/crid/")]', doc, null, XPathResult.ANY_TYPE, null);
var link;
while ((link = links.iterateNext())) {
items[link.href] = Zotero.Utilities.trimInternal(link.textContent);
}
Zotero.selectItems(items, function (items) {
if (!items) {
return;
}
for (var i in items) {
arts.push(i);
}
Zotero.Utilities.processDocuments(arts, scrape);
});
}
else {
scrape(doc, url);
}
}
function scrape(doc, _url) {
var newurl = doc.location.href;
var biblink = ZU.xpathText(doc, '//li/div/a[contains(text(), "BibTeX")]/@href');
//Z.debug(biblink)
var tags = [];
if (doc.evaluate('//a[@rel="tag"]', doc, null, XPathResult.ANY_TYPE, null).iterateNext()) {
var kws = doc.evaluate('//a[@rel="tag"]', doc, null, XPathResult.ANY_TYPE, null);
var kw;
while ((kw = kws.iterateNext())) {
tags.push(Zotero.Utilities.trimInternal(kw.textContent));
}
}
//var abstractPath = '//div[@class="abstract"]/p[@class="entry-content"]';
var abstractPath = '//div[contains(@class, "abstract")]/p[contains(@class, "entry-content")]';
var abstractNote;
if (doc.evaluate(abstractPath, doc, null, XPathResult.ANY_TYPE, null).iterateNext()) {
abstractNote = doc.evaluate(abstractPath, doc, null, XPathResult.ANY_TYPE, null).iterateNext().textContent;
}
Zotero.Utilities.HTTP.doGet(biblink, function (text) {
var trans = Zotero.loadTranslator("import");
trans.setTranslator("9cb70025-a888-4a29-a210-93ec52da40d4");
trans.setString(text);
trans.setHandler("itemDone", function (obj, item) {
item.url = newurl;
item.attachments = [{ url: item.url, title: item.title + " Snapshot", mimeType: "text/html" }];
item.tags = tags;
item.abstractNote = abstractNote;
if (item.ISSN) {
item.ISSN = ZU.cleanISSN(item.ISSN);
}
item.complete();
});
trans.translate();
});
}
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "https://cir.nii.ac.jp/all?q=test&range=0&count=20&sortorder=1&type=0",
"items": "multiple"
},
{
"type": "web",
"url": "https://cir.nii.ac.jp/crid/1390001204062164736",
"items": [
{
"itemType": "journalArticle",
"title": "観測用既存鉄骨造モデル構造物を用いたオンライン応答実験",
"creators": [
{
"firstName": "謙一",
"lastName": "大井",
"creatorType": "author"
},
{
"firstName": "與助",
"lastName": "嶋脇",
"creatorType": "author"
},
{
"firstName": "拓海",
"lastName": "伊藤",
"creatorType": "author"
},
{
"firstName": "玉順",
"lastName": "李",
"creatorType": "author"
}
],
"date": "2002",
"DOI": "10.11188/seisankenkyu.54.384",
"ISSN": "1881-2058",
"abstractNote": "特集 ERS(耐震構造学)",
"issue": "6",
"itemID": "1390001204062164736",
"libraryCatalog": "CiNii Research",
"pages": "384-387",
"publicationTitle": "生産研究",
"url": "https://cir.nii.ac.jp/crid/1390001204062164736",
"volume": "54",
"attachments": [
{
"title": "観測用既存鉄骨造モデル構造物を用いたオンライン応答実験 Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

136
CiNii.js
View File

@ -1,136 +0,0 @@
{
"translatorID": "46291dc3-5cbd-47b7-8af4-d009078186f6",
"label": "CiNii",
"creator": "Michael Berkowitz and Mitsuo Yoshida",
"target": "^https?://ci\\.nii\\.ac\\.jp/",
"minVersion": "1.0.0b4.r5",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2012-11-24 13:12:41"
}
function detectWeb(doc, url) {
if (url.match(/naid/)) {
return "journalArticle";
} else if (doc.evaluate('//a[contains(@href, "/naid/")]', doc, null, XPathResult.ANY_TYPE, null).iterateNext()) {
return "multiple";
}
}
function doWeb(doc, url) {
var arts = new Array();
if (detectWeb(doc, url) == "multiple") {
var items = new Object();
var links = doc.evaluate('//a[contains(@href, "/naid/")]', doc, null, XPathResult.ANY_TYPE, null);
var link;
while (link = links.iterateNext()) {
items[link.href] = Zotero.Utilities.trimInternal(link.textContent);
}
Zotero.selectItems(items, function (items) {
if (!items) {
return true;
}
for (var i in items) {
arts.push(i);
}
Zotero.Utilities.processDocuments(arts, scrape, function () {
Zotero.done();
});
Zotero.wait();
});
} else {
scrape(doc, url)
}
}
function scrape(doc, url){
var newurl = doc.location.href;
var biblink = ZU.xpathText(doc, '//li/div/a[contains(text(), "BibTeX")]/@href');
//Z.debug(biblink)
var tags = new Array();
if (doc.evaluate('//a[@rel="tag"]', doc, null, XPathResult.ANY_TYPE, null).iterateNext()) {
var kws = doc.evaluate('//a[@rel="tag"]', doc, null, XPathResult.ANY_TYPE, null);
var kw;
while (kw = kws.iterateNext()) {
tags.push(Zotero.Utilities.trimInternal(kw.textContent));
}
}
var abstractNote;
if (doc.evaluate('//div[@class="abstract"]', doc, null, XPathResult.ANY_TYPE, null).iterateNext()) {
abstractNote = doc.evaluate('//div[@class="abstract"]', doc, null, XPathResult.ANY_TYPE, null).iterateNext().textContent;
}
Zotero.Utilities.HTTP.doGet(biblink, function(text) {
var trans = Zotero.loadTranslator("import");
trans.setTranslator("9cb70025-a888-4a29-a210-93ec52da40d4");
trans.setString(text);
trans.setHandler("itemDone", function(obj, item) {
item.url = newurl;
item.attachments = [{url:item.url, title:item.title + " Snapshot", mimeType:"text/html"}];
item.tags = tags;
item.abstractNote = abstractNote;
item.complete();
});
trans.translate();
});
}/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "http://ci.nii.ac.jp/search?q=test&range=0&count=20&sortorder=1&type=0",
"items": "multiple"
},
{
"type": "web",
"url": "http://ci.nii.ac.jp/naid/110000244188/ja/",
"items": [
{
"itemType": "journalArticle",
"title": "<研究速報>観測用既存鉄骨造モデル構造物を用いたオンライン応答実験=Pseudo-dynamic tests on existing steel model structure for seismic monitoring",
"creators": [
{
"firstName": "謙一=Kenichi Ohi",
"lastName": "大井",
"creatorType": "author"
},
{
"firstName": "輿助=Yosuke Shimawaki",
"lastName": "嶋脇",
"creatorType": "author"
},
{
"firstName": "拓海=Takumi Ito",
"lastName": "伊藤",
"creatorType": "author"
},
{
"firstName": "Li",
"lastName": "Yushun",
"creatorType": "author"
}
],
"date": "November 2002",
"DOI": "10.11188/seisankenkyu.54.384",
"ISSN": "0037105X",
"issue": "6",
"itemID": "110000244188",
"libraryCatalog": "CiNii",
"pages": "384-387",
"publicationTitle": "生産研究",
"url": "http://ci.nii.ac.jp/naid/110000244188/ja/",
"volume": "54",
"attachments": [
{
"title": "<研究速報>観測用既存鉄骨造モデル構造物を用いたオンライン応答実験=Pseudo-dynamic tests on existing steel model structure for seismic monitoring Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

View File

@ -12,7 +12,7 @@
},
"inRepository": true,
"translatorType": 1,
"lastUpdated": "2022-08-18 11:23:00"
"lastUpdated": "2025-01-04 01:03:00"
}
/*
@ -124,6 +124,7 @@ async function importItems({ references, doc, citaviVersion, rememberTags, itemI
item.numberOfVolumes = ZU.xpathText(references[i], './NumberOfVolumes');
addExtraLine(item, "PMID", ZU.xpathText(references[i], './PubMedID'));
addExtraLine(item, "Citation Key", ZU.xpathText(references[i], './BibTeXKey'));
item.pages = extractPages(ZU.xpathText(references[i], './PageRange'));
item.numPages = extractPages(ZU.xpathText(references[i], './PageCount'));

View File

@ -9,7 +9,7 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2022-11-10 02:47:43"
"lastUpdated": "2023-08-22 04:14:33"
}
/*
@ -40,9 +40,16 @@ function detectWeb(doc, url) {
if (url.includes('/index.cfm/detail/')) {
return 'journalArticle';
}
else if (getSearchResults(doc, true)) {
let appRoot = doc.querySelector("#app"); // Ajax app "mount point"
if (appRoot) {
// Watch for live filtering of search results)
Z.monitorDOMChanges(appRoot);
}
if (getSearchResults(doc, true)) {
return 'multiple';
}
return false;
}
@ -64,11 +71,9 @@ function getSearchResults(doc, checkOnly) {
async function doWeb(doc, url) {
if (detectWeb(doc, url) == 'multiple') {
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (items) {
await Promise.all(
Object.keys(items)
.map(url => requestDocument(url).then(scrape))
);
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(await requestDocument(url));
}
}
else {
@ -76,7 +81,7 @@ async function doWeb(doc, url) {
}
}
function scrape(doc) {
async function scrape(doc) {
var pmid = text(doc, 'li>a[href*="www.ncbi.nlm.nih.gov/pubmed"]');
var doi = text(doc, 'li>a[href*="doi.org/10."]');
var abstract = text(doc, '#cchh-detail-abstract');
@ -185,6 +190,7 @@ var testCases = [
{
"type": "web",
"url": "https://tools.niehs.nih.gov/cchhl/index.cfm/main/search#/params?searchTerm=heat%20pump&selectedFacets=&selectedResults=",
"defer": true,
"items": "multiple"
},
{

265
CourtListener.js Normal file
View File

@ -0,0 +1,265 @@
{
"translatorID": "07890a30-866e-452a-ac3e-c19fcb39b597",
"label": "CourtListener",
"creator": "Sebastian Karcher",
"target": "^https?://www\\.courtlistener\\.com/",
"minVersion": "5.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2025-04-29 03:02:00"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2024 Sebastian Karcher
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
function detectWeb(doc, url) {
if (url.includes('/opinion/')) {
return 'case';
}
else if (getSearchResults(doc, true)) {
return 'multiple';
}
return false;
}
function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
var rows = doc.querySelectorAll('article > h3 > a');
for (let row of rows) {
let href = row.href;
let title = ZU.trimInternal(row.textContent);
if (!href || !title) continue;
if (checkOnly) return true;
found = true;
items[href] = title;
}
return found ? items : false;
}
async function doWeb(doc, url) {
if (detectWeb(doc, url) == 'multiple') {
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(await requestDocument(url));
}
}
else {
await scrape(doc);
}
}
async function scrape(doc, url = doc.location.href) {
var item = new Zotero.Item('case');
let citations = ZU.xpath(doc, '//li/strong[contains(text(), "Citations:")]/following-sibling::span')
.map(el => el.textContent.trim());
let citation = text(doc, 'center b .citation');
item.caseName = text(doc, '#caption');
item.court = text(doc, '.case-court');
item.reporter = text(doc, '.citation .reporter');
item.reporterVolume = text(doc, '.citation .volume');
item.firstPage = text(doc, '.citation .page');
if (!item.reporter && !item.reporterVolume) {
// the reporter elements aren't always tagged. We might have to parse them
// the best version is in the top of the opinion (we always want that for history matching,
// so getting that outside the conditional
// if that's not there, we're parsing from the title of the case
if (!citation) {
citation = citations[0];
}
let citeExpr = citation.trim().match(/^(\d+)\s((?:[A-Z][a-z]?\.\s?)+(?:[2-3]d)?(?:Supp\.)?)\s(\d{1,4})(,|$)/);
if (citeExpr) {
item.reporterVolume = citeExpr[1];
item.reporter = citeExpr[2];
item.firstPage = citeExpr[3];
}
else {
// if we can't match the reporter elements properly, just write the whole thing to citation.
item.history = citation;
}
}
if (!item.history) {
item.history = citations.slice(1).join(', ');
}
item.dateDecided = text(doc, ".case-date-new");
// No good selectors for docket number and authors
let docket = ZU.xpathText(doc, '//li[strong[contains(text(), "Docket Number:")]]/text()[1]');
item.docketNumber = docket ? docket.trim() : "";
let authors = doc.querySelectorAll(".opinion-section-title > a[href*='/person/']");
for (let author of authors) {
item.creators.push(ZU.cleanAuthor(author.textContent.trim(), "author", false));
}
item.url = url.replace(/\/\?.*/, "");
item.attachments.push({ document: doc, title: "Full Text" });
item.extra = "";
item.complete();
}
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "https://www.courtlistener.com/opinion/1872757/gibson-v-bossier-city-general-hosp/?type=o&q=testing&type=o&order_by=score%20desc&stat_Precedential=on",
"items": [
{
"itemType": "case",
"caseName": "Gibson v. Bossier City General Hosp.",
"creators": [],
"dateDecided": "Nov. 26, 1991",
"court": "Louisiana Court of Appeal",
"docketNumber": "22693-CA, 23002-CA",
"firstPage": "1332",
"history": "1991 La. App. LEXIS 3211, 1991 WL 249791",
"reporter": "So.2d",
"reporterVolume": "594",
"url": "https://www.courtlistener.com/opinion/1872757/gibson-v-bossier-city-general-hosp",
"attachments": [
{
"title": "Full Text",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.courtlistener.com/opinion/1611405/blackwell-v-power-test-corp/?type=o&type=o&q=testing&order_by=score+desc&stat_Precedential=on&page=3",
"items": [
{
"itemType": "case",
"caseName": "Blackwell v. Power Test Corp.",
"creators": [
{
"firstName": "Henry Curtis",
"lastName": "Meanor",
"creatorType": "author"
}
],
"dateDecided": "Aug. 19, 1981",
"court": "District Court, D. New Jersey",
"docketNumber": "Civ. A. 80-2227",
"firstPage": "802",
"history": "1981 U.S. Dist. LEXIS 10126",
"reporter": "F.Supp.",
"reporterVolume": "540",
"url": "https://www.courtlistener.com/opinion/1611405/blackwell-v-power-test-corp",
"attachments": [
{
"title": "Full Text",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.courtlistener.com/opinion/108284/griggs-v-duke-power-co/?q=testing",
"items": [
{
"itemType": "case",
"caseName": "Griggs v. Duke Power Co.",
"creators": [
{
"firstName": "Warren Earl",
"lastName": "Burger",
"creatorType": "author"
}
],
"dateDecided": "March 8, 1971",
"court": "Supreme Court of the United States",
"docketNumber": "124",
"firstPage": "424",
"history": "91 S. Ct. 849, 28 L. Ed. 2d 158, 3 Empl. Prac. Dec. (CCH) 8137, 3 Fair Empl. Prac. Cas. (BNA) 175, 1971 U.S. LEXIS 134",
"reporter": "U.S.",
"reporterVolume": "401",
"url": "https://www.courtlistener.com/opinion/108284/griggs-v-duke-power-co",
"attachments": [
{
"title": "Full Text",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.courtlistener.com/?q=testing",
"items": "multiple"
},
{
"type": "web",
"url": "https://www.courtlistener.com/opinion/3959231/state-v-martin/?q=State%20v.%20Martin&type=o&order_by=score%20desc&stat_Precedential=on",
"items": [
{
"itemType": "case",
"caseName": "State v. Martin",
"creators": [
{
"firstName": "Robert L.",
"lastName": "Black",
"creatorType": "author"
}
],
"dateDecided": "Feb. 9, 1983",
"court": "Ohio Court of Appeals",
"docketNumber": "C-820238",
"firstPage": "717",
"history": "20 Ohio App. 3d 172, 20 Ohio B. 215, 1983 Ohio App. LEXIS 16057",
"reporter": "N.E.2d",
"reporterVolume": "485",
"url": "https://www.courtlistener.com/opinion/3959231/state-v-martin",
"attachments": [
{
"title": "Full Text",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

1757
Crossref REST.js Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,332 +0,0 @@
{
"translatorID": "0a61e167-de9a-4f93-a68a-628b48855909",
"translatorType": 8,
"label": "Crossref REST",
"creator": "Martynas Bagdonas",
"target": "",
"minVersion": "5.0.0",
"maxVersion": null,
"priority": 90,
"inRepository": true,
"browserSupport": "gcsibv",
"lastUpdated": "2018-06-16 12:00:00"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2018
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
// Based on CrossRef.js (by Simon Kornblith), which uses OpenURL API
// This translator uses the newer REST API
// https://github.com/Crossref/rest-api-doc
// https://github.com/Crossref/rest-api-doc/blob/master/api_format.md
// REST API documentation not always reflect the actual API
// and some fields are undocumented.
// All Crossref item types can be retrieved at http://api.crossref.org/types
function removeUnsupportedMarkup(text) {
let markupRE = /<(\/?)(\w+)[^<>]*>/gi;
let supportedMarkup = ['i', 'b', 'sub', 'sup', 'sc'];
let transformMarkup = {
'scp': {
open: '<span style="font-variant:small-caps;">',
close: '</span>'
}
};
return text.replace(/<!\[CDATA\[([\s\S]*?)\]\]>/g, '$1') // Remove CDATA markup
.replace(markupRE, function (m, close, name) {
name = name.toLowerCase();
if (supportedMarkup.includes(name)) {
return (close ? '</' : '<') + name + '>';
}
let newMarkup = transformMarkup[name.toLowerCase()];
if (newMarkup) {
return close ? newMarkup.close : newMarkup.open;
}
return '';
});
}
function fixAuthorCapitalization(string) {
// Try to use capitalization function from Zotero Utilities,
// because the current one doesn't support unicode names.
// Can't fix this either because ZU.XRegExp.replace is
// malfunctioning when calling from translators.
if (ZU.capitalizeName) return ZU.capitalizeName(string);
if (typeof string === "string" && string.toUpperCase() === string) {
string = string.toLowerCase().replace(/\b[a-z]/g, function (m) {
return m[0].toUpperCase();
});
}
return string;
}
function parseCreators(result, item, typeOverrideMap) {
let types = ['author', 'editor', 'chair', 'translator'];
for (let i = 0; i < types.length; i++) {
let type = types[i];
if (result[type]) {
let creatorType = null;
if (typeOverrideMap && typeOverrideMap[type] !== undefined) {
creatorType = typeOverrideMap[type];
}
else if (type === "author" || type === "editor" || type === "translator") {
creatorType = type;
}
else {
creatorType = "contributor";
}
if (!creatorType) continue;
for (let j = 0; j < result[type].length; j++) {
let creator = {};
creator.creatorType = creatorType;
if (result[type].name) { // Organization
creator.fieldMode = 1;
creator.lastName = result[type][j].name;
}
else {
creator.firstName = fixAuthorCapitalization(result[type][j].given);
creator.lastName = fixAuthorCapitalization(result[type][j].family);
if (!creator.firstName) creator.fieldMode = 1;
}
item.creators.push(creator);
}
}
}
}
function processCrossref(json) {
json = JSON.parse(json);
for (let i = 0; i < json.message.items.length; i++) {
let result = json.message.items[i];
let item = null;
// Journal article
if (['journal-article'].includes(result.type)) {
item = new Zotero.Item("journalArticle");
if (result['container-title']) item.publicationTitle = result['container-title'][0];
if (result['short-container-title']
&& result['short-container-title'][0] !== result['container-title'][0]) {
item.journalAbbreviation = result['short-container-title'][0];
}
item.volume = result.volume;
item.issue = result.issue;
if (result.ISBN) item.ISBN = result.ISBN[0];
if (result.ISSN) item.ISSN = result.ISSN[0];
}
// Book
else if (['book', 'book-series', 'book-set', 'book-track', 'monograph', 'reference-book']
.includes(result.type)) {
item = new Zotero.Item("book");
item.publisher = result.publisher;
item.place = result['publisher-location'];
if (result.ISBN) item.ISBN = result.ISBN[0];
}
// Book section
else if (['book-chapter', 'book-part', 'book-section', 'reference-entry']
.includes(result.type)) {
item = new Zotero.Item("bookSection");
item.publisher = result.publisher;
item.place = result['publisher-location'];
if (result.ISBN) item.ISBN = result.ISBN[0];
}
// Report
else if (['dataset', 'posted-content', 'report', 'report-series', 'standard']
.includes(result.type)) {
item = new Zotero.Item("report");
item.institution = result.publisher;
item.place = result['publisher-location'];
item.seriesTitle = result['container-title'];
}
// Conference paper
else if (['proceedings-article'].includes(result.type)) {
item = new Zotero.Item("conferencePaper");
item.proceedingsTitle = result['container-title'];
item.publisher = result.publisher;
if (result.event) {
item.conferenceName = result.event.name;
item.place = result.event.location;
}
if (result.ISBN) item.ISBN = result.ISBN[0];
}
// Thesis
else if (['dissertation'].includes(result.type)) {
item = new Zotero.Item("thesis");
item.university = result.publisher;
item.place = result['publisher-location'];
}
else {
return;
}
// edited-book, standard-series - ignore, because Crossref has zero results for this type
// component, journal, journal-issue, journal-volume, other, proceedings,
// proceedings-series, peer-review - ignore, because Zotero doesn't have equivalent item types.
item.abstractNote = result.abstract;
parseCreators(result, item);
// Contains the earliest of: published-online, published-print, content-created
let pubDate = result['issued'];
if (pubDate && pubDate['date-parts'][0]) {
let year = pubDate['date-parts'][0][0];
let month = pubDate['date-parts'][0][1];
let day = pubDate['date-parts'][0][2];
if (year) {
if (month) {
if (day) {
item.date = year + "-" + month + "-" + day;
}
else {
item.date = month + "/" + year;
}
}
else {
item.date = year;
}
}
}
item.pages = result.page;
if (result.DOI) {
if (ZU.fieldIsValidForType('DOI', item.itemType)) {
item.DOI = result.DOI;
}
// add DOI to extra for unsupprted items
else {
if (item.extra) {
item.extra += '\nDOI: ' + result.DOI;
}
else {
item.extra = 'DOI: ' + result.DOI;
}
}
}
// result.URL is always http://dx.doi.org/..
if (result.link && result.link.URL) item.url = result.link.URL;
if (result.title && result.title[0]) {
item.title = result.title[0];
if (result.subtitle && result.subtitle[0]) {
// Don't duplicate subtitle if it already exists in title
if (item.title.toLowerCase().indexOf(result.subtitle[0].toLowerCase()) < 0) {
item.title += ': ' + result.subtitle[0];
}
}
item.title = removeUnsupportedMarkup(item.title);
}
// Check if there are potential issues with character encoding and try to fix it
// e.g. 10.1057/9780230391116.0016 (en dash in title is presented as <control><control>â)
for (let field in item) {
if (typeof item[field] !== 'string') continue;
// Check for control characters that should never be in strings from Crossref
if (/[\u007F-\u009F]/.test(item[field])) {
item[field] = decodeURIComponent(escape(item[field]));
}
item[field] = ZU.unescapeHTML(item[field]);
}
item.libraryCatalog = 'Crossref';
item.complete();
}
}
function detectSearch(item) {
return false;
}
function doSearch(item) {
// Reduce network traffic by selecting only required fields
let selectedFields = [
'type',
'container-title',
'short-container-title',
'volume',
'issue',
'ISBN',
'ISSN',
'publisher',
'publisher-location',
'event',
'abstract',
'issued',
'page',
'DOI',
'link',
'title',
'subtitle',
'author',
'editor',
'chair',
'translator'
];
let query = null;
if (item.DOI) {
if (Array.isArray(item.DOI)) {
query = '?filter=doi:' + item.DOI.map(x => ZU.cleanDOI(x)).filter(x => x).join(',doi:');
} else {
query = '?filter=doi:' + ZU.cleanDOI(item.DOI);
}
}
else if (item.query) {
query = '?query.bibliographic=' + encodeURIComponent(item.query);
}
else return;
query += '&select=' + selectedFields.join(',');
if (Z.getHiddenPref('CrossrefREST.email')) {
query += '&mailto=' + Z.getHiddenPref('CrossrefREST.email');
}
ZU.doGet('https://api.crossref.org/works/' + query, function (responseText) {
processCrossref(responseText);
});
}
/** BEGIN TEST CASES **/
var testCases = [];
/** END TEST CASES **/

View File

@ -9,7 +9,7 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2021-07-09 20:47:02"
"lastUpdated": "2025-08-08 16:00:53"
}
/*
@ -79,6 +79,7 @@ function scrape(doc, url) {
translator.setDocument(doc);
translator.setHandler('itemDone', function (obj, item) {
item.abstractNote = text(doc, '.article-details__abstract');
item.attachments = [];
for (let button of doc.querySelectorAll('.button')) {
@ -140,7 +141,7 @@ var testCases = [
"date": "2015/01/01",
"DOI": "10.1371/journal.pone.0127427",
"ISSN": "1932-6203",
"abstractNote": "DOAJ is a community-curated online directory that indexes and provides access to high quality, open access, peer-reviewed journals.",
"abstractNote": "BACKGROUND:Heritable factors are evidently involved in prostate cancer (PrCa) carcinogenesis, but currently, genetic markers are not routinely used in screening or diagnostics of the disease. More precise information is needed for making treatment decisions to distinguish aggressive cases from indolent disease, for which heritable factors could be a useful tool. The genetic makeup of PrCa has only recently begun to be unravelled through large-scale genome-wide association studies (GWAS). The thus far identified Single Nucleotide Polymorphisms (SNPs) explain, however, only a fraction of familial clustering. Moreover, the known risk SNPs are not associated with the clinical outcome of the disease, such as aggressive or metastasised disease, and therefore cannot be used to predict the prognosis. Annotating the SNPs with deep clinical data together with miRNA expression profiles can improve the understanding of the underlying mechanisms of different phenotypes of prostate cancer. RESULTS:In this study microRNA (miRNA) profiles were studied as potential biomarkers to predict the disease outcome. The study subjects were from Finnish high risk prostate cancer families. To identify potential biomarkers we combined a novel non-parametrical test with an importance measure provided from a Random Forest classifier. This combination delivered a set of nine miRNAs that was able to separate cases from controls. The detected miRNA expression profiles could predict the development of the disease years before the actual PrCa diagnosis or detect the existence of other cancers in the studied individuals. Furthermore, using an expression Quantitative Trait Loci (eQTL) analysis, regulatory SNPs for miRNA miR-483-3p that were also directly associated with PrCa were found. CONCLUSION:Based on our findings, we suggest that blood-based miRNA expression profiling can be used in the diagnosis and maybe even prognosis of the disease. In the future, miRNA profiling could possibly be used in targeted screening, together with Prostate Specific Antigene (PSA) testing, to identify men with an elevated PrCa risk.",
"issue": "5",
"language": "en",
"libraryCatalog": "doaj.org",
@ -214,10 +215,10 @@ var testCases = [
"creatorType": "author"
}
],
"date": "2021/07/01",
"date": "2021/09/01",
"DOI": "10.1136/bmjoq-2021-001396",
"ISSN": "2399-6641",
"abstractNote": "DOAJ is a community-curated online directory that indexes and provides access to high quality, open access, peer-reviewed journals.",
"abstractNote": "Recent research demonstrates that transfusing whole blood (WB=red blood cells (RBC)+plasma+platelets) rather than just RBC (which is current National Health Service (NHS) practice) may improve outcomes for major trauma patients. As part of a programme to investigate provision of WB, NHS Blood and Transplant undertook a 2-year feasibility study to supply the Royal London Hospital (RLH) with (group O negative, O neg) leucodepleted red cell and plasma (LD-RCP) for transfusion of trauma patients with major haemorrhage in prehospital settings.Incidents requiring such prehospital transfusion occur randomly, with very high variation. Availability is critical, but O neg LD-RCP is a scarce resource and has a limited shelf life (14 days) after which it must be disposed of. The consequences of wastage are the opportunity cost of loss of overall treatment capacity across the NHS and reputational damage.The context was this feasibility study, set up to assess deliverability to RLH and subsequent wastage levels. Within this, we conducted a quality improvement project, which aimed to reduce the wastage of LD-RCP to no more than 8% (ie, 1 of the 12 units delivered per week).Over this 2-year period, we reduced wastage from a weekly average of 70%27%. This was achieved over four improvement cycles. The largest improvement came from moving near-expiry LD-RCP to the emergency department (ED) for use with their trauma patients, with subsequent improvements from embedding use in ED as routine practice, introducing a dedicated LD-RCP delivery schedule (which increased the units ≤2 days old at delivery from 42% to 83%) and aligning this delivery schedule to cover two cycles of peak demand (Fridays and Saturdays).",
"issue": "3",
"language": "en",
"libraryCatalog": "doaj.org",

View File

@ -3,13 +3,12 @@
"label": "DOI Content Negotiation",
"creator": "Sebastian Karcher",
"target": "",
"minVersion": "4.0.29.11",
"minVersion": "5.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 8,
"browserSupport": "gcs",
"lastUpdated": "2020-04-20 20:04:00"
"lastUpdated": "2025-07-27 04:51:26"
}
/*
@ -58,145 +57,296 @@ function filterQuery(items) {
return dois;
}
function doSearch(items) {
var dois = filterQuery(items);
if (!dois.length) return;
processDOIs(dois);
async function doSearch(items) {
for (let doi of filterQuery(items)) {
await processDOI(doi);
}
}
function processDOIs(dois) {
var doi = dois.pop();
// by content negotiation we asked for datacite or crossref format, or CSL JSON
ZU.doGet('https://doi.org/' + encodeURIComponent(doi), function (text) {
if (!text) {
return;
}
Z.debug(text);
var trans = Zotero.loadTranslator('import');
trans.setString(text);
if (text.includes("<crossref")) {
// Crossref Unixref
trans.setTranslator('93514073-b541-4e02-9180-c36d2f3bb401');
trans.setHandler('itemDone', function (obj, item) {
item.libraryCatalog = "DOI.org (Crossref)";
item.complete();
});
trans.translate();
}
else if (text.includes("http://datacite.org/schema")
// TEMP
// https://github.com/zotero/translators/issues/2018#issuecomment-616491407
|| text.includes('"agency": "DataCite"')
|| text.includes('"providerId": ')) {
// Datacite JSON
trans.setTranslator('b5b5808b-1c61-473d-9a02-e1f5ba7b8eef');
trans.setHandler('itemDone', function (obj, item) {
item.libraryCatalog = "DOI.org (Datacite)";
item.complete();
});
trans.translate();
}
else {
// use CSL JSON translator
trans.setTranslator('bc03b4fe-436d-4a1f-ba59-de4d2d7a63f7');
trans.setHandler('itemDone', function (obj, item) {
item.libraryCatalog = "DOI.org (CSL JSON)";
// check if there are potential issues with character encoding and try to fix it
// e.g. 10.1057/9780230391116.0016 (en dash in title is presented as escaped unicode)
for (var field in item) {
if (typeof item[field] != 'string') continue;
// check for control characters that should never be in strings from CrossRef
if (/[\u007F-\u009F]/.test(item[field])) {
var escaped = item[field].replace(/[^0-9A-Za-z ]/g, function (c) {
return "%" + c.charCodeAt(0).toString(16);
});
item[field] = decodeURIComponent(escaped);
}
async function processDOI(doi) {
// TEMP: Use Crossref REST for Crossref DOIs during Crossref outage
let currentDate = new Date();
// Outage: 17 May 2025, 14:0015:00 UTC
// Start 1 hour before (13:00 UTC) and end 2 hours after (17:00 UTC)
// TEMP for May 22 outage
let startDate = new Date(Date.UTC(2025, 4, 22, 00, 0, 0));
let endDate = new Date(Date.UTC(2025, 4, 24, 0, 0, 0));
// At least for now, always use REST API for Crossref DOIs
// due to better reliability
// TEMP: Except don't, because some REST API requests are really slow
// https://forums.zotero.org/discussion/comment/496121/#Comment_496121
//if (currentDate >= startDate && currentDate <= endDate) {
if (false) {
try {
let raJSON = await requestJSON(
`https://doi.org/ra/${encodeURIComponent(doi)}`
);
if (raJSON.length) {
let ra = raJSON[0].RA;
if (ra == 'Crossref') {
let translate = Zotero.loadTranslator('search');
// Crossref REST
translate.setTranslator("0a61e167-de9a-4f93-a68a-628b48855909");
let item = { itemType: "journalArticle", DOI: doi };
translate.setSearch(item);
translate.translate();
return;
}
item.complete();
});
trans.translate();
}
}
}, function () {
if (dois.length) processDOIs(dois);
}, undefined, { Accept: "application/vnd.datacite.datacite+json, application/vnd.crossref.unixref+xml, application/vnd.citationstyles.csl+json" });
catch (e) {
Z.debug(e);
}
}
let response = await requestText(
`https://doi.org/${encodeURIComponent(doi)}`,
{ headers: { Accept: "application/vnd.datacite.datacite+json, application/vnd.crossref.unixref+xml, application/vnd.citationstyles.csl+json" } }
);
// by content negotiation we asked for datacite or crossref format, or CSL JSON
if (!response) return;
Z.debug(response);
let trans = Zotero.loadTranslator('import');
trans.setString(response);
if (response.includes("<crossref")) {
// Crossref Unixref
trans.setTranslator('93514073-b541-4e02-9180-c36d2f3bb401');
trans.setHandler('itemDone', function (obj, item) {
item.libraryCatalog = "DOI.org (Crossref)";
item.complete();
});
}
else if (response.includes("http://datacite.org/schema")
// TEMP
// https://github.com/zotero/translators/issues/2018#issuecomment-616491407
|| response.includes('"agency": "DataCite"')
|| response.includes('"providerId": ')) {
// Datacite JSON
trans.setTranslator('b5b5808b-1c61-473d-9a02-e1f5ba7b8eef');
trans.setHandler('itemDone', function (obj, item) {
item.libraryCatalog = "DOI.org (Datacite)";
item.complete();
});
}
else {
// use CSL JSON translator
trans.setTranslator('bc03b4fe-436d-4a1f-ba59-de4d2d7a63f7');
trans.setHandler('itemDone', function (obj, item) {
item.libraryCatalog = "DOI.org (CSL JSON)";
// check if there are potential issues with character encoding and try to fix it
// e.g. 10.1057/9780230391116.0016 (en dash in title is presented as escaped unicode)
for (var field in item) {
if (typeof item[field] != 'string') continue;
// check for control characters that should never be in strings from CrossRef
if (/[\u007F-\u009F]/.test(item[field])) {
var escaped = item[field].replace(/[^0-9A-Za-z ]/g, function (c) {
return "%" + c.charCodeAt(0).toString(16);
});
item[field] = decodeURIComponent(escaped);
}
}
item.complete();
});
}
await trans.translate();
}
/** BEGIN TEST CASES **/
var testCases = [{
"type": "search",
"input": {
"DOI": "10.12763/ONA1045"
},
"items": [{
"itemType": "journalArticle",
"url": "http://docnum.univ-lorraine.fr/pulsar/RCR_543952102_NA1045.pdf",
"pages": "39.79 MB, 402 pages",
"date": "1734",
"DOI": "10.12763/ona1045",
"accessDate": "2019-02-02T02:31:57Z",
"libraryCatalog": "DOI.org (Datacite)",
"language": "fre",
"title": "Code criminel de l'empereur Charles V vulgairement appellé la Caroline contenant les loix qui sont suivies dans les jurisdictions criminelles de l'Empire et à l'usage des conseils de guerre des troupes suisses.",
"creators": [{
"firstName": "",
"lastName": "Heiliges Römisches Reich Deutscher Nation",
"creatorType": "author"
var testCases = [
{
"type": "search",
"input": {
"DOI": "10.12763/ONA1045"
},
{
"firstName": "Franz Adam. Éditeur Scientifique",
"lastName": "Vogel",
"creatorType": "contributor"
},
{
"firstName": "Simon, Claude (167 ?-1752) Éditeur",
"lastName": "Commercial",
"creatorType": "contributor"
},
{
"firstName": "",
"lastName": "Université De Lorraine-Direction De La Documentation Et De L'Edition",
"creatorType": "contributor"
}
],
"tags": [
"Droit"
],
"relations": [],
"attachments": [],
"notes": [
"<h2>Other</h2>\nLe code est accompagné de commentaires de F. A. Vogel, qui signe l'épitre dédicatoire<h2>Other</h2>\nReliure 18è siècle<h2>Other</h2>\nEx-libris manuscrit \"Ex libris Dufour\""
"items": [
{
"itemType": "journalArticle",
"title": "Code criminel de l'empereur Charles V vulgairement appellé la Caroline contenant les loix qui sont suivies dans les jurisdictions criminelles de l'Empire et à l'usage des conseils de guerre des troupes suisses.",
"creators": [
{
"lastName": "Heiliges Römisches Reich Deutscher Nation",
"creatorType": "author",
"fieldMode": 1
},
{
"lastName": "Vogel",
"firstName": "Franz Adam. Éditeur Scientifique",
"creatorType": "contributor"
},
{
"firstName": "Simon, Claude (167 ?-1752) Éditeur",
"lastName": "Commercial",
"creatorType": "contributor"
},
{
"lastName": "Université De Lorraine-Direction De La Documentation Et De L'Edition",
"creatorType": "contributor",
"fieldMode": 1
}
],
"date": "1734",
"DOI": "10.12763/ONA1045",
"language": "fr",
"libraryCatalog": "DOI.org (Datacite)",
"pages": "39.79 MB, 402 pages",
"url": "http://docnum.univ-lorraine.fr/pulsar/RCR_543952102_NA1045.pdf",
"attachments": [],
"tags": [
{
"tag": "Droit"
}
],
"notes": [
{
"note": "<h2>Other</h2>\nLe code est accompagné de commentaires de F. A. Vogel, qui signe l'épitre dédicatoire<h2>Other</h2>\nReliure 18è siècle<h2>Other</h2>\nEx-libris manuscrit \"Ex libris Dufour\""
}
],
"seeAlso": []
}
]
}]
},
{
"type": "search",
"input": {
"DOI": "10.7336/academicus.2014.09.05"
},
"items": [{
"itemType": "journalArticle",
"url": "http://academicus.edu.al/?subpage=volumes&nr=9",
"volume": "9",
"pages": "69-78",
"publicationTitle": "Academicus International Scientific Journal",
"ISSN": "20793715",
"date": "01/2014",
"DOI": "10.7336/academicus.2014.09.05",
"accessDate": "2019-02-02T03:28:48Z",
"libraryCatalog": "DOI.org (Crossref)",
"title": "Second world war, communism and post-communism in Albania, an equilateral triangle of a tragic trans-Adriatic story. The Eftimiadis Saga",
"creators": [{
"firstName": "Muner",
"lastName": "Paolo",
"creatorType": "author"
}],
"tags": [],
"relations": [],
"attachments": [],
"notes": []
}]
}
{
"type": "search",
"input": {
"DOI": "10.7336/academicus.2014.09.05"
},
"items": [
{
"itemType": "journalArticle",
"title": "Second world war, communism and post-communism in Albania, an equilateral triangle of a tragic trans-Adriatic story. The Eftimiadis Saga",
"creators": [
{
"creatorType": "author",
"firstName": "Paolo",
"lastName": "Muner"
}
],
"date": "01/2014",
"DOI": "10.7336/academicus.2014.09.05",
"ISSN": "20793715, 23091088",
"abstractNote": "The complicated, troubled and tragic events of a wealthy family from Vlorë, Albania, which a century ago expanded its business to Italy, in Brindisi and Trieste, and whose grand land tenures and financial properties in Albania were nationalized by Communism after the Second World War. Hence the life-long solitary and hopeless fight of the last heir of the family to reconquer his patrimony that had been nationalized by Communism. Such properties would have been endowed to a planned foundation, which aims at perpetuating the memory of his brother, who was active in the resistance movement during the war and therefore hung by the Germans. His main institutional purpose is to help students from the Vlorë area to attend the University of Trieste. The paper is a travel in time through history, sociology and the consolidation of a states fundamentals, by trying to read the past aiming to understand the presence and save the future. The paper highlights the need to consider past models of social solidarity meanwhile renewing the actual one. This as a re-establishment of rule and understanding, a strategy to cope with pressures to renegotiate the social contract, as a universal need, by considering the pasts experiences as a firm base for successful social interaction. All this, inside a story which in the first look seems to be too personal and narrow, meanwhile it highlights the present and the past in a natural organic connection, dedicated to a nation in continuous struggle for its social reconstruction.",
"libraryCatalog": "DOI.org (Crossref)",
"pages": "69-78",
"publicationTitle": "Academicus International Scientific Journal",
"rights": "https://creativecommons.org/licenses/by-nc-nd/4.0/",
"url": "https://www.medra.org/servlet/MREngine?hdl=10.7336/academicus.2014.09.05",
"volume": "9",
"attachments": [],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "search",
"input": [
{
"DOI": "10.5555/12345678"
},
{
"DOI": "10.1109/TPS.1987.4316723"
},
{
"DOI": "10.5555/666655554444"
}
],
"items": [
{
"itemType": "journalArticle",
"title": "Toward a Unified Theory of High-Energy Metaphysics: Silly String Theory",
"creators": [
{
"creatorType": "author",
"firstName": "Josiah",
"lastName": "Carberry"
},
{
"creatorType": "contributor",
"fieldMode": 1,
"lastName": "Friends of Josiah Carberry"
}
],
"date": "2008-08-14",
"DOI": "10.5555/12345678",
"ISSN": "0264-3561",
"abstractNote": "The characteristic theme of the works of Stone is the bridge between culture and society. Several narratives concerning the fatal !aw, and subsequent dialectic, of semioticist class may be found. Thus, Debord uses the term the subtextual paradigm of consensus to denote a cultural paradox. The subject is interpolated into a neocultural discourse that includes sexuality as a totality. But Marxs critique of prepatriarchialist nihilism states that consciousness is capable of signi\"cance. The main theme of Dietrichs[1]model of cultural discourse is not construction, but neoconstruction. Thus, any number of narratives concerning the textual paradigm of narrative exist. Pretextual cultural theory suggests that context must come from the collective unconscious.",
"issue": "11",
"journalAbbreviation": "Journal of Psychoceramics",
"language": "en",
"libraryCatalog": "DOI.org (Crossref)",
"pages": "1-3",
"publicationTitle": "Journal of Psychoceramics",
"shortTitle": "Toward a Unified Theory of High-Energy Metaphysics",
"url": "https://ojs33.crossref.publicknowledgeproject.org/index.php/test/article/view/2",
"volume": "5",
"attachments": [],
"tags": [],
"notes": [],
"seeAlso": []
},
{
"itemType": "journalArticle",
"title": "Bulk and Surface Plasmons in Artificially Structured Materials",
"creators": [
{
"creatorType": "author",
"firstName": "John J.",
"lastName": "Quinn"
},
{
"creatorType": "author",
"firstName": "Josiah S.",
"lastName": "Carberry"
}
],
"date": "1987",
"DOI": "10.1109/TPS.1987.4316723",
"ISSN": "0093-3813",
"issue": "4",
"journalAbbreviation": "IEEE Trans. Plasma Sci.",
"libraryCatalog": "DOI.org (Crossref)",
"pages": "394-410",
"publicationTitle": "IEEE Transactions on Plasma Science",
"rights": "https://ieeexplore.ieee.org/Xplorehelp/downloads/license-information/IEEE.html",
"url": "http://ieeexplore.ieee.org/document/4316723/",
"volume": "15",
"attachments": [],
"tags": [],
"notes": [],
"seeAlso": []
},
{
"itemType": "journalArticle",
"title": "The Memory Bus Considered Harmful",
"creators": [
{
"creatorType": "author",
"firstName": "Josiah",
"lastName": "Carberry"
}
],
"date": "2012-10-11",
"DOI": "10.5555/666655554444",
"ISSN": "0264-3561",
"issue": "11",
"journalAbbreviation": "Journal of Psychoceramics",
"language": "en",
"libraryCatalog": "DOI.org (Crossref)",
"pages": "1-3",
"publicationTitle": "Journal of Psychoceramics",
"url": "https://ojs33.crossref.publicknowledgeproject.org/index.php/test/article/view/8",
"volume": "9",
"attachments": [],
"tags": [],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

24
DOI.js
View File

@ -9,7 +9,7 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2023-03-12 01:46:07"
"lastUpdated": "2024-06-04 14:34:03"
}
/*
@ -151,7 +151,7 @@ function detectWeb(doc, url) {
return "journalArticle"; // A decent guess
}
function retrieveDOIs(doiOrDOIs) {
async function retrieveDOIs(doiOrDOIs) {
let showSelect = Array.isArray(doiOrDOIs);
let dois = showSelect ? doiOrDOIs : [doiOrDOIs];
let items = {};
@ -214,14 +214,19 @@ function retrieveDOIs(doiOrDOIs) {
// Don't throw on error
translate.setHandler("error", function () {});
translate.translate();
try {
await translate.translate();
}
catch (e) {
Zotero.debug(`Failed to resolve DOI '${doi}': ${e}`);
}
}
}
function doWeb(doc, url) {
async function doWeb(doc, url) {
let doiOrDOIs = getDOIs(doc, url);
Z.debug(doiOrDOIs);
retrieveDOIs(doiOrDOIs);
await retrieveDOIs(doiOrDOIs);
}
/** BEGIN TEST CASES **/
@ -278,9 +283,10 @@ var testCases = [
{
"type": "web",
"url": "https://dataverse.harvard.edu/dataset.xhtml?persistentId=doi:10.7910/DVN/BEJTMI",
"detectedItemType": "journalArticle",
"items": [
{
"itemType": "document",
"itemType": "dataset",
"title": "Transfer of 50 thousand improved genetically improved farmed tilapia (GIFT) fry to Nigeria",
"creators": [
{
@ -296,14 +302,14 @@ var testCases = [
{
"lastName": "WorldFish",
"creatorType": "contributor",
"fieldMode": true
"fieldMode": 1
}
],
"date": "2023",
"DOI": "10.7910/DVN/BEJTMI",
"abstractNote": "The data contains the list of female broodstock that produced improved GIFT fry sent to Nigeria in three batches in 2022",
"extra": "Type: dataset\nDOI: 10.7910/DVN/BEJTMI",
"libraryCatalog": "DOI.org (Datacite)",
"publisher": "Harvard Dataverse",
"repository": "Harvard Dataverse",
"url": "https://dataverse.harvard.edu/citation?persistentId=doi:10.7910/DVN/BEJTMI",
"attachments": [],
"tags": [],

File diff suppressed because one or more lines are too long

View File

@ -2,61 +2,64 @@
"translatorID": "0526c18d-8dc8-40c9-8314-399e0b743a4d",
"label": "Dagstuhl Research Online Publication Server",
"creator": "Philipp Zumstein",
"target": "^https?://(www\\.)?drops\\.dagstuhl\\.de/opus/",
"minVersion": "3.0",
"target": "^https?://(www\\.)?drops\\.dagstuhl\\.de/",
"minVersion": "6.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2016-08-23 06:54:08"
"lastUpdated": "2025-07-19 19:20:18"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2016 Philipp Zumstein
Copyright © 2016-2025 Philipp Zumstein and Zotero contributors
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
function detectWeb(doc, url) {
if (url.indexOf('source_opus')>-1 || url.indexOf('volltexte')>-1) {
var bibtexEntry = ZU.xpathText(doc, '//pre/tt');
if (bibtexEntry.indexOf("@InCollection")>-1) {
if (url.includes('/entities/document/')) {
let bibtexEntry = text(doc, 'pre.bibtex');
if (bibtexEntry.includes("@InCollection")) {
return "bookSection";
}
if (bibtexEntry.indexOf("@Article")>-1) {
if (bibtexEntry.includes("@Article")) {
return "journalArticle";
}
return "conferencePaper";
} else if (getSearchResults(doc, true)) {
}
else if (getSearchResults(doc, true)) {
return "multiple";
}
return false;
}
function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
var rows = ZU.xpath(doc, '//b/a[contains(@href, "source_opus")]|//td/a[contains(@href, "source_opus")]');//
for (var i=0; i<rows.length; i++) {
var href = rows[i].href;
var title = ZU.trimInternal(rows[i].textContent);
var rows = doc.querySelectorAll('a[href*="/entities/document/"]');
for (let row of rows) {
let href = row.href;
let title = ZU.trimInternal(row.textContent);
if (!href || !title) continue;
if (checkOnly) return true;
found = true;
@ -65,74 +68,73 @@ function getSearchResults(doc, checkOnly) {
return found ? items : false;
}
function doWeb(doc, url) {
async function doWeb(doc, url) {
if (detectWeb(doc, url) == "multiple") {
Zotero.selectItems(getSearchResults(doc, false), function (items) {
if (!items) {
return true;
}
var articles = [];
for (var i in items) {
articles.push(i);
}
ZU.processDocuments(articles, scrape);
});
} else {
scrape(doc, url);
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(await requestDocument(url));
}
}
else {
await scrape(doc, url);
}
}
function scrape(doc, url) {
var bibtexEntry = ZU.xpathText(doc, '//pre/tt');
//Z.debug(bibtexEntry);
var pdfurl = ZU.xpathText(doc, '//td//a[contains(@href, "pdf")]/@href');
async function scrape(doc, _url = doc.location.href) {
let bibtexEntry = text(doc, 'pre.bibtex');
let pdfUrl = attr(doc, 'meta[name="citation_pdf_url"]', 'content');
// One more try in case the meta tag didn't work, there are other tags with the PDF link
if (!pdfUrl) {
Z.debug("PDF URL extraction from the meta tag failed, trying other sources.");
pdfUrl = attr(doc, 'section.files a[href$=".pdf"]', 'href');
}
var translator = Zotero.loadTranslator("import");
translator.setTranslator("9cb70025-a888-4a29-a210-93ec52da40d4");
translator.setString(bibtexEntry);
translator.setHandler("itemDone", function(obj, item) {
//if a note is just a list of keywords, then save them as tags
//and delete this note
for (var i=0; i<item.notes.length; i++) {
translator.setHandler("itemDone", function (obj, item) {
// If a note is just a list of keywords, then save them as tags
// and delete this note
for (var i = 0; i < item.notes.length; i++) {
var note = item.notes[i].note;
if (note.indexOf('Keywords:')>-1) {
if (note.includes('Keywords:')) {
note = note.replace('<p>', '').replace('</p>', '').replace('Keywords:', '');
var keywords = note.split(',');
for (var j=0; j<keywords.length; j++) {
for (var j = 0; j < keywords.length; j++) {
item.tags.push(keywords[j].trim());
}
item.notes.splice(i, 1);
}
}
item.attachments.push({
title: "Snapshot",
document: doc
});
if (pdfurl) {
if (pdfUrl) {
item.attachments.push({
url: pdfurl,
url: pdfUrl,
title: "Full Text PDF",
mimeType: "application/pdf"
});
}
item.complete();
});
translator.translate();
await translator.translate();
}
}/** BEGIN TEST CASES **/
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "http://drops.dagstuhl.de/opus/frontdoor.php?source_opus=4958",
"url": "https://drops.dagstuhl.de/entities/document/10.4230/LIPIcs.STACS.2015.1",
"items": [
{
"itemType": "conferencePaper",
"title": "Overcoming Intractability in Unsupervised Learning (Invited Talk)",
"title": "Overcoming Intractability in Unsupervised Learning",
"creators": [
{
"firstName": "Sanjeev",
@ -153,18 +155,19 @@ var testCases = [
"date": "2015",
"DOI": "10.4230/LIPIcs.STACS.2015.1",
"ISBN": "9783939897781",
"itemID": "arora:LIPIcs:2015:4958",
"itemID": "arora:LIPIcs.STACS.2015.1",
"libraryCatalog": "Dagstuhl Research Online Publication Server",
"pages": "11",
"place": "Dagstuhl, Germany",
"proceedingsTitle": "32nd International Symposium on Theoretical Aspects of Computer Science (STACS 2015)",
"publisher": "Schloss DagstuhlLeibniz-Zentrum fuer Informatik",
"publisher": "Schloss Dagstuhl Leibniz-Zentrum für Informatik",
"series": "Leibniz International Proceedings in Informatics (LIPIcs)",
"url": "http://drops.dagstuhl.de/opus/volltexte/2015/4958",
"url": "https://drops.dagstuhl.de/entities/document/10.4230/LIPIcs.STACS.2015.1",
"volume": "30",
"attachments": [
{
"title": "Snapshot"
"title": "Snapshot",
"mimeType": "text/html"
},
{
"title": "Full Text PDF",
@ -184,17 +187,17 @@ var testCases = [
},
{
"type": "web",
"url": "http://drops.dagstuhl.de/opus/portals/lipics/index.php?semnr=15001",
"url": "https://drops.dagstuhl.de/entities/volume/LIPIcs-volume-30",
"items": "multiple"
},
{
"type": "web",
"url": "http://drops.dagstuhl.de/opus/ergebnis.php?wer=opus&suchart=teil&Lines_Displayed=10&sort=o.date_year+DESC%2C+o.title&suchfeld1=freitext&suchwert1=&opt1=AND&opt2=AND&suchfeld3=date_year&suchwert3=&startindex=0&page=0&dir=2&suche=&suchfeld2=oa.person&suchwert2=Hauzar%2C%20David",
"url": "https://drops.dagstuhl.de/search?term=Hauzar%2C%20David",
"items": "multiple"
},
{
"type": "web",
"url": "http://drops.dagstuhl.de/opus/volltexte/2016/5933/",
"url": "https://drops.dagstuhl.de/entities/document/10.4230/LIPIcs.SoCG.2016.41",
"items": [
{
"itemType": "conferencePaper",
@ -239,18 +242,19 @@ var testCases = [
"date": "2016",
"DOI": "10.4230/LIPIcs.SoCG.2016.41",
"ISBN": "9783959770095",
"itemID": "geyer_et_al:LIPIcs:2016:5933",
"itemID": "geyer_et_al:LIPIcs.SoCG.2016.41",
"libraryCatalog": "Dagstuhl Research Online Publication Server",
"pages": "41:141:15",
"place": "Dagstuhl, Germany",
"proceedingsTitle": "32nd International Symposium on Computational Geometry (SoCG 2016)",
"publisher": "Schloss DagstuhlLeibniz-Zentrum fuer Informatik",
"publisher": "Schloss Dagstuhl Leibniz-Zentrum für Informatik",
"series": "Leibniz International Proceedings in Informatics (LIPIcs)",
"url": "http://drops.dagstuhl.de/opus/volltexte/2016/5933",
"url": "https://drops.dagstuhl.de/entities/document/10.4230/LIPIcs.SoCG.2016.41",
"volume": "51",
"attachments": [
{
"title": "Snapshot"
"title": "Snapshot",
"mimeType": "text/html"
},
{
"title": "Full Text PDF",
@ -269,4 +273,4 @@ var testCases = [
]
}
]
/** END TEST CASES **/
/** END TEST CASES **/

File diff suppressed because one or more lines are too long

View File

@ -1,15 +1,15 @@
{
"translatorID": "2a5dc3ed-ee5e-4bfb-baad-36ae007e40ce",
"label": "De Gruyter",
"label": "De Gruyter Brill",
"creator": "Abe Jellinek",
"target": "^https?://www\\.degruyter\\.com/",
"target": "^https?://www\\.degruyterbrill\\.com/",
"minVersion": "2.1.9",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2021-09-02 21:52:03"
"lastUpdated": "2025-05-13 13:34:42"
}
/*
@ -37,23 +37,20 @@
function detectWeb(doc, url) {
let title = attr(doc, 'meta[name="citation_title"]', 'content');
if (title) {
if (doc.querySelector('meta[name="citation_isbn"]')) {
let bookTitle = attr(doc, 'meta[name="citation_inbook_title"]', 'content');
if (!bookTitle || title == bookTitle) {
return "book";
let pageCategory = doc.body.getAttribute('data-pagecategory');
switch (pageCategory) {
case 'book':
return 'book';
case 'chapter':
return 'bookSection';
case 'article':
return 'journalArticle';
case 'search':
case 'journal':
default:
if (getSearchResults(doc, true)) {
return "multiple";
}
else {
return "bookSection";
}
}
else {
return "journalArticle";
}
}
else if (getSearchResults(doc, true)) {
return "multiple";
}
return false;
}
@ -62,6 +59,9 @@ function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
var rows = doc.querySelectorAll('.resultTitle > a[href*="/document/"]');
if (!rows.length) {
rows = doc.querySelectorAll('li a[href*="/document/"][data-doi]');
}
for (let row of rows) {
let href = row.href;
let title = ZU.trimInternal(row.textContent);
@ -127,18 +127,38 @@ function scrape(doc, url) {
delete item.bookTitle;
}
if (item.bookTitle && !item.bookTitle.includes(': ')) {
if (item.itemType == 'bookSection') {
delete item.publicationTitle;
delete item.abstractNote;
delete item.rights; // AI training disclaimer!
let risURL = attr(doc, 'a[title="Download in RIS format"]', 'href');
if (!risURL) {
risURL = url.replace(/\/html([?#].*)$/, '/machineReadableCitation/RIS');
}
ZU.doGet(risURL, function (risText) {
let bookTitle = risText.match(/^\s*T1\s*-\s*(.*)$/m);
if (bookTitle) {
item.bookTitle = bookTitle[1];
// De Gruyter uses TI for the container title and T2 for the subtitle
// Seems nonstandard! So we'll just handle it here
let titleMatch = risText.match(/^\s*TI\s*-\s*(.+)/m);
let subtitleMatch = risText.match(/^\s*T2\s*-\s*(.+)/m);
if (titleMatch) {
item.bookTitle = titleMatch[1];
if (subtitleMatch) {
item.bookTitle = item.bookTitle.trim() + ': ' + subtitleMatch[1];
}
}
item.complete();
let translator = Zotero.loadTranslator('import');
translator.setTranslator('32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7');
translator.setString(risText);
translator.setHandler('itemDone', (_obj, risItem) => {
if (!item.creators.some(c => c.creatorType == 'editor')) {
item.creators.push(...risItem.creators.filter(c => c.creatorType == 'editor'));
}
item.complete();
});
translator.translate();
});
}
else {
@ -147,7 +167,17 @@ function scrape(doc, url) {
});
translator.getTranslatorObject(function (trans) {
if (detectWeb(doc, url) == 'bookSection') {
let detectedType = detectWeb(doc, url);
if (detectedType == 'book') {
// Delete citation_inbook_title if this is actually a book, not a book section
// Prevents EM from mis-detecting as a bookSection in a way that even setting
// trans.itemType can't override
let bookTitleMeta = doc.querySelector('meta[name="citation_inbook_title"]');
if (bookTitleMeta) {
bookTitleMeta.remove();
}
}
else if (detectedType == 'bookSection') {
trans.itemType = 'bookSection';
}
trans.addCustomFields({
@ -164,7 +194,7 @@ function scrape(doc, url) {
var testCases = [
{
"type": "web",
"url": "https://www.degruyter.com/document/doi/10.1515/vfzg-2021-0028/html",
"url": "https://www.degruyterbrill.com/document/doi/10.1515/vfzg-2021-0028/html",
"items": [
{
"itemType": "journalArticle",
@ -181,12 +211,13 @@ var testCases = [
"ISSN": "2196-7121",
"abstractNote": "Die Geschichte homosexueller Menschen im modernen Deutschland besteht nicht nur aus Verfolgung und Diskriminierung, obschon sie oft als solche erinnert wird. Wohl haben homosexuelle Männer unter massiver Verfolgung gelitten, und auch lesbische Frauen waren vielen Diskriminierungen ausgesetzt. Doch die Geschichte der letzten 200 Jahre weist nicht nur jene Transformation im Umgang mit Homosexualität auf, die ab den 1990er Jahren zur Gleichberechtigung führte, sondern mehrere, inhaltlich sehr verschiedene Umbrüche. Wir haben es weder mit einem Kontinuum der Repression noch mit einer linearen Emanzipationsgeschichte zu tun, sondern mit einer höchst widersprüchlichen langfristigen Entwicklung.",
"issue": "3",
"language": "de",
"libraryCatalog": "www.degruyter.com",
"language": "en",
"libraryCatalog": "www.degruyterbrill.com",
"pages": "377-414",
"publicationTitle": "Vierteljahrshefte für Zeitgeschichte",
"rights": "De Gruyter expressly reserves the right to use all content for commercial text and data mining within the meaning of Section 44b of the German Copyright Act.",
"shortTitle": "Homosexuelle im modernen Deutschland",
"url": "https://www.degruyter.com/document/doi/10.1515/vfzg-2021-0028/html",
"url": "https://www.degruyterbrill.com/document/doi/10.1515/vfzg-2021-0028/html",
"volume": "69",
"attachments": [
{
@ -218,7 +249,7 @@ var testCases = [
},
{
"type": "web",
"url": "https://www.degruyter.com/document/doi/10.3138/9781487518806/html",
"url": "https://www.degruyterbrill.com/document/doi/10.3138/9781487518806/html",
"items": [
{
"itemType": "book",
@ -230,14 +261,15 @@ var testCases = [
"creatorType": "author"
}
],
"date": "2021-08-25",
"date": "2021-07-30",
"ISBN": "9781487518806",
"abstractNote": "Bringing together themes in the history of art, punishment, religion, and the history of medicine, Picturing Punishment provides new insights into the wider importance of the criminal to civic life.",
"language": "en",
"libraryCatalog": "www.degruyter.com",
"libraryCatalog": "www.degruyterbrill.com",
"publisher": "University of Toronto Press",
"rights": "De Gruyter expressly reserves the right to use all content for commercial text and data mining within the meaning of Section 44b of the German Copyright Act.",
"shortTitle": "Picturing Punishment",
"url": "https://www.degruyter.com/document/doi/10.3138/9781487518806/html",
"url": "https://www.degruyterbrill.com/document/doi/10.3138/9781487518806/html",
"attachments": [
{
"title": "Full Text PDF",
@ -295,7 +327,7 @@ var testCases = [
},
{
"type": "web",
"url": "https://www.degruyter.com/document/doi/10.3138/9781487518806-008/html",
"url": "https://www.degruyterbrill.com/document/doi/10.3138/9781487518806-008/html",
"items": [
{
"itemType": "bookSection",
@ -307,16 +339,15 @@ var testCases = [
"creatorType": "author"
}
],
"date": "2021-08-25",
"date": "2021-07-30",
"ISBN": "9781487518806",
"abstractNote": "5 Serving the Public Good: Reform, Prestige, and the Productive Criminal Body in Amsterdam was published in Picturing Punishment on page 135.",
"bookTitle": "Picturing Punishment: The Spectacle and Material Afterlife of the Criminal Body in the Dutch Republic",
"language": "en",
"libraryCatalog": "www.degruyter.com",
"libraryCatalog": "www.degruyterbrill.com",
"pages": "135-157",
"publisher": "University of Toronto Press",
"shortTitle": "5 Serving the Public Good",
"url": "https://www.degruyter.com/document/doi/10.3138/9781487518806-008/html",
"url": "https://www.degruyterbrill.com/document/doi/10.3138/9781487518806-008/html",
"attachments": [],
"tags": [],
"notes": [],
@ -326,7 +357,7 @@ var testCases = [
},
{
"type": "web",
"url": "https://www.degruyter.com/document/doi/10.1515/ncrs-2021-0236/html",
"url": "https://www.degruyterbrill.com/document/doi/10.1515/ncrs-2021-0236/html",
"items": [
{
"itemType": "journalArticle",
@ -359,10 +390,11 @@ var testCases = [
"abstractNote": "C 17 H 14 FNO 2 , monoclinic, P 2 1 / c (no. 15), a  = 7.3840(6) Å, b  = 10.9208(8) Å, c  = 16.7006(15) Å, β  = 101.032(9)°, V  = 1321.84(19) Å 3 , Z  = 4, R gt ( F ) = 0.0589, wR ref ( F 2 ) = 0.1561, T = 100.00(18) K.",
"issue": "5",
"language": "en",
"libraryCatalog": "www.degruyter.com",
"libraryCatalog": "www.degruyterbrill.com",
"pages": "1101-1103",
"publicationTitle": "Zeitschrift für Kristallographie - New Crystal Structures",
"url": "https://www.degruyter.com/document/doi/10.1515/ncrs-2021-0236/html",
"rights": "De Gruyter expressly reserves the right to use all content for commercial text and data mining within the meaning of Section 44b of the German Copyright Act.",
"url": "https://www.degruyterbrill.com/document/doi/10.1515/ncrs-2021-0236/html",
"volume": "236",
"attachments": [
{
@ -378,7 +410,7 @@ var testCases = [
},
{
"type": "web",
"url": "https://www.degruyter.com/document/doi/10.1515/ncrs-2021-0236/html",
"url": "https://www.degruyterbrill.com/document/doi/10.1515/ncrs-2021-0236/html",
"items": [
{
"itemType": "journalArticle",
@ -411,10 +443,11 @@ var testCases = [
"abstractNote": "C 17 H 14 FNO 2 , monoclinic, P 2 1 / c (no. 15), a  = 7.3840(6) Å, b  = 10.9208(8) Å, c  = 16.7006(15) Å, β  = 101.032(9)°, V  = 1321.84(19) Å 3 , Z  = 4, R gt ( F ) = 0.0589, wR ref ( F 2 ) = 0.1561, T = 100.00(18) K.",
"issue": "5",
"language": "en",
"libraryCatalog": "www.degruyter.com",
"libraryCatalog": "www.degruyterbrill.com",
"pages": "1101-1103",
"publicationTitle": "Zeitschrift für Kristallographie - New Crystal Structures",
"url": "https://www.degruyter.com/document/doi/10.1515/ncrs-2021-0236/html",
"rights": "De Gruyter expressly reserves the right to use all content for commercial text and data mining within the meaning of Section 44b of the German Copyright Act.",
"url": "https://www.degruyterbrill.com/document/doi/10.1515/ncrs-2021-0236/html",
"volume": "236",
"attachments": [
{
@ -431,12 +464,211 @@ var testCases = [
{
"type": "web",
"url": "https://www.degruyter.com/search?query=test",
"defer": true,
"items": "multiple"
},
{
"type": "web",
"url": "https://www.degruyter.com/journal/key/mt/html",
"url": "https://www.degruyterbrill.com/journal/key/mt/67/5/html",
"items": "multiple"
},
{
"type": "web",
"url": "https://www.degruyterbrill.com/document/doi/10.1515/9783110773712-010/html",
"items": [
{
"itemType": "bookSection",
"title": "10 Skaldic Poetry Encrypted Communication",
"creators": [
{
"firstName": "Jon Gunnar",
"lastName": "Jørgensen",
"creatorType": "author"
},
{
"lastName": "Engh",
"firstName": "Line Cecilie",
"creatorType": "editor"
},
{
"lastName": "Gullbekk",
"firstName": "Svein Harald",
"creatorType": "editor"
},
{
"lastName": "Orning",
"firstName": "Hans Jacob",
"creatorType": "editor"
}
],
"date": "2024-08-19",
"ISBN": "9783110773712",
"bookTitle": "Standardization in the Middle Ages: Volume 1: The North",
"language": "en",
"libraryCatalog": "www.degruyterbrill.com",
"pages": "229-250",
"publisher": "De Gruyter",
"url": "https://www.degruyterbrill.com/document/doi/10.1515/9783110773712-010/html",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.degruyterbrill.com/document/doi/10.3138/9781487552978/html",
"items": [
{
"itemType": "book",
"title": "Freedoms of Speech: Anthropological Perspectives on Language, Ethics, and Power",
"creators": [],
"date": "2024-12-16",
"ISBN": "9781487552978",
"abstractNote": "This collection brings together leading anthropologists and fresh new voices in the discipline to consider freedoms of speech with a wide comparative lens.",
"language": "en",
"libraryCatalog": "www.degruyterbrill.com",
"publisher": "University of Toronto Press",
"rights": "De Gruyter expressly reserves the right to use all content for commercial text and data mining within the meaning of Section 44b of the German Copyright Act.",
"shortTitle": "Freedoms of Speech",
"url": "https://www.degruyterbrill.com/document/doi/10.3138/9781487552978/html",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [
{
"tag": "censors"
},
{
"tag": "censorship"
},
{
"tag": "defamation"
},
{
"tag": "dissent"
},
{
"tag": "ethics"
},
{
"tag": "fascism"
},
{
"tag": "free speech Islam"
},
{
"tag": "free speech Russia"
},
{
"tag": "freedom of speech"
},
{
"tag": "human rights"
},
{
"tag": "linguistics"
},
{
"tag": "politics of free speech"
},
{
"tag": "press freedom"
},
{
"tag": "speech debates"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.degruyterbrill.com/document/doi/10.1515/9783111233758/html",
"items": [
{
"itemType": "book",
"title": "Internet Lexicography: An Introduction",
"creators": [],
"date": "2024-11-04",
"ISBN": "9783111233758",
"abstractNote": "The Internet has become the central publication platform for dictionaries. This profound change in the dictionary landscape gives rise to a whole range of new questions for lexicographic practice and dictionary research. This volume provides for the first time an introduction to the central fields of work in Internet lexicography and presents the current state of scientific research and lexicographic practice. The chapters cover key aspects of dictionary creation, such as the technical framework, data modeling, and lexicographic process, linking dictionary content, access and navigation structures, automatic extraction of lexicographic information, user participation, and research on dictionary use. The aim of this volume is to provide students and teachers (at universities) with an introductory and easy-to-read overview on Internet lexicography, thus anchoring this important and innovative field of research and practice in university teaching. All chapters convey the basic concepts and methods in a comprehensible way and are enriched by references to further and more in-depth reading.",
"language": "en",
"libraryCatalog": "www.degruyterbrill.com",
"publisher": "De Gruyter",
"rights": "De Gruyter expressly reserves the right to use all content for commercial text and data mining within the meaning of Section 44b of the German Copyright Act.",
"shortTitle": "Internet Lexicography",
"url": "https://www.degruyterbrill.com/document/doi/10.1515/9783111233758/html",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [
{
"tag": "Lexicography"
},
{
"tag": "digital language tools"
},
{
"tag": "language documentation"
},
{
"tag": "linguistics"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.degruyterbrill.com/document/doi/10.31826/9781463235949-008/html",
"items": [
{
"itemType": "bookSection",
"title": "Did Isaiah Really See God? The Ancient Discussion About Isaiah 6:1",
"creators": [
{
"firstName": "Magnar",
"lastName": "Kartveit",
"creatorType": "author"
},
{
"lastName": "Zehnder",
"firstName": "Markus",
"creatorType": "editor"
}
],
"date": "2014-05-14",
"ISBN": "9781463235949",
"bookTitle": "New Studies in the Book of Isaiah: Essays in Honor of Hallvard Hagelia",
"language": "en",
"libraryCatalog": "www.degruyterbrill.com",
"pages": "115-136",
"publisher": "Gorgias Press",
"shortTitle": "Did Isaiah Really See God?",
"url": "https://www.degruyterbrill.com/document/doi/10.31826/9781463235949-008/html",
"attachments": [],
"tags": [],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

View File

@ -2,14 +2,14 @@
"translatorID": "d8341c22-8cf4-428f-be3b-ada9fa8933eb",
"label": "Deutsche Nationalbibliothek",
"creator": "Philipp Zumstein",
"target": "^https?://portal\\.dnb\\.de/opac\\.htm\\?",
"target": "^https?://portal\\.dnb\\.de/opac(\\.htm|/(enhancedSearch|simpleSearch|showFullRecord)\\?)",
"minVersion": "3.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2018-05-14 19:08:02"
"lastUpdated": "2024-01-15 19:48:46"
}
/*
@ -36,51 +36,55 @@
*/
var typeMapping = {
//"Blindendrucke"
"Bücher" : "book",
//"Elektronische Datenträger"
"Filme/Hörbücher" : "videoRecording",
"Karten" : "map",
//"Blindendrucke"
Bücher: "book",
//"Elektronische Datenträger"
"Filme/Hörbücher": "videoRecording",
Karten: "map",
//"Medienkombinationen"
//"Mikroformen"
"Musiktonträger" : "audioRecording",
//"Musiknoten"
"Artikel" : "journalArticle",
Musiktonträger: "audioRecording",
//"Musiknoten"
Artikel: "journalArticle",
//"Online Ressourcen"
//"Zeitschriften/Serien"
//"Ausgaben/Hefte"
"archivierte Webseiten" : "webpage",
"archivierte Webseiten": "webpage",
//"Gesamttitel Sammlung/Nachlass"
"Manuskripte" : "manuscript",
"Briefe" : "letter",
Manuskripte: "manuscript",
Briefe: "letter",
//"Lebensdokumente"
//"Sammlungen"
//"Trägermaterialien (Papiere und Einbände)"
"Bilder/Grafiken" : "artwork"
"Bilder/Grafiken": "artwork"
//"Flugblätter"
};
function detectWeb(doc, url) {
if (
url.indexOf('method=showFullRecord')>-1 ||
(url.indexOf('method=simpleSearch')>-1 && doc.getElementById('fullRecordTable'))
(url.includes('method=showFullRecord') || url.includes('/showFullRecord?'))
|| ((url.includes('method=simpleSearch') || url.includes('/simpleSearch?') || url.includes('/enhancedSearch?') || url.includes('method=enhancedSearch'))
&& doc.getElementById('fullRecordTable'))
) {
var type=ZU.xpathText(doc, '//table[@id="fullRecordTable"]/tbody/tr/td/img/@alt');
var type = ZU.xpathText(doc, '//table[@id="fullRecordTable"]/tbody/tr/td/img/@alt');
if (typeMapping[type]) {
return typeMapping[type];
} else {
}
else {
return "book";
}
} else if (getSearchResults(doc, true)) {
}
else if (getSearchResults(doc, true)) {
return "multiple";
}
return false;
}
function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
var rows = ZU.xpath(doc, '//table[@id="searchresult"]//a[contains(@id, "recordLink")]');
for (var i=0; i<rows.length; i++) {
for (var i = 0; i < rows.length; i++) {
var href = rows[i].href;
var title = ZU.trimInternal(rows[i].firstChild.textContent);
if (!href || !title) continue;
@ -92,63 +96,57 @@ function getSearchResults(doc, checkOnly) {
}
function doWeb(doc, url) {
if (detectWeb(doc, url) == "multiple") {
Zotero.selectItems(getSearchResults(doc, false), function (items) {
if (!items) {
return true;
}
var articles = [];
for (var i in items) {
articles.push(i);
}
ZU.processDocuments(articles, scrape);
});
} else {
scrape(doc, url);
async function doWeb(doc, url) {
if (detectWeb(doc, url) == 'multiple') {
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(await requestDocument(url));
}
}
else {
await scrape(doc);
}
}
function scrape(doc, url) {
async function scrape(doc) {
var marc = ZU.xpath(doc, '//div[@class="link"]//a[contains(@href, "/about/marcxml")]');
if (marc.length) {
var marcUrl = marc[0].href;
ZU.doGet(marcUrl, function(result) {
//call MARCXML translator
var translator = Zotero.loadTranslator("import");
translator.setTranslator("edd87d07-9194-42f8-b2ad-997c4c7deefd");
translator.setString(result);
translator.setHandler("itemDone", function (obj, item) {
finalize(doc, item);
item.complete();
});
translator.translate();
});
} else {
Z.debug("No MARC link found --> Use COinS translator");
//call COinS translator
var translator = Zotero.loadTranslator("web");
translator.setTranslator("05d07af9-105a-4572-99f6-a8e231c0daef");
translator.setDocument(doc);
translator.setHandler("itemDone", function (obj, item) {
let result = await requestText(marcUrl);
//call MARCXML translator
let translator = Zotero.loadTranslator("import");
translator.setTranslator("edd87d07-9194-42f8-b2ad-997c4c7deefd");
translator.setString(result);
translator.setHandler("itemDone", (_obj, item) => {
finalize(doc, item);
item.complete();
});
translator.translate();
await translator.translate();
}
}
else {
Z.debug("No MARC link found --> Use COinS translator");
// call COinS translator
// eslint-disable-next-line no-redeclare
let translator = Zotero.loadTranslator("web");
translator.setTranslator("05d07af9-105a-4572-99f6-a8e231c0daef");
translator.setDocument(doc);
translator.setHandler("itemDone", (_obj, item) => {
finalize(doc, item);
item.complete();
});
await translator.translate();
}
}
function finalize(doc, item) {
var toc = ZU.xpath(doc, '//a[contains(@title, "Inhaltsverzeichnis")]');
if (toc.length) {
item.attachments.push( {
url : toc[0].href,
item.attachments.push({
url: toc[0].href,
title: "Table of Contents PDF",
mimeType: "application/pdf"
});
@ -156,8 +154,8 @@ function finalize(doc, item) {
var abstract = ZU.xpath(doc, '//a[contains(@title, "Inhaltstext")]');
if (abstract.length) {
item.attachments.push( {
url : abstract[0].href,
item.attachments.push({
url: abstract[0].href,
title: "Abstract",
mimeType: "text/html"
});
@ -491,6 +489,106 @@ var testCases = [
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://portal.dnb.de/opac/simpleSearch?query=test",
"items": "multiple"
},
{
"type": "web",
"url": "https://portal.dnb.de/opac/simpleSearch?query=idn%3D1272086992&cqlMode=true",
"items": [
{
"itemType": "book",
"title": "Den Netten beißen die Hunde: Wie Sie sich Respekt verschaffen, Grenzen setzen und den verdienten Erfolg erlangen - Mit großem \"Bin ich zu nett?\"-Test",
"creators": [
{
"firstName": "Martin",
"lastName": "Wehrle",
"creatorType": "author"
}
],
"date": "2024",
"ISBN": "9783442179046",
"language": "ger",
"libraryCatalog": "Deutsche Nationalbibliothek",
"numPages": "320",
"place": "München",
"publisher": "Goldmann",
"shortTitle": "Den Netten beißen die Hunde",
"attachments": [
{
"title": "Abstract",
"mimeType": "text/html"
}
],
"tags": [
{
"tag": "(Produktform)Paperback / softback"
},
{
"tag": "(VLB-WN)2933: Taschenbuch / Sachbücher/Angewandte Psychologie"
},
{
"tag": "Business"
},
{
"tag": "Büro"
},
{
"tag": "Den Letzten beißen die Hunde"
},
{
"tag": "Durchsetzungsvermögen"
},
{
"tag": "Mental Load"
},
{
"tag": "Nein sagen ohne Schuldgefühle"
},
{
"tag": "Partnerschaft Kommunikation"
},
{
"tag": "Sei einzig nicht artig"
},
{
"tag": "Selbstbewusstsein"
},
{
"tag": "Selbstbewustsein stärken"
},
{
"tag": "Selbstrespekt"
},
{
"tag": "Wenn jeder dich mag nimmt keiner dich ernst"
},
{
"tag": "Wertschätzung"
},
{
"tag": "ausgenutzt werden"
},
{
"tag": "ernst genommen werden"
},
{
"tag": "fehlende Anerkennung"
},
{
"tag": "sich durchsetzen"
},
{
"tag": "spiegel bestseller"
}
],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

View File

@ -9,104 +9,199 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2012-09-20 20:46:53"
"lastUpdated": "2024-05-15 15:07:13"
}
function detectWeb(doc, url) {
if (doc.evaluate('//div[@class="DHQarticle"]', doc, null, XPathResult.ANY_TYPE, null).iterateNext()) {
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2012-2024 Michael Berkowitz
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
function detectWeb(doc, _url) {
if (doc.querySelector('.DHQarticle')) {
return "journalArticle";
} else if (doc.evaluate('//div[@id="mainContent"]/div/p', doc, null, XPathResult.ANY_TYPE, null).iterateNext()) {
}
if (doc.querySelector('#toc') && getSearchResults(doc, true)) {
return "multiple";
}
return false;
}
function xpathtext(doc, xpath, xdoc) {
return Zotero.Utilities.trimInternal(doc.evaluate(xpath, xdoc, null, XPathResult.ANY_TYPE, null).iterateNext().textContent);
}
function doWeb(doc, url) {
var articles = new Array();
if (detectWeb(doc, url) == "multiple") {
var items = new Object;
var arts = doc.evaluate('//div[@id="mainContent"]/div/p/a', doc, null, XPathResult.ANY_TYPE, null);
var art;
while (art = arts.iterateNext()) {
items[art.href] = art.textContent;
}
Zotero.selectItems(items, function (items) {
if (!items) {
return true;
}
for (var i in items) {
articles.push(i);
}
scrape(articles, function () {
});
});
}
else {
articles = [url];
scrape(articles);
function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
var rows = doc.querySelectorAll('#toc .articleInfo > a:first-of-type');
for (let row of rows) {
let href = row.href;
let title = ZU.trimInternal(row.textContent);
if (!href || !title) continue;
if (checkOnly) return true;
found = true;
items[href] = title;
}
Zotero.debug(articles);}
return found ? items : false;
}
function scrape(articles){
Zotero.Utilities.processDocuments(articles, function(newDoc) {
var item = new Zotero.Item("journalArticle");
item.url = newDoc.location.href;
item.title = xpathtext(newDoc, '//h1[@class="articleTitle"]', newDoc);
var voliss = xpathtext(newDoc, '//div[@id="pubInfo"]', newDoc);
voliss = voliss.match(/(.*)Volume\s+(\d+)\s+Number\s+(\d+)/);
item.date = voliss[1];
item.volume = voliss[2];
item.issue = voliss[3];
var authors = newDoc.evaluate('//div[@class="author"]', newDoc, null, XPathResult.ANY_TYPE, null);
var aut;
while (aut = authors.iterateNext()) {
item.creators.push(Zotero.Utilities.cleanAuthor(xpathtext(newDoc, './a[1]', aut), "author"));
async function doWeb(doc, url) {
if (detectWeb(doc, url) == "multiple") {
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (!items) return;
for (let url of Object.keys(items)) {
scrape(await requestDocument(url));
}
item.attachments = [{url:item.url, title:"DHQ Snapshot", mimeType:"text/html"}];
item.complete();
}, function() {});}/** BEGIN TEST CASES **/
}
else {
scrape(doc, url);
}
}
function scrape(doc, url = doc.location.href) {
// Get the metadata
const main = doc.querySelector('#mainContent');
// Of the form "YYYY Volume.Issue"
const [year, volume, issue] = text(main, '.toolbar > a').split(/[\s\\.]+/);
const title = ZU.trimInternal(text(main, 'h1.articleTitle'));
const authors = main.querySelectorAll('.DHQheader .author');
const abstract = ZU.trimInternal(text(main, '#abstract > p'));
const license = ZU.trimInternal(text(main, ".license > a[rel='license']:last-of-type"));
// Build item
const item = new Z.Item("journalArticle");
item.url = doc.location.href;
item.title = title;
item.creators = [...authors].map((author) => {
return ZU.cleanAuthor(text(author, 'a:first-child'), "author");
});
item.publicationTitle = "Digital Humanities Quarterly";
item.ISSN = "1938-4122";
item.date = year;
item.volume = volume;
item.issue = issue;
item.abstractNote = abstract;
item.rights = license;
const pdfLink = main.querySelector('.toolbar > a[href$=".pdf"]');
if (pdfLink) {
item.attachments.push({
url: pdfLink.href,
title: "Full Text PDF",
mimeType: "application/pdf"
});
}
else {
item.attachments.push({
document: doc,
title: "Snapshot"
});
}
item.complete();
}
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "http://www.digitalhumanities.org/dhq/vol/5/2/000094/000094.html",
"url": "https://www.digitalhumanities.org/dhq/vol/5/2/index.html",
"items": "multiple"
},
{
"type": "web",
"url": "https://www.digitalhumanities.org/dhq/vol/17/1/000671/000671.html",
"items": [
{
"itemType": "journalArticle",
"title": "Introduction to Special Issue: Project Resiliency in the Digital Humanities",
"creators": [
{
"firstName": "Wesley",
"lastName": "Beal",
"firstName": "Martin",
"lastName": "Holmes",
"creatorType": "author"
},
{
"firstName": "Janelle",
"lastName": "Jenstad",
"creatorType": "author"
},
{
"firstName": "J. Matthew",
"lastName": "Huculak",
"creatorType": "author"
}
],
"notes": [],
"tags": [],
"seeAlso": [],
"date": "2023",
"ISSN": "1938-4122",
"abstractNote": "This introduction to the Project Resiliency issue argues that we have work to do in getting projects to the point of being done and archivable. The Endings Project, a collaboration between three developers, three humanities scholars, and three librarians, arose from the maintenance burden accrued by the Humanities Computing and Media Centre at the University of Victoria and our desire to design projects that, from their inception, are ready for long-term archiving. After describing the events leading up to the Endings Symposium and briefly summarizing the articles in this issue, we discuss the necessity of a culture of constraint if we wish to preserve digital humanities projects in the same way that libraries preserve books.",
"issue": "1",
"libraryCatalog": "Digital Humanities Quarterly",
"publicationTitle": "Digital Humanities Quarterly",
"rights": "Creative Commons Attribution-NoDerivatives 4.0 International License",
"shortTitle": "Introduction to Special Issue",
"url": "https://www.digitalhumanities.org/dhq/vol/17/1/000671/000671.html",
"volume": "17",
"attachments": [
{
"url": "http://www.digitalhumanities.org/dhq/vol/5/2/000094/000094.html",
"title": "DHQ Snapshot",
"mimeType": "text/html"
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"url": "http://www.digitalhumanities.org/dhq/vol/5/2/000094/000094.html",
"title": "Network Narration in John Dos Passoss U.S.A. Trilogy",
"date": "2011",
"volume": "5",
"issue": "2",
"libraryCatalog": "Digital Humanities Quarterly",
"accessDate": "CURRENT_TIMESTAMP"
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "http://www.digitalhumanities.org/dhq/vol/5/1/index.html",
"items": "multiple"
"url": "https://www.digitalhumanities.org/dhq/vol/17/2/000699/000699.html",
"items": [
{
"itemType": "journalArticle",
"title": "ᐊᒐᐦᑭᐯᐦᐃᑲᓇ ᒫᒥᑐᓀᔨᐦᐃᒋᑲᓂᐦᑳᓂᕽ | acahkipehikana mâmitoneyihicikanihkânihk | Programming with Cree# and Ancestral Code: Nehiyawewin Spirit Markings in an Artificial Brain",
"creators": [
{
"firstName": "Jon",
"lastName": "Corbett",
"creatorType": "author"
}
],
"date": "2023",
"ISSN": "1938-4122",
"abstractNote": "In this article, I discuss my project “Ancestral Code”, which consists of an integrated development environment (IDE) and the Nehiyaw (Plains Cree) based programming languages called Cree# (pronounced: Cree-Sharp) and ᐊᒋᒧ (âcimow). These languages developed in response to western perspectives on human-computer relationships, which I challenge and reframe in Nehiyaw/Indigenous contexts.",
"issue": "2",
"libraryCatalog": "Digital Humanities Quarterly",
"publicationTitle": "Digital Humanities Quarterly",
"rights": "Creative Commons Attribution-NoDerivatives 4.0 International License",
"shortTitle": "ᐊᒐᐦᑭᐯᐦᐃᑲᓇ ᒫᒥᑐᓀᔨᐦᐃᒋᑲᓂᐦᑳᓂᕽ | acahkipehikana mâmitoneyihicikanihkânihk | Programming with Cree# and Ancestral Code",
"url": "https://www.digitalhumanities.org/dhq/vol/17/2/000699/000699.html",
"volume": "17",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/
/** END TEST CASES **/

View File

@ -2,14 +2,14 @@
"translatorID": "fc353b26-8911-4c34-9196-f6f567c93901",
"label": "Douban",
"creator": "Ace Strong<acestrong@gmail.com>",
"target": "^https?://(www|book)\\.douban\\.com/(subject|doulist|people/[a-zA-Z._]*/(do|wish|collect)|.*?status=(do|wish|collect)|group/[0-9]*?/collection|tag)",
"target": "^https?://(www|book)\\.douban\\.com/(subject|doulist|people/[a-zA-Z0-9._]*/(do|wish|collect)|.*?status=(do|wish|collect)|group/[0-9]*?/collection|tag)",
"minVersion": "2.0rc1",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2020-06-04 03:46:18"
"lastUpdated": "2024-08-07 08:46:18"
}
/*
@ -189,7 +189,7 @@ function scrapeAndParse(doc, url) {
// #########################
function detectWeb(doc, url) {
var pattern = /subject_search|doulist|people\/[a-zA-Z._]*?\/(?:do|wish|collect)|.*?status=(?:do|wish|collect)|group\/[0-9]*?\/collection|tag/;
var pattern = /subject_search|doulist|people\/[a-zA-Z0-9._]*?\/(?:do|wish|collect)|.*?status=(?:do|wish|collect)|group\/[0-9]*?\/collection|tag/;
if (pattern.test(url)) {
return "multiple";

View File

@ -9,30 +9,30 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2022-10-05 02:33:49"
"lastUpdated": "2023-10-23 09:05:55"
}
/*
***** BEGIN LICENSE BLOCK *****
***** BEGIN LICENSE BLOCK *****
Copyright © 2022 Sebastian Karcher
Copyright © 2022 Sebastian Karcher
This file is part of Zotero.
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
***** END LICENSE BLOCK *****
*/
@ -64,11 +64,9 @@ function getSearchResults(doc, checkOnly) {
async function doWeb(doc, url) {
if (detectWeb(doc, url) == 'multiple') {
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (items) {
await Promise.all(
Object.keys(items)
.map(url => requestDocument(url).then(scrape))
);
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(await requestDocument(url));
}
}
else {
@ -213,6 +211,40 @@ var testCases = [
"type": "web",
"url": "https://www.dukeupress.edu/books/browse?sortid=7",
"items": "multiple"
},
{
"type": "web",
"url": "https://www.dukeupress.edu/beyond-this-narrow-now",
"items": [
{
"itemType": "book",
"title": "\"Beyond This Narrow Now\": Or, Delimitations, of W. E. B. Du Bois",
"creators": [
{
"firstName": "Nahum Dimitri",
"lastName": "Chandler",
"creatorType": "author"
}
],
"date": "2022",
"ISBN": "9781478014805",
"abstractNote": "In “Beyond This Narrow Now” Nahum Dimitri Chandler shows that the premises of W. E. B. Du Bois's thinking at the turn of the twentieth century stand as fundamental references for the whole itinerary of his thought. Opening with a distinct approach to the legacy of Du Bois, Chandler proceeds through a series of close readings of Du Bois's early essays, previously unpublished or seldom studied, with discrete annotations of The Souls of Black Folk: Essays and Sketches of 1903, elucidating and elaborating basic epistemological terms of his thought. With theoretical attention to how the African American stands as an example of possibility for Du Bois and renders problematic traditional ontological thought, Chandler also proposes that Du Bois's most well-known phrase—“the problem of the color line”—sustains more conceptual depth than has yet been understood, with pertinence for our accounts of modern systems of enslavement and imperial colonialism and the incipient moments of modern capitalization. Chandler's work exemplifies a more profound engagement with Du Bois, demonstrating that he must be re-read, appreciated, and studied anew as a philosophical writer and thinker contemporary to our time.",
"libraryCatalog": "Duke University Press Books",
"numPages": "328",
"place": "Durham, NC",
"publisher": "Duke University Press",
"shortTitle": "\"Beyond This Narrow Now\"",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

347
E-periodica Switzerland.js Normal file
View File

@ -0,0 +1,347 @@
{
"translatorID": "dbfd99e3-6925-4b71-92b8-12b02aa875fc",
"label": "E-periodica Switzerland",
"creator": "Alain Borel",
"target": "^https?://(www|news?)\\.e-periodica\\.ch",
"minVersion": "5.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2023-08-15 20:15:50"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2023 Alain Borel
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
function detectWeb(doc, url) {
if (url.includes('/digbib/view')) {
return "journalArticle";
}
else if (getSearchResults(doc, true)) {
return "multiple";
}
else {
return false;
}
}
function getSearchResults(doc, checkOnly) {
var items = {};
// Zotero.debug(items);
var found = false;
var rows = doc.querySelectorAll('h2.ep-result__title > a');
for (let row of rows) {
//Zotero.debug(row.textContent);
let href = row.href;
//Zotero.debug(href);
let title = ZU.trimInternal(row.textContent);
if (!href || !title) continue;
if (checkOnly) return true;
found = true;
items[href] = title;
// Zotero.debug(items[href]);
}
return found ? items : false;
}
async function doWeb(doc, url) {
if (detectWeb(doc, url) == 'multiple') {
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (!items) return;
for (let resultUrl of Object.keys(items)) {
await scrape(resultUrl);
}
}
else {
// The journalArticle type will be applicable in general unless we find multiple refs.
await scrape(url);
}
}
async function scrape(url) {
// In general the article ID is given the pid parameter in the URL
// If the URL ends with a hash/fragment identifier,
// the final digits of the pid parameter (after a double colon) must be replaced with the hash ID
// e.g. alp-001:1907:2::332#375 => alp-001:1907:2::375
let articleURL = new URL(url);
let articleID = articleURL.searchParams.get("pid");
let articleViewFragment = articleURL.hash.replace(/^#/, ""); // trim leading #
if (/\d+/.test(articleViewFragment)) {
// Normalize article ID by replacing the last segment with the real
// page id if any
articleID = articleID.replace(/::\d+$/, "::" + articleViewFragment);
}
let pageinfoUrl = "https://www.e-periodica.ch/digbib/ajax/pageinfo?pid=" + encodeURIComponent(articleID);
//Zotero.debug('JSON URL ' + pageinfoUrl);
let epJSON = await requestJSON(pageinfoUrl);
//Zotero.debug(epJSON);
let risURL;
if (epJSON.articles.length == 0) {
// Fallback for non-article content, listed as Werbung, Sonstiges and various others:
// this information is unfortunately not included in the JSON metadata => let's add a reasonable pseudo-title
epJSON.articles = [{ title: "Untitled" }];
}
if (epJSON.articles["0"].hasRisLink) {
risURL = '/view/' + epJSON.articles["0"].risLink;
}
// Zotero.debug(risURL);
var pdfURL = null;
if (epJSON.articles["0"].hasPdfLink) {
pdfURL = epJSON.articles["0"].pdfLink;
}
// Zotero.debug(pdfURL);
if (risURL) {
let risText = await requestText(risURL);
processRIS(risText, pdfURL);
}
else {
var item = new Zotero.Item("journalArticle");
item.title = epJSON.articles["0"].title.replace(' : ', ': ');
item.publicationTitle = epJSON.journalTitle.replace(' : ', ': ');
var numyear = epJSON.volumeNumYear.split(/[ ()]/).filter(element => element);
if (numyear.length > 1) {
item.date = numyear.slice(-1);
}
if (numyear.length > 0) {
item.volume = numyear[0];
}
if (epJSON.issueNumber) {
item.issue = epJSON.issueNumber;
}
if (epJSON.viewerLink.length > 0) {
if (epJSON.viewerLink.indexOf("http") == 0) {
item.url = epJSON.viewerLink;
}
else {
item.url = "https://www.e-periodica.ch" + epJSON.viewerLink;
}
}
if (epJSON.pdfLink) {
if (epJSON.pdfLink.indexOf("http") == 0) {
pdfURL = epJSON.pdfLink;
}
else {
pdfURL = "https://www.e-periodica.ch" + epJSON.pdfLink;
}
}
if (pdfURL) {
item.attachments.push({
url: pdfURL,
title: "Full Text PDF",
type: "application/pdf"
});
}
item.complete();
}
}
function processRIS(risText, pdfURL) {
// load translator for RIS
var translator = Zotero.loadTranslator("import");
translator.setTranslator("32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7");
// Z.debug(text);
translator.setString(risText);
translator.setHandler("itemDone", function (obj, item) {
// Don't save HTML snapshot from 'UR' tag
item.attachments = [];
// change colon spacing in title and publicationTitle
item.title = item.title.replace(' : ', ': ');
if (item.publicationTitle) {
item.publicationTitle = item.publicationTitle.replace(' : ', ': ');
}
if (item.title == item.title.toUpperCase()) {
item.title = ZU.capitalizeTitle(item.title.toLowerCase(), true);
}
// Retrieve fulltext
if (pdfURL !== null) {
item.attachments.push({
url: pdfURL,
title: "Full Text PDF",
type: "application/pdf"
});
}
// DB in RIS maps to archive; we don't want that
delete item.archive;
item.complete();
});
translator.getTranslatorObject(function (trans) {
trans.doImport();
});
}/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "https://www.e-periodica.ch/digbib/view?pid=enh-006%3A2018%3A11::121#133",
"detectedItemType": "journalArticle",
"items": [
{
"itemType": "journalArticle",
"title": "Untersuchungen zur aktuellen Verbreitung der schweizerischen Laufkäfer (Coleoptera: Carabidae): Zwischenbilanz",
"creators": [
{
"lastName": "Hoess",
"firstName": "René",
"creatorType": "author"
},
{
"lastName": "Chittaro",
"firstName": "Yannick",
"creatorType": "author"
},
{
"lastName": "Walter",
"firstName": "Thomas",
"creatorType": "author"
}
],
"date": "2018",
"DOI": "10.5169/seals-986030",
"ISSN": "1662-8500",
"libraryCatalog": "E-periodica Switzerland",
"pages": "129",
"publicationTitle": "Entomo Helvetica: entomologische Zeitschrift der Schweiz",
"shortTitle": "Untersuchungen zur aktuellen Verbreitung der schweizerischen Laufkäfer (Coleoptera",
"volume": "11",
"attachments": [
{
"title": "Full Text PDF",
"type": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.e-periodica.ch/digbib/view?pid=bts-004%3A2011%3A137%3A%3A254&referrer=search#251",
"detectedItemType": "journalArticle",
"items": [
{
"itemType": "journalArticle",
"title": "Décentralisation, opportunités et contraintes",
"creators": [
{
"lastName": "Fignolé",
"firstName": "Jean-Claude",
"creatorType": "author"
}
],
"date": "2011",
"DOI": "10.5169/seals-144646",
"ISSN": "0251-0979",
"issue": "05-06",
"libraryCatalog": "E-periodica Switzerland",
"pages": "14",
"publicationTitle": "Tracés: bulletin technique de la Suisse romande",
"volume": "137",
"attachments": [
{
"title": "Full Text PDF",
"type": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.e-periodica.ch/digbib/view?pid=alp-001%3A1907%3A2%3A%3A332#375",
"detectedItemType": "journalArticle",
"items": [
{
"itemType": "journalArticle",
"title": "Stimmen und Meinungen: schweizerisches Nationaldrama?",
"creators": [
{
"lastName": "Falke",
"firstName": "Konrad",
"creatorType": "author"
}
],
"date": "1907-1908",
"DOI": "10.5169/seals-747870",
"issue": "12",
"libraryCatalog": "E-periodica Switzerland",
"pages": "364",
"publicationTitle": "Berner Rundschau: Halbmonatsschrift für Dichtung, Theater, Musik und bildende Kunst in der Schweiz",
"shortTitle": "Stimmen und Meinungen",
"volume": "2",
"attachments": [
{
"title": "Full Text PDF",
"type": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.e-periodica.ch/digbib/view?pid=bts-004%3A2011%3A137%3A%3A262#262",
"detectedItemType": "journalArticle",
"items": [
{
"itemType": "journalArticle",
"title": "Untitled",
"creators": [],
"date": "2011",
"issue": "05-06",
"libraryCatalog": "E-periodica Switzerland",
"publicationTitle": "Tracés: bulletin technique de la Suisse romande",
"url": "https://www.e-periodica.ch/digbib/view?pid=bts-004%3A2011%3A137%3A%3A262",
"volume": "137",
"attachments": [
{
"title": "Full Text PDF",
"type": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

View File

@ -2,14 +2,14 @@
"translatorID": "660fcf3e-3414-41b8-97a5-e672fc2e491d",
"label": "EBSCO Discovery Layer",
"creator": "Sebastian Karcher",
"target": "^https?://discovery\\.ebsco\\.com/",
"target": "^https?://(discovery|research)\\.ebsco\\.com/",
"minVersion": "5.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2023-02-12 03:36:07"
"lastUpdated": "2024-02-04 04:24:48"
}
/*
@ -35,14 +35,14 @@
***** END LICENSE BLOCK *****
*/
const itemRegex = /\/c\/([^/]+)\/(?:details|viewer\/pdf)\/([^?]+)/;
const itemRegex = /\/c\/([^/]+)(?:\/search)?\/(?:details|viewer\/pdf)\/([^?]+)/;
function detectWeb(doc, url) {
if (itemRegex.test(url)) {
if (url.includes("/viewer/pdf")) {
return "journalArticle";
}
Z.monitorDOMChanges(doc.querySelector('#page-container'));
let type = text(doc, 'div.article-type');
let type = text(doc, 'div[class*="article-type"]');
if (type) {
return getType(type);
}
@ -60,7 +60,9 @@ function detectWeb(doc, url) {
function getType(type) {
// This can probably be fine-tuned, but it'll work for 90% of results
if (type.toLowerCase().includes("article")) {
type = type.toLowerCase();
// Z.debug(type)
if (type.includes("article") || type.includes("artikel")) {
return "journalArticle";
}
else {
@ -73,6 +75,9 @@ function getSearchResults(doc, checkOnly) {
var found = false;
var rows = doc.querySelectorAll('h2.result-item-title > a');
if (!rows.length) {
rows = doc.querySelectorAll('div[class*="result-item-title"]>a');
}
for (let row of rows) {
let href = row.href;
let title = ZU.trimInternal(row.textContent);
@ -138,6 +143,5 @@ async function scrape(doc, url = doc.location.href) {
}
/** BEGIN TEST CASES **/
var testCases = [
]
/** END TEST CASES **/

View File

@ -8,8 +8,8 @@
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsib",
"lastUpdated": "2021-10-11 01:07:25"
"browserSupport": "gcsibv",
"lastUpdated": "2024-04-15 01:50:53"
}
/*
@ -56,7 +56,7 @@ function detectWeb(doc, url) {
* given the text of the delivery page, downloads an item
*/
function downloadFunction(text, url, prefs) {
if (text.search(/^TY\s\s?-/m) == -1) {
if (!(/^TY\s\s?-/m.test(text))) {
text = "\nTY - JOUR\n" + text; // this is probably not going to work if there is garbage text in the begining
}
@ -87,12 +87,14 @@ function downloadFunction(text, url, prefs) {
let subtitle;
// EBSCOhost uses nonstandard tags to represent journal titles on some items
// Sometimes T2 also just duplicates the journal title across along with JO/JF/J1
// no /g flag so we don't create duplicate tags
let journalRe = /^(JO|JF|J1)/m;
if (journalRe.test(text)) {
let journalTitleRe = /^(?:JO|JF|J1)\s\s?-\s?(.*)/m;
if (journalTitleRe.test(text)) {
let subtitleRe = /^T2\s\s?-\s?(.*)/m;
let subtitleMatch = text.match(subtitleRe);
if (subtitleMatch) {
if (subtitleMatch && subtitleMatch[1] != text.match(journalTitleRe)[1]) {
// if there's already something in T2, store it and erase it from the RIS
subtitle = subtitleMatch[1];
text = text.replace(subtitleRe, '');
@ -100,7 +102,7 @@ function downloadFunction(text, url, prefs) {
text = text.replace(journalRe, 'T2');
}
// Let's try to keep season info
// Y1 - 1993///Winter93
// Y1 - 2009///Spring2009
@ -115,7 +117,7 @@ function downloadFunction(text, url, prefs) {
translator.setString(text);
// eslint-disable-next-line padded-blocks
translator.setHandler("itemDone", function (obj, item) {
/* Fix capitalization issues */
// title
if (!item.title && prefs.itemTitle) {
@ -204,7 +206,8 @@ function downloadFunction(text, url, prefs) {
item.attachments.push({
url: prefs.pdfURL,
title: "EBSCO Full Text",
mimeType: "application/pdf"
mimeType: "application/pdf",
proxy: false
});
item.complete();
}
@ -401,6 +404,8 @@ function findPdfUrl(pdfDoc) {
/**
* borrowed from http://www.webtoolkit.info/javascript-base64.html
*/
// We should have this available now - leaving in the code just in case
/*
var base64KeyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
function utf8Encode(string) {
@ -450,7 +455,7 @@ function btoa(input) {
+ base64KeyStr.charAt(enc3) + base64KeyStr.charAt(enc4);
}
return output;
}
} */
/**
* end borrowed code

37
ERIC.js
View File

@ -9,7 +9,7 @@
"inRepository": true,
"translatorType": 12,
"browserSupport": "gcsibv",
"lastUpdated": "2022-11-09 21:08:42"
"lastUpdated": "2024-07-05 11:56:39"
}
/*
@ -89,11 +89,9 @@ function getSearchResults(doc, checkOnly) {
async function doWeb(doc, url) {
if (detectWeb(doc, url) == 'multiple') {
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (items) {
await Promise.all(
Object.keys(items)
.map(url => requestDocument(url).then(scrape))
);
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(await requestDocument(url));
}
}
else {
@ -133,8 +131,14 @@ async function scrape(doc, url = doc.location.href) {
if (DOI) {
item.DOI = ZU.cleanDOI(decodeURIComponent(DOI));
}
if (item.itemType == "journalArticle" && item.publisher == item.publicationTitle) {
delete item.publisher; // Publisher & Publication Title are often identical
if (item.publisher == item.publicationTitle) {
// Publisher & Publication Title are often identical
if (item.itemType == "journalArticle") {
delete item.publisher;
}
else if (item.itemType == "report") {
delete item.publicationTitle;
}
}
item.extra = "ERIC Number: " + ericID;
@ -224,7 +228,6 @@ async function doSearch(search) {
item.complete();
}
/** BEGIN TEST CASES **/
var testCases = [
{
@ -445,10 +448,6 @@ var testCases = [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
},
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [
@ -525,10 +524,6 @@ var testCases = [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
},
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [
@ -835,7 +830,13 @@ var testCases = [
"extra": "ERIC Number: ED616685",
"language": "English",
"libraryCatalog": "ERIC",
"attachments": [],
"url": "https://eric.ed.gov/?id=ED616685",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [
{
"tag": "Cognitive Processes"

View File

@ -2,20 +2,20 @@
"translatorID": "bf053edc-a8c3-458c-93db-6d04ead2e636",
"label": "EUR-Lex",
"creator": "Philipp Zumstein, Pieter van der Wees",
"target": "^https?://(www\\.)?eur-lex\\.europa\\.eu/(legal-content/[A-Z][A-Z]/(TXT|ALL)/|search\\.html\\?)",
"target": "^https://eur-lex\\.europa\\.eu/",
"minVersion": "3.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2021-12-31 02:00:49"
"lastUpdated": "2025-10-30 15:50:58"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2017-2021 Philipp Zumstein, Pieter van der Wees
Copyright © 2025 Abe Jellinek
This file is part of Zotero.
@ -161,19 +161,14 @@ function scrape(doc, url) {
var type = detectWeb(doc, url);
var item = new Zotero.Item(type);
// determine the language in which we are currently viewing the document
var languageUrl = url.split("/")[4].toUpperCase();
if (languageUrl == "AUTO") {
languageUrl = autoLanguage || "EN";
}
var language = languageMapping[languageUrl].iso || "eng";
var viewingLanguage = (doc.documentElement.lang || "en").toUpperCase();
// Cases only return language; discard everything else
item.language = languageUrl.toLowerCase();
item.language = viewingLanguage.toLowerCase();
if (eliTypeUri) {
// type: everything with ELI (see var typeMapping: bill, statute, report)
item.title = attr(doc, 'meta[property="eli:title"][lang=' + languageUrl.toLowerCase() + "]", "content");
var uri = attr(doc, "#format_language_table_digital_sign_act_" + languageUrl.toUpperCase(), "href");
item.title = attr(doc, 'meta[property="eli:title"][lang=' + viewingLanguage.toLowerCase() + "]", "content");
var uri = attr(doc, "#format_language_table_digital_sign_act_" + viewingLanguage.toUpperCase(), "href");
if (uri) {
var uriParts = uri.split("/").pop().replace("?uri=", "")
.split(":");
@ -207,7 +202,7 @@ function scrape(doc, url) {
}
item.legislativeBody = passedByArray.join(", ");
item.url = attr(doc, 'meta[typeOf="eli:LegalResource"]', "about") + "/" + language.toLowerCase();
item.url = attr(doc, 'meta[typeOf="eli:LegalResource"]', "about");
}
else if (item.itemType == "case") {
@ -215,13 +210,13 @@ function scrape(doc, url) {
// pretty hacky stuff, as there's little metadata available
var docCourt = docType.substr(0, 1);
if (docCourt == "C") {
item.court = languageMapping[languageUrl].ECJ || languageMapping.EN.ECJ;
item.court = languageMapping[viewingLanguage].ECJ || languageMapping.EN.ECJ;
}
else if (docCourt == "T") {
item.court = languageMapping[languageUrl].GC || languageMapping.EN.GC;
item.court = languageMapping[viewingLanguage].GC || languageMapping.EN.GC;
}
else if (docCourt == "F") {
item.court = languageMapping[languageUrl].CST || languageMapping.EN.CST;
item.court = languageMapping[viewingLanguage].CST || languageMapping.EN.CST;
}
item.url = url;
@ -253,10 +248,10 @@ function scrape(doc, url) {
}
// attachments
// type: all
var pdfurl = "https://eur-lex.europa.eu/legal-content/" + languageUrl + "/TXT/PDF/?uri=CELEX:" + celex;
var htmlurl = "https://eur-lex.europa.eu/legal-content/" + languageUrl + "/TXT/HTML/?uri=CELEX:" + celex;
item.attachments = [{ url: pdfurl, title: "EUR-Lex PDF (" + languageUrl + ")", mimeType: "application/pdf" }];
item.attachments.push({ url: htmlurl, title: "EUR-Lex HTML (" + languageUrl + ")", mimeType: "text/html", snapshot: true });
var pdfurl = "https://eur-lex.europa.eu/legal-content/" + viewingLanguage + "/TXT/PDF/?uri=CELEX:" + celex;
var htmlurl = "https://eur-lex.europa.eu/legal-content/" + viewingLanguage + "/TXT/HTML/?uri=CELEX:" + celex;
item.attachments = [{ url: pdfurl, title: "EUR-Lex PDF (" + viewingLanguage + ")", mimeType: "application/pdf" }];
item.attachments.push({ url: htmlurl, title: "EUR-Lex HTML (" + viewingLanguage + ")", mimeType: "text/html", snapshot: true });
item.complete();
}
@ -276,7 +271,7 @@ var testCases = [
"codeVolume": "281",
"language": "en",
"legislativeBody": "EP, CONSIL",
"url": "http://data.europa.eu/eli/dir/1995/46/oj/eng",
"url": "http://data.europa.eu/eli/dir/1995/46/oj",
"attachments": [
{
"title": "EUR-Lex PDF (EN)",
@ -300,20 +295,20 @@ var testCases = [
"items": [
{
"itemType": "statute",
"nameOfAct": "Règlement (CE) n° 2257/94 de la Commission, du 16 septembre 1994, fixant des normes de qualité pour les bananes (Texte présentant de l'intérêt pour l'EEE)",
"nameOfAct": "Commission Regulation (EC) No 2257/94 of 16 September 1994 laying down quality standards for bananas (Text with EEA relevance)",
"creators": [],
"dateEnacted": "1994-09-16",
"code": "OJ L",
"codeNumber": "245",
"language": "fr",
"url": "http://data.europa.eu/eli/reg/1994/2257/oj/fra",
"language": "en",
"url": "http://data.europa.eu/eli/reg/1994/2257/oj",
"attachments": [
{
"title": "EUR-Lex PDF (FR)",
"title": "EUR-Lex PDF (EN)",
"mimeType": "application/pdf"
},
{
"title": "EUR-Lex HTML (FR)",
"title": "EUR-Lex HTML (EN)",
"mimeType": "text/html",
"snapshot": true
}
@ -369,15 +364,15 @@ var testCases = [
"title": "Bez námitek k navrhovanému spojení (Věc M.10068 — Brookfield/Mansa/Polenergia) (Text s významem pro EHP) 2021/C 14/01",
"creators": [],
"date": "2021",
"language": "cs",
"language": "nl",
"url": "https://eur-lex.europa.eu/legal-content/CS/TXT/?uri=uriserv%3AOJ.C_.2021.014.01.0001.01.CES&toc=OJ%3AC%3A2021%3A014%3ATOC",
"attachments": [
{
"title": "EUR-Lex PDF (CS)",
"title": "EUR-Lex PDF (NL)",
"mimeType": "application/pdf"
},
{
"title": "EUR-Lex HTML (CS)",
"title": "EUR-Lex HTML (NL)",
"mimeType": "text/html",
"snapshot": true
}
@ -398,17 +393,17 @@ var testCases = [
"creators": [],
"dateDecided": "21 ta' Settembru 2011",
"abstractNote": "Trade mark Komunitarja - Proċedimenti għal dikjarazzjoni ta invalidità - Trade mark Komunitarja verbali SCOMBER MIX - Raġuni assoluta għal rifjut - Karattru deskrittiv - Artikolu 7(1)(b) u (ċ) tar-Regolament (KE) Nru 40/94 [li sar l-Artikolu 7(1)(b) u (c) tar-Regolament (KE) Nru 207/2009]",
"court": "Il-Qorti Ġenerali",
"court": "Gerecht EU",
"docketNumber": "Kawża T-201/09",
"language": "mt",
"language": "nl",
"url": "https://eur-lex.europa.eu/legal-content/MT/TXT/?uri=CELEX%3A62009TJ0201",
"attachments": [
{
"title": "EUR-Lex PDF (MT)",
"title": "EUR-Lex PDF (NL)",
"mimeType": "application/pdf"
},
{
"title": "EUR-Lex HTML (MT)",
"title": "EUR-Lex HTML (NL)",
"mimeType": "text/html",
"snapshot": true
}

View File

@ -1,116 +1,120 @@
{
"translatorID": "09a9599e-c20e-a405-d10d-35ad4130a426",
"label": "Electronic Colloquium on Computational Complexity",
"creator": "Jonas Schrieb",
"target": "^https?://eccc\\.weizmann\\.ac\\.il/",
"creator": "Jonas Schrieb and Morgan Shirley",
"target": "^https?://eccc\\.weizmann\\.ac\\.il/(title|year|keyword|report|search)",
"minVersion": "1.0.0b3.r1",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsib",
"lastUpdated": "2017-01-05 17:11:41"
"browserSupport": "gcsibv",
"lastUpdated": "2023-08-14 06:03:23"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2023 Jonas Schrieb and Morgan Shirley
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
const preprintType = ZU.fieldIsValidForType('title', 'preprint')
? 'preprint'
: 'report';
function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
var rows = doc.querySelectorAll('a[href^="/report/"]');
for (let row of rows) {
let href = row.href;
let title = text(row, "h4");
if (!href || !title) continue;
if (checkOnly) return true;
found = true;
items[href] = title;
}
return found ? items : false;
}
function detectWeb(doc, url) {
var singleRe = /^https?:\/\/eccc\.weizmann\.ac\.il\/report\/\d{4}\/\d{3}/;
var multipleRe = /^https?:\/\/eccc\.weizmann\.ac\.il\/(title|year|keyword)\//;
if (singleRe.test(url)) {
return "report";
} else if (multipleRe.test(url)) {
return "multiple";
var multipleRe = /^https?:\/\/eccc\.weizmann\.ac\.il\/(title|year|keyword|search)\//;
var singleRe = /^https?:\/\/eccc\.weizmann\.ac\.il\/report\//;
if (multipleRe.test(url)) {
return getSearchResults(doc, true) && "multiple";
}
else if (singleRe.test(url)) {
return preprintType;
}
else return false;
}
function scrape(doc) {
var newItem = new Zotero.Item("report");
var url = doc.location.href;
var tmp = url.match(/\/(\d{4})\/(\d{3})\/$/);
newItem.date = tmp[1];
newItem.reportNumber = tmp[2];
newItem.url = url;
async function scrape(doc, url = doc.location.href) {
let translator = Zotero.loadTranslator('web');
// Embedded Metadata
translator.setTranslator('951c027d-74ac-47d4-a107-9c3069ab7b48');
translator.setDocument(doc);
translator.setHandler('itemDone', (_obj, item) => {
item.publisher = "Electronic Colloquium on Computational Complexity";
var titleXPath = "id('box')//h4";
newItem.title = doc.evaluate(titleXPath, doc, null, XPathResult.ANY_TYPE, null).iterateNext().textContent;
var authorsXPath = "id('box')//a[contains(@href,'author')]";
var authors = doc.evaluate(authorsXPath, doc, null, XPathResult.ANY_TYPE, null);
var nextAuthor;
while (nextAuthor = authors.iterateNext()) {
newItem.creators.push(Zotero.Utilities.cleanAuthor(nextAuthor.textContent, "author"));
}
var keywordsXPath = "id('box')//a[contains(@href,'keyword')]";
var keywords = doc.evaluate(keywordsXPath, doc, null, XPathResult.ANY_TYPE, null);
var nextKeyword;
var i = 0;
while (nextKeyword = keywords.iterateNext()) {
newItem.tags[i++] = nextKeyword.textContent;
}
var abstractXPath = "id('box')/text()";
var abstractLines = doc.evaluate(abstractXPath, doc, null, XPathResult.ANY_TYPE, null);
newItem.abstractNote = "";
var nextLine;
while (nextLine = abstractLines.iterateNext()) {
newItem.abstractNote += nextLine.textContent;
}
newItem.attachments = [
{url:url, title:"ECCC Snapshot", mimeType:"text/html"},
{url:url+"download", title:"ECCC Full Text PDF", mimeType:"application/pdf"}
];
newItem.complete();
}
function doWeb(doc, url) {
var articles = new Array();
var items = new Object();
var nextTitle;
if (detectWeb(doc, url) == "multiple") {
var titleXPath = "//a[starts-with(@href,'/report/')]/h4";
var linkXPath = "//a[starts-with(@href,'/report/')][h4]";
var titles = doc.evaluate(titleXPath, doc, null, XPathResult.ANY_TYPE, null);
var links = doc.evaluate(linkXPath, doc, null, XPathResult.ANY_TYPE, null);
while (nextTitle = titles.iterateNext()) {
nextLink = links.iterateNext();
items[nextLink.href] = nextTitle.textContent;
// Keywords and abstract are not in the metadata; scrape from webpage
var keywords = doc.querySelectorAll("#box a[href^='/keyword/']");
for (let i = 0; i < keywords.length; i++) {
item.tags[i] = keywords[i].textContent;
}
Zotero.selectItems(items, function (items) {
if (!items) {
Zotero.done();
}
for (var i in items) {
articles.push(i);
}
ZU.processDocuments(articles, scrape);
});
} else {
scrape(doc, url)
}
var abstractParagraphs = doc.querySelectorAll("#box p");
item.abstractNote = "";
for (let i = 0; i < abstractParagraphs.length; i++) {
item.abstractNote += abstractParagraphs[i].innerText + "\n";
}
item.complete();
});
let em = await translator.getTranslatorObject();
em.itemType = preprintType;
await em.doWeb(doc, url);
}
/** BEGIN TEST CASES **/
async function doWeb(doc, url) {
if (detectWeb(doc, url) == 'multiple') {
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(await requestDocument(url));
}
}
else {
await scrape(doc, url);
}
}/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "https://eccc.weizmann.ac.il/report/2006/067/",
"detectedItemType": "preprint",
"items": [
{
"itemType": "report",
"itemType": "preprint",
"title": "On the Impact of Combinatorial Structure on Congestion Games",
"creators": [
{
"firstName": "Heiner",
@ -128,39 +132,98 @@ var testCases = [
"creatorType": "author"
}
],
"notes": [],
"tags": [
"Combinatorial Structure",
"Congestion Games",
"Convergence Time",
"PLS-Completeness"
],
"seeAlso": [],
"date": "2006/5/28",
"abstractNote": "We study the impact of combinatorial structure in congestion games on the complexity of computing pure Nash equilibria and the convergence time of best response sequences. In particular, we investigate which properties of the strategy spaces of individual players ensure a polynomial convergence time. We show, if the strategy space of each player consists of the bases of a matroid over the set of resources, then the lengths of all best response sequences are polynomially bounded in the number of players and resources. We can also prove that this result is tight, that is, the matroid property is a necessary and sufficient condition on the players' strategy spaces for guaranteeing polynomial time convergence to a Nash equilibrium. In addition, we present an approach that enables us to devise hardness proofs for various kinds of combinatorial games, including first results about the hardness of market sharing games and congestion games for overlay network design. Our approach also yields a short proof for the PLS-completeness of network congestion games.",
"archiveID": "TR06-067",
"language": "en",
"libraryCatalog": "eccc.weizmann.ac.il",
"repository": "Electronic Colloquium on Computational Complexity",
"url": "https://eccc.weizmann.ac.il/report/2006/067/",
"attachments": [
{
"url": "https://eccc.weizmann.ac.il/report/2006/067/",
"title": "ECCC Snapshot",
"mimeType": "text/html"
},
{
"url": "https://eccc.weizmann.ac.il/report/2006/067/download",
"title": "ECCC Full Text PDF",
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"date": "2006",
"reportNumber": "067",
"url": "https://eccc.weizmann.ac.il/report/2006/067/",
"title": "On the Impact of Combinatorial Structure on Congestion Games",
"abstractNote": "",
"libraryCatalog": "Electronic Colloquium on Computational Complexity",
"accessDate": "CURRENT_TIMESTAMP"
"tags": [
{
"tag": "Combinatorial Structure"
},
{
"tag": "Congestion Games"
},
{
"tag": "Convergence Time"
},
{
"tag": "PLS-Completeness"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://eccc.weizmann.ac.il/keyword/13486/",
"url": "https://eccc.weizmann.ac.il/report/2007/112/",
"detectedItemType": "preprint",
"items": [
{
"itemType": "preprint",
"title": "Unbounded-Error Communication Complexity of Symmetric Functions",
"creators": [
{
"firstName": "Alexander A.",
"lastName": "Sherstov",
"creatorType": "author"
}
],
"date": "2007/11/12",
"abstractNote": "The sign-rank of a real matrix M is the least rank\nof a matrix R in which every entry has the same sign as the\ncorresponding entry of M. We determine the sign-rank of every\nmatrix of the form M=[ D(|x AND y|) ]_{x,y}, where\nD:{0,1,...,n}->{-1,+1} is given and x and y range over {0,1}^n.\nSpecifically, we prove that the sign-rank of M equals\n2^{\\tilde Theta(k)}, where k is the number of times D changes\nsign in {0,1,...,n}.\nPut differently, we prove an optimal lower bound\non the unbounded-error communication complexity of every\nsymmetric function, i.e., a function of the form\nf(x,y)=D(|x AND y|) for some D. The unbounded-error model is\nessentially the most powerful of all models of communication\n(both classical and quantum), and proving lower bounds in it\nis a substantial challenge. The only previous nontrivial lower\nbounds for this model appear in the groundbreaking work of\nForster (2001) and its extensions. As corollaries to our\nresult, we give new lower bounds for PAC learning and for\nthreshold-of-majority circuits.\nThe technical content of our proof is diverse and\nfeatures random walks on (Z_2)^n, discrete approximation theory,\nthe Fourier transform on (Z_2)^n, linear-programming duality,\nand matrix analysis.",
"archiveID": "TR07-112",
"language": "en",
"libraryCatalog": "eccc.weizmann.ac.il",
"repository": "Electronic Colloquium on Computational Complexity",
"url": "https://eccc.weizmann.ac.il/report/2007/112/",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [
{
"tag": "Communication complexity"
},
{
"tag": "Sign-rank"
},
{
"tag": "Unbounded-error communication complexity"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://eccc.weizmann.ac.il/search/?search=combinatorial",
"detectedItemType": "multiple",
"items": "multiple"
},
{
"type": "web",
"url": "https://eccc.weizmann.ac.il/search/?search=asdf",
"detectedItemType": false,
"items": []
},
{
"type": "web",
"url": "https://eccc.weizmann.ac.il/keyword/14114/",
"detectedItemType": "multiple",
"items": "multiple"
}
]

View File

@ -9,7 +9,7 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2023-04-24 14:42:56"
"lastUpdated": "2025-10-14 17:29:56"
}
/*
@ -179,7 +179,9 @@ function getContentText(doc, name, strict, all) {
}
function getContent(doc, name, strict) {
var xpath = '/x:html/x:head/x:meta['
var xpath = '/x:html'
+ '/*[local-name() = "head" or local-name() = "body"]'
+ '/x:meta['
+ (strict ? '@name' : 'substring(@name, string-length(@name)-' + (name.length - 1) + ')')
+ '="' + name + '"]/';
return ZU.xpath(doc, xpath + '@content | ' + xpath + '@contents', namespaces);
@ -234,25 +236,15 @@ function detectWeb(doc, url) {
function init(doc, url, callback, forceLoadRDF) {
getPrefixes(doc);
var metaTags = doc.head.getElementsByTagName("meta");
Z.debug("Embedded Metadata: found " + metaTags.length + " meta tags.");
var metaTags = doc.querySelectorAll("meta");
Z.debug("Embedded Metadata: found " + metaTags.length + " meta tags");
if (forceLoadRDF /* check if this is called from doWeb */ && !metaTags.length) {
if (doc.head) {
Z.debug(doc.head.innerHTML
.replace(/<style[^<]+(?:<\/style>|\/>)/ig, '')
.replace(/<link[^>]+>/ig, '')
.replace(/(?:\s*[\r\n]\s*)+/g, '\n')
);
}
else {
Z.debug("Embedded Metadata: No head tag");
}
Z.debug("Embedded Metadata: No meta tags found");
}
var hwType, hwTypeGuess, generatorType, statements = [];
var hwType, hwTypeGuess, generatorType, heuristicType, statements = [];
for (let i = 0; i < metaTags.length; i++) {
let metaTag = metaTags[i];
for (let metaTag of metaTags) {
// Two formats allowed:
// <meta name="..." content="..." />
// <meta property="..." content="..." />
@ -334,6 +326,11 @@ function init(doc, url, callback, forceLoadRDF) {
}
}
// WordPress indicators:
if (doc.getElementById("wp-block-library-css") || doc.getElementsByClassName("yoast-schema-graph").length) {
heuristicType = "blogPost";
}
if (statements.length || forceLoadRDF) {
// load RDF translator, so that we don't need to replicate import code
var translator = Zotero.loadTranslator("import");
@ -350,7 +347,7 @@ function init(doc, url, callback, forceLoadRDF) {
rdf.Zotero.RDF.addStatement(statement[0], statement[1], statement[2], true);
}
var nodes = rdf.getNodes(true);
rdf.defaultUnknownType = hwTypeGuess || generatorType
rdf.defaultUnknownType = hwTypeGuess || generatorType || heuristicType
// if we have RDF data, then default to webpage
|| (nodes.length ? "webpage" : false);
@ -581,16 +578,24 @@ function processHighwireCreators(creatorNodes, role, doc) {
/* If there is only one author node and
we get nothing when splitting by semicolon, there are at least two
words on either side of a comma, and it doesn't appear to be a
two-word Spanish surname, we split by comma. */
Spanish surname, we split by comma. */
let lang = getContentText(doc, 'citation_language');
let twoWordName = authorsByComma.length == 2
let spanishName = authorsByComma.length == 2
&& ['es', 'spa', 'Spanish', 'español'].includes(lang)
&& authorsByComma[0].split(' ').length == 2;
&& (
// If it's a Spanish-language item and the text before the comma
// has exactly two words, this is very probably a single Spanish name
authorsByComma[0].split(' ').length == 2
// If the text before the comma has more than two words, we can't be
// sure, but we'll take it if there's an accented character or a
// "de" particle (this is not great)
|| authorsByComma[0].split(' ').length > 2 && /[À-ú]|\b[Dd]e\b/u.test(authorsByComma[0])
);
if (authorsByComma.length > 1
&& authorsByComma[0].includes(" ")
&& authorsByComma[1].includes(" ")
&& !twoWordName) creators = authorsByComma;
&& !spanishName) creators = authorsByComma;
}
for (let creator of creators) {
@ -683,7 +688,8 @@ function addLowQualityMetadata(doc, newItem) {
Array.from(doc.querySelectorAll('meta[name="author" i], meta[property="author" i]'))
.map(authorNode => authorNode.content)
.filter(content => content && /[^\s,-.;]/.test(content)));
if (w3authors.size) {
// Condé Nast is a company, not an author
if (w3authors.size && !(w3authors.size == 1 && w3authors.has("Condé Nast"))) {
for (let author of w3authors) {
newItem.creators.push(ZU.cleanAuthor(author, "author"));
}
@ -707,7 +713,7 @@ function addLowQualityMetadata(doc, newItem) {
}
if (!newItem.url) {
newItem.url = ZU.xpathText(doc, '//head/link[@rel="canonical"]/@href') || doc.location.href;
newItem.url = attr(doc, 'head > link[rel="canonical"]', 'href') || doc.location.href;
}
if (!newItem.language) {
@ -736,7 +742,7 @@ function tryOgAuthors(doc) {
var authors = [];
var ogAuthors = ZU.xpath(doc, '//meta[@property="article:author" or @property="video:director" or @property="music:musician"]');
for (var i = 0; i < ogAuthors.length; i++) {
if (ogAuthors[i].content && /(https?:\/\/)?[\da-z.-]+\.[a-z.]{2,6}/.test(ogAuthors[i].content) && ogAuthors[i].content !== "false") {
if (ogAuthors[i].content && !/(https?:\/\/)?[\da-z.-]+\.[a-z.]{2,6}/.test(ogAuthors[i].content) && ogAuthors[i].content !== "false") {
authors.push(ZU.cleanAuthor(ogAuthors[i].content, "author"));
}
}
@ -747,13 +753,33 @@ function getAuthorFromByline(doc, newItem) {
var bylineClasses = ['byline', 'bylines', 'vcard', 'article-byline'];
Z.debug("Looking for authors in " + bylineClasses.join(', '));
var bylines = [], byline;
for (var i = 0; i < bylineClasses.length; i++) {
byline = doc.getElementsByClassName(bylineClasses[i]);
Z.debug("Found " + byline.length + " elements with '" + bylineClasses[i] + "' class");
for (var j = 0; j < byline.length; j++) {
if (!byline[j].innerText.trim()) continue;
for (let isStrict of [true, false]) {
for (let bylineClass of bylineClasses) {
byline = isStrict
? doc.getElementsByClassName(bylineClass)
: doc.querySelectorAll(`[class*="${bylineClass}" i]`);
Z.debug(`Found ${byline.length} elements with '${bylineClass}' class (strict: ${isStrict})`);
for (let bylineElement of byline) {
if (!bylineElement.innerText?.trim()) continue;
if (bylines.includes(bylineElement)) continue;
bylines.push(bylineElement);
}
bylines.push(byline[j]);
if (isStrict && bylines.length) {
break;
}
}
}
if (!bylines.length) {
let otherSelectors = ['a[rel="author"]'];
for (let selector of otherSelectors) {
selector += ':not(:empty)';
if (doc.querySelectorAll(selector).length == 1) {
bylines.push(doc.querySelector(selector));
break;
}
}
}
@ -826,7 +852,9 @@ function getAuthorFromByline(doc, newItem) {
}
if (ZU.xpath(bylineParent, titleXPath).length) {
if (actualByline) {
if (actualByline
&& actualByline.textContent.trim().toLowerCase()
!== bylines[i].textContent.trim().toLowerCase()) {
// found more than one, bail
Z.debug('More than one possible byline found. Will not proceed');
return;
@ -843,11 +871,11 @@ function getAuthorFromByline(doc, newItem) {
// are any of these actual likely to appear in the real world?
// well, no, but things happen:
// https://github.com/zotero/translators/issues/2001
let irrelevantTags = 'time, button, textarea, script';
if (actualByline.querySelector(irrelevantTags)) {
let irrelevantSelector = 'time, button, textarea, script, [class*="email"], [class*="date"]';
if (actualByline.querySelector(irrelevantSelector)) {
actualByline = actualByline.cloneNode(true);
for (let child of actualByline.querySelectorAll(irrelevantTags)) {
child.parentNode.removeChild(child);
for (let child of [...actualByline.querySelectorAll(irrelevantSelector)]) {
child.remove();
}
}
@ -1057,7 +1085,7 @@ var testCases = [
"ISSN": "1821-9241",
"abstractNote": "The synergistic interaction between Human Immunodeficiency virus (HIV) disease and Malaria makes it mandatory for patients with HIV to respond appropriately in preventing and treating malaria. Such response will help to control the two diseases. This study assessed the knowledge of 495 patients attending the HIV clinic, in Lagos University Teaching Hospital, Nigeria.&nbsp; Their treatment seeking, preventive practices with regards to malaria, as well as the impact of socio &ndash; demographic / socio - economic status were assessed. Out of these patients, 245 (49.5 %) used insecticide treated bed nets; this practice was not influenced by socio &ndash; demographic or socio &ndash; economic factors.&nbsp; However, knowledge of the cause, knowledge of prevention of malaria, appropriate use of antimalarial drugs and seeking treatment from the right source increased with increasing level of education (p &lt; 0.05). A greater proportion of the patients, 321 (64.9 %) utilized hospitals, pharmacy outlets or health centres when they perceived an attack of malaria. Educational intervention may result in these patients seeking treatment from the right place when an attack of malaria fever is perceived.",
"issue": "4",
"journalAbbreviation": "1",
"journalAbbreviation": "Tanzania J Hlth Res",
"language": "en",
"libraryCatalog": "www.ajol.info",
"publicationTitle": "Tanzania Journal of Health Research",
@ -1078,168 +1106,7 @@ var testCases = [
},
{
"type": "web",
"url": "https://scholarworks.umass.edu/climate_nuclearpower/2011/nov19/34/",
"items": [
{
"itemType": "conferencePaper",
"title": "Session F: Contributed Oral Papers F2: Energy, Climate, Nuclear Medicine: Reducing Energy Consumption and CO2 One Street Lamp at a Time",
"creators": [
{
"firstName": "Peter",
"lastName": "Somssich",
"creatorType": "author"
}
],
"date": "2011",
"abstractNote": "Why wait for federal action on incentives to reduce energy use and address Greenhouse Gas (GHG) reductions (e.g. CO2), when we can take personal actions right now in our private lives and in our communities? One such initiative by private citizens working with Portsmouth NH officials resulted in the installation of energy reducing lighting products on Court St. and the benefits to taxpayers are still coming after over 4 years of operation. This citizen initiative to save money and reduce CO2 emissions, while only one small effort, could easily be duplicated in many towns and cities. Replacing old lamps in just one street fixture with a more energy efficient (Non-LED) lamp has resulted after 4 years of operation ($\\sim $15,000 hr. life of product) in real electrical energy savings of $>$ {\\$}43. and CO2 emission reduction of $>$ 465 lbs. The return on investment (ROI) was less than 2 years. This is much better than any financial investment available today and far safer. Our street only had 30 such lamps installed; however, the rest of Portsmouth (population 22,000) has at least another 150 street lamp fixtures that are candidates for such an upgrade. The talk will also address other energy reduction measures that green the planet and also put more green in the pockets of citizens and municipalities.",
"conferenceName": "Climate Change and the Future of Nuclear Power",
"language": "en",
"libraryCatalog": "scholarworks.umass.edu",
"shortTitle": "Session F",
"url": "https://scholarworks.umass.edu/climate_nuclearpower/2011/nov19/34",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://scholarworks.umass.edu/lov/vol2/iss1/2/",
"items": [
{
"itemType": "journalArticle",
"title": "Wabanaki Resistance and Healing: An Exploration of the Contemporary Role of an Eighteenth Century Bounty Proclamation in an Indigenous Decolonization Process",
"creators": [
{
"firstName": "Bonnie D.",
"lastName": "Newsom",
"creatorType": "author"
},
{
"firstName": "Jamie",
"lastName": "Bissonette-Lewey",
"creatorType": "author"
}
],
"date": "2012",
"DOI": "10.7275/R5KW5CXB",
"ISSN": "1947-508X",
"abstractNote": "The purpose of this paper is to examine the contemporary role of an eighteenth century bounty proclamation issued on the Penobscot Indians of Maine. We focus specifically on how the changing cultural context of the 1755 Spencer Phips Bounty Proclamation has transformed the document from serving as a tool for sanctioned violence to a tool of decolonization for the Indigenous peoples of Maine. We explore examples of the ways indigenous and non-indigenous people use the Phips Proclamation to illustrate past violence directed against Indigenous peoples. This exploration is enhanced with an analysis of the re-introduction of the Phips Proclamation using concepts of decolonization theory.",
"issue": "1",
"language": "en",
"libraryCatalog": "scholarworks.umass.edu",
"pages": "2",
"publicationTitle": "Landscapes of Violence",
"shortTitle": "Wabanaki Resistance and Healing",
"url": "https://scholarworks.umass.edu/lov/vol2/iss1/2",
"volume": "2",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://scholarworks.umass.edu/open_access_dissertations/508/",
"items": [
{
"itemType": "thesis",
"title": "Decision-Theoretic Meta-reasoning in Partially Observable and Decentralized Settings",
"creators": [
{
"firstName": "Alan Scott",
"lastName": "Carlin",
"creatorType": "author"
}
],
"date": "2012",
"abstractNote": "This thesis examines decentralized meta-reasoning. For a single agent or multiple agents, it may not be enough for agents to compute correct decisions if they do not do so in a timely or resource efficient fashion. The utility of agent decisions typically increases with decision quality, but decreases with computation time. The reasoning about one's computation process is referred to as meta-reasoning. Aspects of meta-reasoning considered in this thesis include the reasoning about how to allocate computational resources, including when to stop one type of computation and begin another, and when to stop all computation and report an answer. Given a computational model, this translates into computing how to schedule the basic computations that solve a problem. This thesis constructs meta-reasoning strategies for the purposes of monitoring and control in multi-agent settings, specifically settings that can be modeled by the Decentralized Partially Observable Markov Decision Process (Dec-POMDP). It uses decision theory to optimize computation for efficiency in time and space in communicative and non-communicative decentralized settings. Whereas base-level reasoning describes the optimization of actual agent behaviors, the meta-reasoning strategies produced by this thesis dynamically optimize the computational resources which lead to the selection of base-level behaviors.",
"extra": "DOI: 10.7275/n8e9-xy93",
"language": "en",
"libraryCatalog": "scholarworks.umass.edu",
"university": "University of Massachusetts Amherst",
"url": "https://scholarworks.umass.edu/open_access_dissertations/508",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://scielosp.org/article/rsp/2007.v41suppl2/94-100/en/",
"items": [
{
"itemType": "journalArticle",
"title": "Perceptions of HIV rapid testing among injecting drug users in Brazil",
"creators": [
{
"firstName": "P. R.",
"lastName": "Telles-Dias",
"creatorType": "author"
},
{
"firstName": "S.",
"lastName": "Westman",
"creatorType": "author"
},
{
"firstName": "A. E.",
"lastName": "Fernandez",
"creatorType": "author"
},
{
"firstName": "M.",
"lastName": "Sanchez",
"creatorType": "author"
}
],
"date": "2007-12",
"DOI": "10.1590/S0034-89102007000900015",
"ISSN": "0034-8910, 0034-8910, 1518-8787",
"abstractNote": "OBJETIVO: Descrever as impressões, experiências, conhecimentos, crenças e a receptividade de usuários de drogas injetáveis para participar das estratégias de testagem rápida para HIV. MÉTODOS: Estudo qualitativo exploratório foi conduzido entre usuários de drogas injetáveis, de dezembro de 2003 a fevereiro de 2004, em cinco cidades brasileiras, localizadas em quatro regiões do País. Um roteiro de entrevista semi-estruturado contendo questões fechadas e abertas foi usado para avaliar percepções desses usuários sobre procedimentos e formas alternativas de acesso e testagem. Foram realizadas 106 entrevistas, aproximadamente 26 por região. RESULTADOS: Características da população estudada, opiniões sobre o teste rápido e preferências por usar amostras de sangue ou saliva foram apresentadas junto com as vantagens e desvantagens associadas a cada opção. Os resultados mostraram a viabilidade do uso de testes rápidos entre usuários de drogas injetáveis e o interesse deles quanto à utilização destes métodos, especialmente se puderem ser equacionadas questões relacionadas à confidencialidade e confiabilidade dos testes. CONCLUSÕES: Os resultados indicam que os testes rápidos para HIV seriam bem recebidos por essa população. Esses testes podem ser considerados uma ferramenta valiosa, ao permitir que mais usuários de drogas injetáveis conheçam sua sorologia para o HIV e possam ser referidos para tratamento, como subsidiar a melhoria das estratégias de testagem entre usuários de drogas injetáveis.",
"journalAbbreviation": "Rev. Saúde Pública",
"language": "en",
"libraryCatalog": "scielosp.org",
"pages": "94-100",
"publicationTitle": "Revista de Saúde Pública",
"url": "https://scielosp.org/article/rsp/2007.v41suppl2/94-100/en/",
"volume": "41",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.hindawi.com/journals/mpe/2013/868174/",
"url": "https://onlinelibrary.wiley.com/doi/10.1155/2013/868174",
"items": [
{
"itemType": "journalArticle",
@ -1261,14 +1128,16 @@ var testCases = [
"creatorType": "author"
}
],
"date": "2013/2/20",
"date": "2013/01/01",
"DOI": "10.1155/2013/868174",
"ISSN": "1024-123X",
"abstractNote": "The problem of network-based robust filtering for stochastic systems with sensor nonlinearity is investigated in this paper. In the network environment, the effects of the sensor saturation, output quantization, and network-induced delay are taken into simultaneous consideration, and the output measurements received in the filter side are incomplete. The random delays are modeled as a linear function of the stochastic variable described by a Bernoulli random binary distribution. The derived criteria for performance analysis of the filtering-error system and filter design are proposed which can be solved by using convex optimization method. Numerical examples show the effectiveness of the design method.",
"ISSN": "1563-5147",
"abstractNote": "The problem of network-based robust filtering for stochastic systems with sensor nonlinearity is investigated in this paper. In the network environment, the effects of the sensor saturation, output q...",
"issue": "1",
"language": "en",
"libraryCatalog": "www.hindawi.com",
"libraryCatalog": "onlinelibrary.wiley.com",
"pages": "868174",
"publicationTitle": "Mathematical Problems in Engineering",
"url": "https://www.hindawi.com/journals/mpe/2013/868174/",
"url": "https://onlinelibrary.wiley.com/doi/10.1155/2013/868174",
"volume": "2013",
"attachments": [
{
@ -1337,10 +1206,8 @@ var testCases = [
"creatorType": "author"
}
],
"date": "2015-08-05T12:05:17Z",
"abstractNote": "New research finds creativity benefits.",
"language": "en",
"url": "https://hbr.org/2015/08/how-to-do-walking-meetings-right",
"websiteTitle": "Harvard Business Review",
"attachments": [
{
"title": "Snapshot",
@ -1379,6 +1246,7 @@ var testCases = [
"language": "en",
"libraryCatalog": "olh.openlibhums.org",
"publicationTitle": "Open Library of Humanities",
"rights": "Copyright: © 2015 The Author(s). This is an open-access article distributed under the terms of the Creative Commons Attribution 3.0 Unported License (CC-BY 3.0), which permits unrestricted use, distribution, and reproduction in any medium, provided the original author and source are credited. See http://creativecommons.org/licenses/by/3.0/.",
"url": "https://olh.openlibhums.org/article/id/4400/",
"volume": "1",
"attachments": [
@ -1407,9 +1275,9 @@ var testCases = [
"creatorType": "author"
}
],
"date": "2016-01-07T08:20:02-05:00",
"date": "2016-01-07T13:20:02+00:00",
"abstractNote": "Excluding female characters in merchandise is an ongoing pattern.",
"language": "en",
"language": "en-US",
"url": "https://www.vox.com/2016/1/7/10726296/wheres-rey-star-wars-monopoly",
"websiteTitle": "Vox",
"attachments": [
@ -1499,7 +1367,7 @@ var testCases = [
"language": "eng",
"libraryCatalog": "www.diva-portal.org",
"shortTitle": "Mobility modeling for transport efficiency",
"url": "http://urn.kb.se/resolve?urn=urn:nbn:se:liu:diva-112443",
"url": "https://urn.kb.se/resolve?urn=urn:nbn:se:liu:diva-112443",
"attachments": [
{
"title": "Full Text PDF",
@ -1569,12 +1437,13 @@ var testCases = [
"DOI": "10.1353/kri.2008.0061",
"ISSN": "1538-5000",
"issue": "4",
"journalAbbreviation": "kri",
"language": "en",
"libraryCatalog": "muse.jhu.edu",
"pages": "627-656",
"publicationTitle": "Kritika: Explorations in Russian and Eurasian History",
"shortTitle": "Serfs on the Move",
"url": "https://muse.jhu.edu/article/234097",
"url": "https://muse.jhu.edu/pub/28/article/234097",
"volume": "1",
"attachments": [
{
@ -1635,14 +1504,12 @@ var testCases = [
],
"date": "2015-06",
"ISBN": "9788460842118",
"abstractNote": "Abstracts aceptados sin presentacion / Accepted abstracts without presentation",
"conferenceName": "International Conference Arquitectonics Network: Architecture, Education and Society, Barcelona, 3-5 June 2015: Abstracts",
"language": "spa",
"libraryCatalog": "upcommons.upc.edu",
"publisher": "GIRAS. Universitat Politècnica de Catalunya",
"rights": "Open Access",
"shortTitle": "Necesidad y morfología",
"url": "https://upcommons.upc.edu/handle/2117/114657",
"url": "https://hdl.handle.net/2117/114657",
"attachments": [
{
"title": "Full Text PDF",
@ -1657,7 +1524,7 @@ var testCases = [
},
{
"type": "web",
"url": "https://www.pewresearch.org/fact-tank/2019/12/12/u-s-children-more-likely-than-children-in-other-countries-to-live-with-just-one-parent/",
"url": "https://www.pewresearch.org/short-reads/2019/12/12/u-s-children-more-likely-than-children-in-other-countries-to-live-with-just-one-parent/",
"items": [
{
"itemType": "blogPost",
@ -1669,10 +1536,11 @@ var testCases = [
"creatorType": "author"
}
],
"date": "2019-12-12",
"abstractNote": "Almost a quarter of U.S. children under 18 live with one parent and no other adults, more than three times the share of children around the world who do so.",
"blogTitle": "Pew Research Center",
"language": "en-US",
"url": "https://www.pewresearch.org/fact-tank/2019/12/12/u-s-children-more-likely-than-children-in-other-countries-to-live-with-just-one-parent/",
"url": "https://www.pewresearch.org/short-reads/2019/12/12/u-s-children-more-likely-than-children-in-other-countries-to-live-with-just-one-parent/",
"attachments": [
{
"title": "Snapshot",
@ -1785,10 +1653,10 @@ var testCases = [
"DOI": "10.3765/plsa.v4i1.4468",
"ISSN": "2473-8689",
"abstractNote": "Forced alignment automatically aligns audio recordings of spoken language with transcripts at the segment level, greatly reducing the time required to prepare data for phonetic analysis. However, existing algorithms are mostly trained on a few well-documented languages. We test the performance of three algorithms against manually aligned data. For at least some tasks, unsupervised alignment (either based on English or trained from a small corpus) is sufficiently reliable for it to be used on legacy data for low-resource languages. Descriptive phonetic work on vowel inventories and prosody can be accurately captured by automatic alignment with minimal training data. Consonants provided significantly more challenges for forced alignment.",
"issue": "1",
"journalAbbreviation": "Proc Ling Soc Amer",
"language": "en",
"libraryCatalog": "journals.linguisticsociety.org",
"pages": "3-12",
"pages": "3:1-12",
"publicationTitle": "Proceedings of the Linguistic Society of America",
"rights": "Copyright (c) 2019 Sarah Babinski, Rikker Dockum, J. Hunter Craft, Anelisa Fergus, Dolly Goldenberg, Claire Bowern",
"shortTitle": "A Robin Hood approach to forced alignment",
@ -1808,23 +1676,17 @@ var testCases = [
},
{
"type": "web",
"url": "https://www.swr.de/wissen/1000-antworten/kultur/woher-kommt-redensart-ueber-die-wupper-gehen-100.html",
"url": "https://www.swr.de/wissen/1000-antworten/woher-kommt-redensart-ueber-die-wupper-gehen-102.html",
"items": [
{
"itemType": "webpage",
"title": "Woher kommt \"über die Wupper gehen\"?",
"creators": [
{
"firstName": "",
"lastName": "SWRWissen",
"creatorType": "author"
}
],
"date": "2019-04-11",
"abstractNote": "Es gibt eine Vergleichsredensart: \"Der ist über den Jordan gegangen.“ Das heißt, er ist gestorben. Das bezieht sich auf die alten Grenzen Israels. In Wuppertal jedoch liegt jenseits des Flusses das Gefängnis.",
"creators": [],
"date": "2024-03-05",
"abstractNote": "Es gibt eine Vergleichsredensart: \"Der ist über den Jordan gegangen.\" Das heißt, er ist gestorben. Das bezieht sich auf die alten Grenzen Israels. In Wuppertal jedoch liegt jenseits des Flusses das Gefängnis. Von Rolf-Bernhard Essig",
"language": "de",
"url": "https://www.swr.de/wissen/1000-antworten/woher-kommt-redensart-ueber-die-wupper-gehen-100.html",
"websiteTitle": "swr.online",
"url": "https://www.swr.de/kultur/sprache/woher-kommt-redensart-ueber-die-wupper-gehen-102.html",
"websiteTitle": "SWR",
"attachments": [
{
"title": "Snapshot",
@ -1877,13 +1739,13 @@ var testCases = [
"title": "Windows Privilege Escalation: Kernel Exploit",
"creators": [
{
"firstName": "Raj",
"lastName": "Chandel",
"firstName": "",
"lastName": "Raj",
"creatorType": "author"
}
],
"date": "2021-12-30T17:41:33+00:00",
"abstractNote": "As this series was dedicated to Windows Privilege escalation thus Im writing this Post to explain command practice for kernel-mode exploitation. Table of Content What",
"abstractNote": "Learn about kernel-mode exploitation techniques for Windows Privilege Escalation with Metasploit, ExploitDB, and more.",
"blogTitle": "Hacking Articles",
"language": "en",
"shortTitle": "Windows Privilege Escalation",
@ -1900,85 +1762,6 @@ var testCases = [
}
]
},
{
"type": "web",
"url": "https://opg.optica.org/oe/fulltext.cfm?uri=oe-30-21-39188&id=509758",
"items": [
{
"itemType": "journalArticle",
"title": "Self-calibration interferometric stitching test method for cylindrical surfaces",
"creators": [
{
"firstName": "Hao",
"lastName": "Hu",
"creatorType": "author"
},
{
"firstName": "Zizhou",
"lastName": "Sun",
"creatorType": "author"
},
{
"firstName": "Shuai",
"lastName": "Xue",
"creatorType": "author"
},
{
"firstName": "Chaoliang",
"lastName": "Guan",
"creatorType": "author"
},
{
"firstName": "Yifan",
"lastName": "Dai",
"creatorType": "author"
},
{
"firstName": "Junfeng",
"lastName": "Liu",
"creatorType": "author"
},
{
"firstName": "Xiaoqiang",
"lastName": "Peng",
"creatorType": "author"
},
{
"firstName": "Shanyong",
"lastName": "Chen",
"creatorType": "author"
},
{
"firstName": "Yong",
"lastName": "Liu",
"creatorType": "author"
}
],
"date": "2022/10/10",
"DOI": "10.1364/OE.473836",
"ISSN": "1094-4087",
"abstractNote": "The surface figure accuracy requirement of cylindrical surfaces widely used in rotors of gyroscope, spindles of ultra-precision machine tools and high-energy laser systems is nearly 0.1 µm. Cylindricity measuring instrument that obtains 1-D profile result cannot be utilized for deterministic figuring methods. Interferometric stitching test for cylindrical surfaces utilizes a CGH of which the system error will accumulated to unacceptable extent for large aperture/angular aperture that require many subapertures. To this end, a self-calibration interferometric stitching method for cylindrical surfaces is proposed. The mathematical model of cylindrical surface figure and the completeness condition of self-calibration stitching test of cylindrical surfaces were analyzed theoretically. The effects of shear/stitching motion error and the subapertures lattice on the self-calibration test results were analyzed. Further, a self-calibration interferometric stitching algorithm that can theoretically recover all the necessary components of the system error for testing cylindrical surfaces was proposed. Simulations and experiments on a shaft were conducted to validate the feasibility.",
"issue": "21",
"journalAbbreviation": "Opt. Express, OE",
"language": "EN",
"libraryCatalog": "opg.optica.org",
"pages": "39188-39206",
"publicationTitle": "Optics Express",
"rights": "&#169; 2022 Optica Publishing Group",
"url": "https://opg.optica.org/oe/abstract.cfm?uri=oe-30-21-39188",
"volume": "30",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://themarkup.org/inside-the-markup/2023/01/18/five-ways-toward-a-fairer-more-transparent-hiring-process",
@ -2008,6 +1791,188 @@ var testCases = [
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.nhs.uk/baby/babys-development/behaviour/separation-anxiety/",
"items": [
{
"itemType": "webpage",
"title": "Separation anxiety",
"creators": [],
"date": "7 Dec 2020, 4:40 p.m.",
"abstractNote": "Separation anxiety is a normal part of your child's development. Find out how to handle the times when your baby or toddler cries or is clingy when you leave them.",
"language": "en",
"url": "https://www.nhs.uk/baby/babys-development/behaviour/separation-anxiety/",
"websiteTitle": "nhs.uk",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.tatler.com/article/clodagh-mckenna-hon-harry-herbert-wedding-george-osborne-highclere-castle",
"items": [
{
"itemType": "webpage",
"title": "The Queens godson married glamorous Irish chef Clodagh McKenna at Highclere this weekend",
"creators": [
{
"firstName": "Annabel",
"lastName": "Sampson",
"creatorType": "author"
}
],
"date": "2021-08-16T09:54:36.000Z",
"abstractNote": "The Hon Harry Herbert, son of the 7th Earl of Carnarvon, married Clodagh McKenna in a fairytale wedding attended by everyone from George Osborne and his fiancée, Thea Rogers, to Laura Whitmore",
"language": "en-GB",
"url": "https://www.tatler.com/article/clodagh-mckenna-hon-harry-herbert-wedding-george-osborne-highclere-castle",
"websiteTitle": "Tatler",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.timesofisrael.com/in-biggest-exit-in-israeli-history-google-buying-cyber-unicorn-wiz-for-32-billion/",
"items": [
{
"itemType": "blogPost",
"title": "In biggest exit in Israeli history, Google buys cyber unicorn Wiz for $32 billion",
"creators": [
{
"firstName": "Sharon",
"lastName": "Wrobel",
"creatorType": "author"
}
],
"abstractNote": "With the acquisition of Wiz, Google's parent company wants to strengthen its cyber offerings to better compete in the cloud computing race against tech giants Amazon and Microsoft",
"language": "en-US",
"url": "https://www.timesofisrael.com/in-biggest-exit-in-israeli-history-google-buying-cyber-unicorn-wiz-for-32-billion/",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://minerva.usc.gal/entities/publication/9a4fd001-4717-428f-96a5-44812f8f3805",
"items": [
{
"itemType": "journalArticle",
"title": "Contribución del análisis del líquido pleural al diagnóstico de los derrames pleurales",
"creators": [
{
"firstName": "María Esther",
"lastName": "San José Capilla",
"creatorType": "author"
}
],
"date": "2016-05-13",
"abstractNote": "El derrame pleural es una complicación común en numerosas enfermedades, y el diagnóstico diferencial es frecuentemente difícil de obtener sin la utilización de técnicas invasivas, lo que se intenta evitar. Aunque hay una amplia variedad de pruebas de laboratorio, un porcentaje significativo de pacientes con derrame pleural permanecen sin diagnosticar, o el diagnóstico se basa exclusivamente en evidencias clínicas, como son la experiencia del clínico o la respuesta al tratamiento empírico; por lo que son necesarios estudiar nuevos parámetros que permitan un diagnóstico diferencial más preciso. El trabajo actual consiste en estudiar cómo podemos mejorar el diagnóstico de líquido pleural a partir de la toracocentesis diagnóstica y de una muestra de sangre periférica extraída en el mismo momento de la punción pleural. El punto inicial de la diferenciación de la patología pleural es la diferenciación trasudado/exudado, que se realiza tradicionalmente mediante los clásicos criterios de Light. No obstante, esta diferenciación sigue siendo objeto de controversia, por lo que estudiamos para dicho fin nuevos parámetros, como son las fracciones de Colesterol, la determinación de Triglicéridos o de N-terminal del propéptido natriurético cerebral. Una vez clasificado el derrame como exudado, los pasos siguientes incluyen la diferenciación de las distintas patologías que pueden estar implicadas en su desarrollo. Para ello, se utilizan los parámetros clásicos en líquido pleural y suero de Adenosina Desaminasa, Lactato Deshidrogenasa, pH, Glucosa, recuento total y diferencial de células nucleadas,…. . Después del despistaje habitual de las diferentes entidades, aún permanece un 5-10% de los derrames pleurales sin diagnosticar, por lo que intentamos estudiar nuevos enfoques, como son la determinación de citoquinas proinflamatorias para el estudio de derrames de causa infecciosa, así como el intento de diagnóstico de tuberculosis pleural mediante un estudio de regresión aplicando datos clínicos y de laboratorio para el diagnóstico de esta entidad en pacientes menores de 40 años, grupo de pacientes donde la incidencia de esta enfermedad es muy elevada. Asimismo, intentamos comprobar la utilidad de un método sencillo como es el recuento diferencial de las células nucleadas para clarificar las distintas patologías que acompañan al derrame pleural, y un estudio estadístico de rendimiento del análisis del líquido pleural, junto con los datos clínicos y radiográficos, como ayuda para el diagnóstico de esta patología, fundamentalmente orientado hacia el origen neoplásico del derrame pleural. Nuestra finalidad es facilitar el diagnóstico de las distintas patologías implicadas en la patogenia del derrame pleural, sin necesidad de tener que recurrir a procedimientos invasivos, como son la biopsia pleural, la videotoracoscopia,.., y evitar lo máximo posible las posibles complicaciones que conlleva un diagnóstico tardío de estos procesos.",
"language": "spa",
"libraryCatalog": "minerva.usc.gal",
"url": "http://hdl.handle.net/10347/14743",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.statista.com/chart/13139/estimated-worldwide-mobile-e-commerce-sales/",
"items": [
{
"itemType": "webpage",
"title": "Infographic: Global Mobile E-Commerce Worth $2.2 Trillion in 2023",
"creators": [
{
"firstName": "Katharina",
"lastName": "Buchholz",
"creatorType": "author"
}
],
"date": "2023-08-10",
"abstractNote": "This chart shows estimated worldwide mobile e-commerce sales and their share in all e-commerce sales.",
"language": "en",
"shortTitle": "Infographic",
"url": "https://www.statista.com/chart/13139/estimated-worldwide-mobile-e-commerce-sales",
"websiteTitle": "Statista Daily Data",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://optimization-online.org/2023/05/maximum-likelihood-probability-measures-over-sets-and-applications-to-data-driven-optimization/",
"items": [
{
"itemType": "blogPost",
"title": "Maximum Likelihood Probability Measures over Sets and Applications to Data-Driven Optimization Optimization Online",
"creators": [
{
"firstName": "Juan",
"lastName": "Borrero",
"creatorType": "author"
},
{
"firstName": "Denis",
"lastName": "Saure",
"creatorType": "author"
}
],
"date": "2023-05-15",
"language": "en-US",
"url": "https://optimization-online.org/2023/05/maximum-likelihood-probability-measures-over-sets-and-applications-to-data-driven-optimization/",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

View File

@ -9,7 +9,7 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2019-12-25 15:35:07"
"lastUpdated": "2024-08-29 15:32:04"
}
/*
@ -35,13 +35,11 @@
***** END LICENSE BLOCK *****
*/
// attr()/text() v2
// eslint-disable-next-line
function attr(docOrElem,selector,attr,index){var elem=index?docOrElem.querySelectorAll(selector).item(index):docOrElem.querySelector(selector);return elem?elem.getAttribute(attr):null;}function text(docOrElem,selector,index){var elem=index?docOrElem.querySelectorAll(selector).item(index):docOrElem.querySelector(selector);return elem?elem.textContent:null;}
let doiRe = /\/(10\.[^#?/]+\/[^#?/]+)\//;
function detectWeb(doc, url) {
// ensure that we only detect where scrape will (most likely) work
if (url.includes('/content/doi/') && (url.search(/\/(10\.[^#?/]+\/[^#?/]+)\//) != -1 || url.includes("/full"))) {
if (url.includes('/content/doi/') && doiRe.test(url)) {
if (attr(doc, 'meta[name="dc.Type"]', 'content') == "book-part") {
return "bookSection";
}
@ -78,36 +76,47 @@ function getSearchResults(doc, url, checkOnly) {
}
function doWeb(doc, url) {
async function doWeb(doc, url) {
if (detectWeb(doc, url) == "multiple") {
Zotero.selectItems(getSearchResults(doc, url, false), function (items) {
if (!items) {
return;
}
var articles = [];
for (var i in items) {
articles.push(i);
}
ZU.processDocuments(articles, scrape);
});
let items = await Zotero.selectItems(getSearchResults(doc, url, false));
if (!items) return;
for (let url of Object.keys(items)) {
// requestDocument() doesn't yet set doc.cookie, so pass the parent doc's cookie
await scrape(await requestDocument(url), url, doc.cookie);
}
}
else {
scrape(doc, url);
await scrape(doc, url);
}
}
function scrape(doc, url) {
var DOI = url.match(/\/(10\.[^#?/]+\/[^#?/]+)\//);
var risURL;
if (DOI) {
risURL = "/insight/content/doi/" + DOI[1] + "/full/ris";
async function scrape(doc, url, cookieFallback) {
let response;
let DOI = url.match(doiRe)[1];
let cookie = doc.cookie || cookieFallback;
let xsrfTokenMatch = cookie && cookie.match(/XSRF-TOKEN=([^;]+)/);
if (xsrfTokenMatch) {
let xsrfToken = xsrfTokenMatch[1];
Z.debug('Using new API. XSRF token:');
Z.debug(xsrfToken);
let risURL = "/insight/api/citations/format/ris?_xsrf=" + xsrfToken; // Already URL-encoded
let body = JSON.stringify({ dois: [DOI] });
response = await requestText(risURL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-XSRF-TOKEN': decodeURIComponent(xsrfToken)
},
body
});
}
else {
Z.debug("can't find DOI, trying alternative approach for risURL");
risURL = url.replace(/\/full.*/, "/full/ris");
Z.debug('Using old API');
let risURL = "/insight/content/doi/" + DOI + "/full/ris";
response = await requestText(risURL);
}
// Z.debug(risURL);
var pdfURL;
// make this works on PDF pages
@ -118,66 +127,63 @@ function scrape(doc, url) {
pdfURL = attr(doc, 'a.intent_pdf_link', 'href');
}
// Z.debug("pdfURL: " + pdfURL);
ZU.doGet(risURL, function (response) {
// they number authors in their RIS...
response = response.replace(/A\d+\s+-/g, "AU -");
// they number authors in their RIS...
response = response.replace(/^A\d+\s+-/gm, "AU -");
var abstract = doc.getElementById('abstract');
var translator = Zotero.loadTranslator("import");
var tags = doc.querySelectorAll('li .intent_text');
translator.setTranslator("32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7");
translator.setString(response);
translator.setHandler("itemDone", function (obj, item) {
if (pdfURL) {
item.attachments.push({
url: pdfURL,
title: "Full Text PDF",
mimeType: "application/pdf"
var abstract = doc.getElementById('abstract');
var translator = Zotero.loadTranslator("import");
var tags = doc.querySelectorAll('li .intent_text');
translator.setTranslator("32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7");
translator.setString(response);
translator.setHandler("itemDone", function (obj, item) {
if (pdfURL) {
item.attachments.push({
url: pdfURL,
title: "Full Text PDF",
mimeType: "application/pdf"
});
}
else {
item.attachments.push({
title: "Snapshot",
document: doc
});
}
for (let tag of tags) {
item.tags.push(tag.textContent);
}
var authorsNodes = doc.querySelectorAll("div > a.contrib-search");
if (authorsNodes.length > 0) {
// prefer the authors information from the website as it contains the last and first name separately
// where the RIS data does not separate them correctly (it uses a space instead of comma)
// but the editors are only part of the RIS data
var authors = [];
for (let author of authorsNodes) {
authors.push({
firstName: text(author, "span.given-names"),
lastName: text(author, "span.surname"),
creatorType: "author"
});
}
else {
item.attachments.push({
title: "Snapshot",
document: doc
});
}
for (let tag of tags) {
item.tags.push(tag.textContent);
}
var authorsNodes = doc.querySelectorAll("div > a.contrib-search");
if (authorsNodes.length > 0) {
// prefer the authors information from the website as it contains the last and first name separately
// where the RIS data does not separate them correctly (it uses a space instead of comma)
// but the editors are only part of the RIS data
var authors = [];
for (let author of authorsNodes) {
authors.push({
firstName: text(author, "span.given-names"),
lastName: text(author, "span.surname"),
creatorType: "author"
});
}
var otherContributors = item.creators.filter(creator => creator.creatorType !== "author");
item.creators = otherContributors.length !== 0 ? authors.concat(separateNames(otherContributors)) : authors;
}
else {
Z.debug("No tags available for authors");
item.creators = separateNames(item.creators);
}
var otherContributors = item.creators.filter(creator => creator.creatorType !== "author");
item.creators = otherContributors.length !== 0 ? authors.concat(separateNames(otherContributors)) : authors;
}
else {
Z.debug("No tags available for authors");
item.creators = separateNames(item.creators);
}
if (item.date) {
item.date = ZU.strToISO(item.date);
}
if (abstract) {
item.abstractNote = ZU.trimInternal(abstract.textContent).replace(/^Abstract\s*/, "");
}
item.complete();
});
translator.translate();
if (item.date) {
item.date = ZU.strToISO(item.date);
}
if (abstract) {
item.abstractNote = ZU.trimInternal(abstract.textContent).replace(/^Abstract\s*/, "");
}
item.complete();
});
await translator.translate();
}
function separateNames(creators) {
@ -283,18 +289,18 @@ var testCases = [
"creators": [
{
"lastName": "Menk",
"creatorType": "author",
"firstName": "K. Bryan"
"firstName": "K. Bryan",
"creatorType": "author"
},
{
"lastName": "Malone",
"creatorType": "author",
"firstName": "Stephanie"
"firstName": "Stephanie",
"creatorType": "author"
}
],
"date": "2015-01-01",
"ISBN": "9781784415877 9781784415884",
"abstractNote": "Originality/value This technique creates opportunities for students to have unique assignments encouraging student to student teaching and can be applied to assignments in any accounting course (undergraduate and graduate). This testing method has been used in Intermediate I and II, Individual Taxation, and Corporate Taxation.",
"abstractNote": "Purpose The subject area of the assignment is accounting education and testing techniques. Methodology/approach This paper details an effective method to create individualized assignments and testing materials. Using a spreadsheet (Microsoft Excel), the creation of the unique assignments and answer keys can be semi-automated to reduce the grading difficulties of unique assignments. Findings Because students are using a unique data set for each assignment, the students are able to more effectively engage in student to student teaching. This process of unique assignments allows students to collaborate without fear that a single student would provide the answers. As tax laws (e.g., credit and deduction phase-outs, tax rates, and dependents) change depending on the level of income and other factors, an individualized test is ideal in a taxation course. Practical implications The unique assignments allow instructors to create markedly different scenarios for each student. Using this testing method requires that the student thoroughly understands the conceptual processes as the questions cannot be predicted. A list of supplementary materials is included, covering sample questions, conversion to codes, and sample assignment questions. Originality/value This technique creates opportunities for students to have unique assignments encouraging student to student teaching and can be applied to assignments in any accounting course (undergraduate and graduate). This testing method has been used in Intermediate I and II, Individual Taxation, and Corporate Taxation.",
"bookTitle": "Advances in Accounting Education: Teaching and Curriculum Innovations",
"extra": "DOI: 10.1108/S1085-462220150000016007",
"libraryCatalog": "Emerald Insight",
@ -306,7 +312,8 @@ var testCases = [
"volume": "16",
"attachments": [
{
"title": "Snapshot"
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [
@ -339,24 +346,24 @@ var testCases = [
"title": "The influence of context upon consumer sensory evaluation of chickenmeat quality",
"creators": [
{
"firstName": "Orla",
"lastName": "Kennedy",
"creatorType": "author",
"firstName": "Orla"
"creatorType": "author"
},
{
"firstName": "Barbara",
"lastName": "StewartKnox",
"creatorType": "author",
"firstName": "Barbara"
"creatorType": "author"
},
{
"firstName": "Peter",
"lastName": "Mitchell",
"creatorType": "author",
"firstName": "Peter"
"creatorType": "author"
},
{
"firstName": "David",
"lastName": "Thurnham",
"creatorType": "author",
"firstName": "David"
"creatorType": "author"
}
],
"date": "2004-01-01",
@ -371,8 +378,8 @@ var testCases = [
"volume": "106",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [
@ -401,33 +408,33 @@ var testCases = [
"creators": [
{
"lastName": "Kutz-Flamenbaum",
"creatorType": "author",
"firstName": "Rachel V."
"firstName": "Rachel V.",
"creatorType": "author"
},
{
"lastName": "Staggenborg",
"creatorType": "author",
"firstName": "Suzanne"
"firstName": "Suzanne",
"creatorType": "author"
},
{
"lastName": "Duncan",
"creatorType": "author",
"firstName": "Brittany J."
"firstName": "Brittany J.",
"creatorType": "author"
},
{
"lastName": "Earl",
"creatorType": "editor",
"firstName": "Jennifer"
"firstName": "Jennifer",
"creatorType": "editor"
},
{
"lastName": "A. Rohlinger",
"creatorType": "editor",
"firstName": "Deana"
"lastName": "Rohlinger",
"firstName": "Deana A.",
"creatorType": "editor"
}
],
"date": "2012-01-01",
"ISBN": "9781780528816 9781780528809",
"abstractNote": "Research implications We argue that events such as the G-20 meetings provide protesters with opportunities to gain temporary “standing” with the media. During such times, activists can use tactics and frames to alter the balance of power in relations with the media and the state and to attract positive media coverage, particularly when activists develop strategies that are not exclusively focused on the media. We argue that a combination of political opportunities and activist media strategies enabled protest organizers to position themselves as central figures in the G-20 news story and leverage that position to build media interest, develop relationships with reporters, and influence newspaper coverage.",
"abstractNote": "Purpose Movements typically have great difficulty using the mass media to spread their messages to the public, given the media's greater power to impose their frames on movement activities and goals. In this paper, we look at the impact of the political context and media strategies of protesters against the 2009 G-20 meetings in Pittsburgh on media coverage of the protests.Methodology We employ field observations, interviews with activists and reporters, and a content analysis of print coverage of the demonstrations by the two local daily newspapers, the Pittsburgh Post-Gazette and the Pittsburgh Tribune-Review.Findings We find that protesters were relatively successful in influencing how they were portrayed in local newspaper stories and in developing a sympathetic image of their groups members. Specifically, we find that activist frames were present in newspaper coverage and activists were quoted as frequently as city officials.Research implications We argue that events such as the G-20 meetings provide protesters with opportunities to gain temporary “standing” with the media. During such times, activists can use tactics and frames to alter the balance of power in relations with the media and the state and to attract positive media coverage, particularly when activists develop strategies that are not exclusively focused on the media. We argue that a combination of political opportunities and activist media strategies enabled protest organizers to position themselves as central figures in the G-20 news story and leverage that position to build media interest, develop relationships with reporters, and influence newspaper coverage.",
"bookTitle": "Media, Movements, and Political Change",
"extra": "DOI: 10.1108/S0163-786X(2012)0000033008",
"libraryCatalog": "Emerald Insight",
@ -438,7 +445,8 @@ var testCases = [
"volume": "33",
"attachments": [
{
"title": "Snapshot"
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [
@ -475,29 +483,29 @@ var testCases = [
"title": "Tourism research in Spain: The contribution of geography (19601995)",
"creators": [
{
"firstName": "Salvador",
"lastName": "Antón i Clavé",
"creatorType": "author",
"firstName": "Salvador"
"creatorType": "author"
},
{
"firstName": "Francisco",
"lastName": "López Palomeque",
"creatorType": "author",
"firstName": "Francisco"
"creatorType": "author"
},
{
"firstName": "Manuel J.",
"lastName": "Marchena Gómez",
"creatorType": "author",
"firstName": "Manuel J."
"creatorType": "author"
},
{
"firstName": "Sevilla",
"lastName": "Vera Rebollo",
"creatorType": "author",
"firstName": "Sevilla"
"creatorType": "author"
},
{
"firstName": "J.",
"lastName": "Fernando Vera Rebollo",
"creatorType": "author",
"firstName": "J."
"creatorType": "author"
}
],
"date": "1996-01-01",
@ -513,8 +521,8 @@ var testCases = [
"volume": "51",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [
@ -547,6 +555,72 @@ var testCases = [
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.emerald.com/insight/content/doi/10.1108/JACPR-02-2022-0685/full/html",
"items": [
{
"itemType": "journalArticle",
"title": "A multi-level, time-series network analysis of the impact of youth peacebuilding on quality peace",
"creators": [
{
"firstName": "Laura K.",
"lastName": "Taylor",
"creatorType": "author"
},
{
"firstName": "Celia",
"lastName": "Bähr",
"creatorType": "author"
}
],
"date": "2023-01-01",
"DOI": "10.1108/JACPR-02-2022-0685",
"ISSN": "1759-6599",
"abstractNote": "Purpose Over 60% of armed conflicts re-occur; the seed of future conflict is sown even as a peace agreement is signed. The cyclical nature of war calls for a focus on youth who can disrupt this pattern over time. Addressing this concern, the developmental peace-building model calls for a dynamic, multi-level and longitudinal approach. Using an innovative statistical approach, this study aims to investigate the associations among four youth peace-building dimensions and quality peace. Design/methodology/approach Multi-level time-series network analysis of a data set containing 193 countries and spanning the years between 2011 and 2020 was performed. This statistical approach allows for complex modelling that can reveal new patterns of how different youth peace-building dimensions (i.e. education, engagement, information, inclusion), identified through rapid evidence assessment, promote quality peace over time. Such a methodology not only assesses between-country differences but also within-country change. Findings While the within-country contemporaneous network shows positive links for education, the temporal network shows significant lagged effects for all four dimensions on quality peace. The between-country network indicates significant direct effects of education and information, on average, and indirect effects of inclusion and engagement, on quality peace. Originality/value This approach demonstrates a novel application of multi-level time-series network analysis to explore the dynamic development of quality peace, capturing both stability and change. The analysis illustrates how youth peace-building dimensions impact quality peace in the macro-system globally. This investigation of quality peace thus illustrates that the science of peace does not necessitate violent conflict.",
"issue": "2",
"libraryCatalog": "Emerald Insight",
"pages": "109-123",
"publicationTitle": "Journal of Aggression, Conflict and Peace Research",
"url": "https://doi.org/10.1108/JACPR-02-2022-0685",
"volume": "15",
"attachments": [
{
"title": "Full Text PDF",
"mimeType": "application/pdf"
}
],
"tags": [
{
"tag": "Developmental peace-building model"
},
{
"tag": "Education"
},
{
"tag": "Engagement"
},
{
"tag": "Inclusion"
},
{
"tag": "Information"
},
{
"tag": "Quality peace"
},
{
"tag": "Time-series network analysis"
},
{
"tag": "Youth peacebuilding"
}
],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

View File

@ -0,0 +1,221 @@
{
"translatorID": "dc879929-ae39-45b3-b49b-dab2c80815ab",
"label": "Encyclopedia of Korean Culture",
"creator": "jacoblee36251",
"target": "^https?://(www\\.)?encykorea\\.aks\\.ac\\.kr/Article/",
"minVersion": "5.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2023-09-15 20:07:33"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2023 jacoblee36251
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
function detectWeb(doc, url) {
if (/^https?:\/\/[^/]+\/Article\/E\d+/.test(url)) {
return 'encyclopediaArticle';
}
else if (getSearchResults(doc, true)) {
return 'multiple';
}
return false;
}
function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
var rows = doc.querySelectorAll('li.item > a[href^="/Article/E"]');
for (let row of rows) {
let href = row.href;
let title = ZU.trimInternal(row.querySelector('div.title').textContent);
if (!href || !title) continue;
if (checkOnly) return true;
found = true;
items[href] = title;
}
return found ? items : false;
}
async function doWeb(doc, url) {
if (detectWeb(doc, url) == 'multiple') {
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(await requestDocument(url));
}
}
else {
await scrape(doc, url);
}
}
async function scrape(doc, url = doc.location.href) {
var item = new Zotero.Item('encyclopediaArticle');
item.title = ZU.trimInternal(text(doc, ".content-head-title"));
item.encyclopediaTitle = "한국민족문화대백과사전 [Encyclopedia of Korean Culture]";
item.publisher = "Academy of Korean Studies";
item.language = "ko";
// Clean url by removing # terms
item.url = url.replace(/#.*/, "");
// Author processing; may be 0 or more names, would be in Korean
var authors = doc.querySelector('div.author-wrap > span');
if (authors) {
authors = authors.textContent;
// For simplicity, assume one character surnames for everybody (there are rare exceptions)
for (let author of authors.split('·')) {
item.creators.push({
lastName: author[0],
firstName: author.slice(1),
creatorType: "author"
});
}
}
item.attachments.push({ title: "Snapshot", document: doc, mimeType: "text/html" });
item.complete();
}
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "https://encykorea.aks.ac.kr/Article/E0013414#cm_multimedia",
"detectedItemType": "encyclopediaArticle",
"items": [
{
"itemType": "encyclopediaArticle",
"title": "다대포 (多大浦)",
"creators": [
{
"lastName": "오",
"firstName": "건환",
"creatorType": "author"
},
{
"lastName": "김",
"firstName": "건유",
"creatorType": "author"
}
],
"encyclopediaTitle": "한국민족문화대백과사전 [Encyclopedia of Korean Culture]",
"language": "ko",
"libraryCatalog": "Encyclopedia of Korean Culture",
"publisher": "Academy of Korean Studies",
"url": "https://encykorea.aks.ac.kr/Article/E0013414",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://encykorea.aks.ac.kr/Article/E0002855",
"detectedItemType": "encyclopediaArticle",
"items": [
{
"itemType": "encyclopediaArticle",
"title": "경주 남산 탑곡 마애불상군 (慶州 南山 塔谷 磨崖佛像群)",
"creators": [],
"encyclopediaTitle": "한국민족문화대백과사전 [Encyclopedia of Korean Culture]",
"language": "ko",
"libraryCatalog": "Encyclopedia of Korean Culture",
"publisher": "Academy of Korean Studies",
"url": "https://encykorea.aks.ac.kr/Article/E0002855",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://encykorea.aks.ac.kr/Article/E0025488",
"detectedItemType": "encyclopediaArticle",
"items": [
{
"itemType": "encyclopediaArticle",
"title": "사랑 (舍廊)",
"creators": [
{
"lastName": "김",
"firstName": "동욱",
"creatorType": "author"
}
],
"encyclopediaTitle": "한국민족문화대백과사전 [Encyclopedia of Korean Culture]",
"language": "ko",
"libraryCatalog": "Encyclopedia of Korean Culture",
"publisher": "Academy of Korean Studies",
"url": "https://encykorea.aks.ac.kr/Article/E0025488",
"attachments": [
{
"title": "Snapshot",
"mimeType": "text/html"
}
],
"tags": [],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://encykorea.aks.ac.kr/Article/Search/%ED%95%99%EC%9B%90?field=&type=&alias=false&body=false&containdesc=false&keyword=%ED%95%99%EC%9B%90",
"detectedItemType": "multiple",
"items": "multiple"
},
{
"type": "web",
"url": "https://encykorea.aks.ac.kr/Article/List/Field/%EC%98%88%EC%88%A0%C2%B7%EC%B2%B4%EC%9C%A1%3E%EC%A1%B0%EA%B0%81",
"detectedItemType": "multiple",
"items": "multiple"
},
{
"type": "web",
"url": "https://encykorea.aks.ac.kr/Article/List/Type/%EC%9C%A0%EC%A0%81",
"detectedItemType": "multiple",
"items": "multiple"
}
]
/** END TEST CASES **/

331
Envidat.js Normal file
View File

@ -0,0 +1,331 @@
{
"translatorID": "0f6f5164-b44b-4ef6-9c5e-e3f39637569b",
"label": "Envidat",
"creator": "Alain Borel",
"target": "^https://(www\\.)?envidat.ch/",
"minVersion": "6.0",
"maxVersion": "",
"priority": 100,
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2025-04-29 03:02:00"
}
/*
***** BEGIN LICENSE BLOCK *****
Copyright © 2023 Alain Borel
This file is part of Zotero.
Zotero is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Zotero is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Zotero. If not, see <http://www.gnu.org/licenses/>.
***** END LICENSE BLOCK *****
*/
// A search query in the frontend will be converted to a query for:
// all the words in the title or the notes
// OR all possible single-word queries in the title or notes
let possibleCombinations = (str) => {
let combinations = ['%22*' + str.split(' ').join('%20') + '*%22~2'];
let terms = str.match(/\S+/g);
for (let i = 0; i < terms.length; i++) {
combinations.push('%22*' + terms[i] + '*%22');
}
return combinations;
};
// create the search URL for the API using an array of possible combinations
let apiQuery = (arr) => {
const finalParams = '&wt=json&rows=1000&fq=capacity:public&fq=state:active';
let subterms = [];
for (let k = 0; k < arr.length; k++) {
subterms.push('title:' + arr[k]);
subterms.push('notes:' + arr[k]);
}
return 'q=' + subterms.join('%20OR%20') + finalParams;
};
function detectWeb(doc, url) {
if (url.includes('/#/metadata/') || url.includes('/dataset/')) {
return 'dataset';
}
else if (url.includes('/#/browse?')) {
Zotero.debug('This should be multiple objects');
return 'multiple';
}
else return false;
}
async function getSearchResults(doc, checkOnly) {
var items = {};
var found = false;
// https://www.envidat.ch/#/browse?search=rock%20snow
// => https://www.envidat.ch/query?q=title:%22*rock%20snow*%22~2%20OR%20notes:%22*rock%20snow*%22~2%20OR%20title:%20%22*rock*%22%20OR%20notes:%20%22*rock*%22%20OR%20title:%20%22*snow*%22%20OR%20notes:%20%22*snow*%22&wt=json&rows=1000&fq=capacity:public&fq=state:active
// tags are used at frontend level: https://www.envidat.ch/#/browse?search=rock%20snow&tags=FOREST&isAuthorSearch=false
// => same call
let queryString = doc.location.href.replace('https://www.envidat.ch/#/browse', '');
let urlParams = new URLSearchParams(queryString);
let query = urlParams.get('search');
let tags = urlParams.get('tags');
if (tags) {
tags = tags.split(',');
}
else {
tags = [];
}
let termCombinations = possibleCombinations(query);
let myQuery = apiQuery(termCombinations);
let searchApiUrl = 'https://www.envidat.ch/query?' + myQuery;
let { response: rsp } = await requestJSON(searchApiUrl);
let href;
let title;
if (rsp.docs) {
found = true;
if (checkOnly) return found;
for (let row of rsp.docs) {
// Zotero.debug(row.tags);
let foundTags = {};
let allTagsFound = true;
for (let tag of tags) {
foundTags[tag] = [];
for (let rowTag of row.tags) {
let matcher = new RegExp(tag, "g");
//if (rowTag.search(tag) >= 0) {
if (matcher.match(rowTag)) {
foundTags[tag].push(rowTag);
}
}
}
for (let tag of tags) {
if (foundTags[tag] == 0) {
allTagsFound = false;
}
}
Zotero.debug(allTagsFound);
if (allTagsFound) {
// Zotero.debug(foundTags);
href = '/#/metadata/' + row.name;
title = ZU.trimInternal(row.title);
// Zotero.debug(href + '/' + title);
items[href] = title;
}
}
}
return found ? items : false;
}
async function doWeb(doc, url) {
if (detectWeb(doc, url) == 'multiple') {
// Zotero.debug('multiple');
let searchResults = await getSearchResults(doc, false);
let items = await Zotero.selectItems(searchResults);
// Zotero.debug(items.length);
if (!items) return;
for (let url of Object.keys(items)) {
// Zotero.debug('about to scrape() ' + url);
await scrape(url);
}
}
else {
await scrape(url);
}
}
async function scrape(url) {
// Zotero.debug(url);
let dataciteUrl = url.replace('#/metadata/', 'dataset/') + '/export/datacite.xml';
// Zotero.debug(dataciteUrl);
if (dataciteUrl) {
let xmlDoc = await requestDocument(dataciteUrl);
processMetadata(xmlDoc);
}
}
function processMetadata(xmlDoc) {
// TODO: Replace with call to Datacite XML if we ever add a translator for that
let item = new Zotero.Item('dataset');
item.repository = 'Envidat';
item.title = text(xmlDoc, "title");
item.date = text(xmlDoc, "publicationYear");
item.language = text(xmlDoc, "language");
item.publisher = text(xmlDoc, "publisher");
for (let creatorNode of xmlDoc.getElementsByTagName("creator")) {
let givenName = text(creatorNode, "givenName");
let familyName = text(creatorNode, "familyName");
// TODO should we use or map the roles from Datacite?
let author = { lastName: familyName, firstName: givenName, creatorType: 'author' };
item.creators.push(author);
}
for (let subjectNode of xmlDoc.getElementsByTagName("subject")) {
let tag = { tag: subjectNode.textContent };
if (tag.tag === tag.tag.toUpperCase()) {
tag.tag = ZU.capitalizeTitle(tag.tag, true);
}
item.tags.push(tag);
}
// TODO find an example with a DOI
item.DOI = text(xmlDoc, "Identifier");
item.url = text(xmlDoc, "alternateIdentifier[alternateIdentifierType='URL']:last-child");
item.abstractNote = text(xmlDoc, "description[descriptionType='Abstract' i]");
item.rights = text(xmlDoc, "rights");
item.complete();
}
/** BEGIN TEST CASES **/
var testCases = [
{
"type": "web",
"url": "https://www.envidat.ch/#/metadata/experimental-rockfall-dataset-tschamut-grisons-switzerland",
"items": [
{
"itemType": "dataset",
"title": "Induced Rockfall Dataset (Small Rock Experimental Campaign), Tschamut, Grisons, Switzerland",
"creators": [
{
"lastName": "Caviezel",
"firstName": "Andrin",
"creatorType": "author"
},
{
"lastName": "Bühler",
"firstName": "Yves",
"creatorType": "author"
},
{
"lastName": "Christen",
"firstName": "Marc",
"creatorType": "author"
},
{
"lastName": "Bartelt",
"firstName": "Perry",
"creatorType": "author"
}
],
"date": "2018",
"abstractNote": "Dataset of an experimental campaign of induced rockfall in Tschamut, Grisons, Switzerland. \nThe data archive contains site specific geographical data such as DEM and orthophoto as well as the deposition points of manually induced rockfall by releasing differently shaped boulders with 3080 kg of mass. Additionally available are all the StoneNode data streams for rocks equipped with a sensor. The data set consists of \n* Deposition points from two series (wet (27/10/2016) and frozen (08/12/2016) ground) \n* Digital Elevation Model (grid resolution 2 m) obtained via UAV\n* Orthophoto (5 cm resolution) obtained via UAV\n* Digitized rock point clouds (.pts input files for RAMMS::ROCKFALL)\n* StoneNode v1.0 raw data stream for equipped rocks.\nFurther information is found in\n* A. Caviezel et al., _Design and Evaluation of a Low-Power Sensor Device for Induced Rockfall Experiments_, IEEE Transactions on Instrumentation and Measurement, 2018, 67, 767-779, http://ieeexplore.ieee.org/document/8122020/\n* P. Niklaus et al., _StoneNode: A low-power sensor device for induced rockfall experiments_, 2017 IEEE Sensors Applications Symposium (SAS), 2017, 1-6, http://ieeexplore.ieee.org/document/7894081/",
"language": "en",
"libraryCatalog": "Envidat",
"repository": "EnviDat",
"rights": "ODbL with Database Contents License (DbCL)",
"url": "https://www.envidat.ch/dataset/5b7a47bf-cbea-42a0-879f-ea2ccd17e82f",
"attachments": [],
"tags": [
{
"tag": "Dem"
},
{
"tag": "Deposition Points"
},
{
"tag": "Induced Rockfall"
},
{
"tag": "Natural Hazards"
},
{
"tag": "Rockfall"
},
{
"tag": "Rockfall Experiments"
},
{
"tag": "Rockfall Runout"
},
{
"tag": "Sensor Stream"
},
{
"tag": "Stonenode"
},
{
"tag": "Stonenodedata"
}
],
"notes": [],
"seeAlso": []
}
]
},
{
"type": "web",
"url": "https://www.envidat.ch/dataset/10-16904-envidat-28",
"items": [
{
"itemType": "dataset",
"title": "Snowfarming data set Davos and Martell 2015",
"creators": [
{
"lastName": "Grünewald",
"firstName": "Thomas",
"creatorType": "author"
},
{
"lastName": "Wolfsperger",
"firstName": "Fabian",
"creatorType": "author"
},
{
"lastName": "Lehning",
"firstName": "Michael",
"creatorType": "author"
}
],
"date": "2018",
"abstractNote": "Two data sets obtained for snow farming projects (Fluela, Davos, CH and Martell, IT) in 2015. \nThe data set contains for each site:\n* 10 cm GIS raster of snow depth calculated from terrestrial laserscanning surveys (TLS) in the end of winter season (April/May)\n* 10 cm GIS raster of snow depth calculated from TLS in the end of summer season (October)\nInput files for SNOWPACK model:\n* .sno: snow profile at the end of winter\n* .smet: meteorological data measured by weather stations in the area\nFor more details see Grünewald, T., Lehning, M., and Wolfsperger, F.: Snow farming: Conserving snow over the summer season, The Cryosphere Discuss., https://doi.org/10.5194/tc-2017-93, in review, 2017.",
"language": "en",
"libraryCatalog": "Envidat",
"repository": "EnviDat",
"rights": "ODbL with Database Contents License (DbCL)",
"url": "https://www.envidat.ch/dataset/640b09be-3b86-492e-aba2-449329969989",
"attachments": [],
"tags": [
{
"tag": "Snow"
},
{
"tag": "Snow Conservation"
},
{
"tag": "Snow Farming"
},
{
"tag": "Snowpack"
},
{
"tag": "Terrestrial Laser Scanning"
},
{
"tag": "Winter Tourism"
}
],
"notes": [],
"seeAlso": []
}
]
}
]
/** END TEST CASES **/

View File

@ -9,7 +9,7 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2021-06-19 08:52:49"
"lastUpdated": "2024-03-23 01:38:15"
}
/*
@ -39,7 +39,7 @@
function detectWeb(doc, url) {
if (url.includes('/article/')) {
if (url.includes('/PPR/')) {
return 'report';
return 'preprint';
}
else {
return "journalArticle";
@ -66,17 +66,18 @@ function getSearchResults(doc, checkOnly) {
return found ? items : false;
}
function doWeb(doc, url) {
if (detectWeb(doc, url) == "multiple") {
Zotero.selectItems(getSearchResults(doc, false), function (items) {
if (!items) return;
Object.keys(items).forEach(scrape);
});
async function doWeb(doc, url) {
if (detectWeb(doc, url) == 'multiple') {
let items = await Zotero.selectItems(getSearchResults(doc, false));
if (!items) return;
for (let url of Object.keys(items)) {
await scrape(await requestDocument(url));
}
}
else {
let jsonURL = getJSONURL(url);
if (jsonURL) {
scrape(jsonURL);
await scrape(jsonURL);
}
else {
Z.debug('Couldn\'t extract ID from URL: ' + url);
@ -84,10 +85,11 @@ function doWeb(doc, url) {
}
}
function scrape(jsonURL) {
ZU.doGet(jsonURL, function (respText) {
processJSON(JSON.parse(respText));
});
async function scrape(jsonURL) {
// Z.debug(jsonURL);
let respText = await requestJSON(jsonURL);
processJSON(respText);
}
function getJSONURL(pageURL) {
@ -98,6 +100,7 @@ function getJSONURL(pageURL) {
}
function processJSON(json) {
// Z.debug(json);
if (!json.resultList || !json.resultList.result || !json.resultList.result.length) {
Z.debug('Query returned no results');
return;
@ -145,8 +148,7 @@ function processPubTypeList(pubTypeList, item) {
if (!pubTypeList || !pubTypeList.pubType) return;
if (pubTypeList.pubType.length == 1 && pubTypeList.pubType[0] == 'Preprint') {
item.itemType = 'report';
item.extra = (item.extra || '') + `Type: article\n`;
item.itemType = 'preprint';
}
else {
item.itemType = 'journalArticle';
@ -214,6 +216,7 @@ function processKeywordList(keywordList, item) {
}
}
/** BEGIN TEST CASES **/
var testCases = [
{
@ -363,7 +366,7 @@ var testCases = [
"url": "https://europepmc.org/article/PPR/PPR358366",
"items": [
{
"itemType": "report",
"itemType": "preprint",
"title": "Fly ash application in moorum embankment and its stability analysis using FLAC/SLOPE and Response Surface Metho",
"creators": [
{
@ -378,11 +381,17 @@ var testCases = [
}
],
"date": "2021",
"DOI": "10.21203/rs.3.rs-631949/v1",
"abstractNote": "This paper presents the application of fly ash in moorum embankment by partial replacement of moorum with fly ash and its stability analysis has been carried out. An experimental investigation was carried out on moorum blended with fly ash at different proportions of fly ash by dry weight of soil for the moorum embankment stability analysis. The Index properties and strength properties were assessed by performing Atterberg's limit, specific gravity, grain size distribution, compaction test, direct shear test (DST), and California Bearing Ratio (CBR) test respectively. The embankment slope stability analysis was performed using FLAC/SLOPE version 8.10 (Fast Lagrangian Analysis of Continua) software at a various slope angle of 30°, 32°, and 34° and different heights of the embankment of 6 m, 8 m, and 10 m to calculate Factor of Safety (FOS). FOS decreases with the increment of fly ash content, the height of embankment, and slope angle respectively. In addition to the numerical analysis, Response Surface Methodology (RSM) based (Face-Centered Central Composite Design) was used to predict FOS. The developed mathematical equation illustrates that the RSM model was statistically significant and the results give a reliable prediction of FOS.",
"extra": "Type: article",
"libraryCatalog": "Europe PMC",
"rights": "cc by",
"url": "https://doi.org/10.21203/rs.3.rs-631949/v1",
"attachments": [],
"attachments": [
{
"title": "Full Text PDF (Open access)",
"mimeType": "application/pdf"
}
],
"tags": [],
"notes": [],
"seeAlso": []

View File

@ -9,7 +9,7 @@
"inRepository": true,
"translatorType": 4,
"browserSupport": "gcsibv",
"lastUpdated": "2021-08-16 20:40:08"
"lastUpdated": "2024-03-21 19:05:49"
}
/*
@ -44,7 +44,7 @@
function detectWeb(doc, url) {
if (url.includes('/articles/')
&& doc.querySelector('meta[name="citation_title"]')) {
return "report";
return "preprint";
}
else if (getSearchResults(doc, true)) {
return "multiple";
@ -85,20 +85,21 @@ function scrape(doc, url) {
translator.setDocument(doc);
translator.setHandler('itemDone', function (obj, item) {
item.itemType = 'report';
item.extra = (item.extra || '') + '\nType: article'; // preprint
item.itemType = 'preprint';
delete item.pages;
delete item.reportType;
item.reportNumber = `${item.volume}:${item.issue}`;
delete item.genre;
if (item.volume && item.issue) {
item.archiveID = `${item.volume}:${item.issue}`;
}
delete item.volume;
delete item.issue;
delete item.number;
item.institution = item.publicationTitle;
delete item.publisher;
item.publisher = item.publicationTitle;
delete item.publicationTitle;
delete item.distributor;
delete item.company;
delete item.institution;
delete item.label;
if (item.date) {
item.date = ZU.strToISO(item.date);
@ -110,7 +111,7 @@ function scrape(doc, url) {
});
translator.getTranslatorObject(function (trans) {
trans.itemType = "report";
trans.itemType = "preprint";
trans.doWeb(doc, url);
});
}
@ -122,8 +123,8 @@ var testCases = [
"url": "https://f1000research.com/articles/10-614",
"items": [
{
"itemType": "report",
"title": "Cerebrospinal fluid neurofilament light levels in CLN2 disease patients treated with enzyme replacement therapy normalise after two years on treatment",
"itemType": "preprint",
"title": "Cerebrospinal fluid neurofilament light chain levels in CLN2 disease patients treated with enzyme replacement therapy normalise after two years on treatment",
"creators": [
{
"firstName": "Katharina",
@ -186,13 +187,13 @@ var testCases = [
"creatorType": "author"
}
],
"date": "2021-07-20",
"date": "2022-01-05",
"DOI": "10.12688/f1000research.54556.2",
"abstractNote": "Classic late infantile neuronal ceroid lipofuscinosis (CLN2 disease) is caused by a deficiency of tripeptidyl-peptidase-1. In 2017, the first CLN2 enzyme replacement therapy (ERT) cerliponase alfa (Brineura) was approved by the FDA and EMA. The CLN2 disease clinical rating scale (CLN2 CRS) was developed to monitor loss of motor function, language and vision as well as frequency of generalised tonic clonic seizures. Using CLN2 CRS in an open label clinical trial it was shown that Brineura slowed down the progression of CLN2 symptoms. Neurofilament light chain (NfL) is a protein highly expressed in myelinated axons. An increase of cerebrospinal fluid (CSF) and blood NfL is found in a variety of neuroinflammatory, neurodegenerative, traumatic, and cerebrovascular diseases. We analysed CSF NfL in CLN2 patients treated with Brineura to establish whether it can be used as a possible biomarker of response to therapy. Newly diagnosed patients had CSF samples collected and analysed at first treatment dose and up to 12 weeks post-treatment to look at acute changes. Patients on a compassionate use programme who were already receiving ERT for approximately 1yr had CSF samples collected and NfL analysed over the following 1.3 years (2.3 years post-initiation of ERT) to look at long-term changes. All newly diagnosed patients we investigated with classical late infantile phenotype had high NfL levels &gt;2000 pg/ml at start of treatment. No significant change was observed in NfL up to 12 weeks post-treatment. After one year of ERT, two out of six patients still had high NfL levels, but all patients showed a continued decrease, and all had low NfL levels after two years on ERT. NfL levels appear to correspond and predict improved clinical status of patients on ERT and could be useful as a biomarker to monitor neurodegeneration and verify disease modification in CLN2 patients on ERT.",
"extra": "Type: article",
"institution": "F1000Research",
"archiveID": "10:614",
"language": "en",
"libraryCatalog": "f1000research.com",
"reportNumber": "10:614",
"repository": "F1000Research",
"rights": "http://creativecommons.org/licenses/by/4.0/",
"url": "https://f1000research.com/articles/10-614",
"attachments": [
@ -203,7 +204,7 @@ var testCases = [
],
"tags": [
{
"tag": "Enzyme replacment therapy"
"tag": "Enzyme replacement therapy"
},
{
"tag": "Neurofilament light"
@ -222,7 +223,7 @@ var testCases = [
"url": "https://f1000research.com/articles/10-153",
"items": [
{
"itemType": "report",
"itemType": "preprint",
"title": "Regional disparities in postnatal care among mothers aged 15-49 years old: An analysis of the Indonesian Demographic and Health Survey 2017",
"creators": [
{
@ -252,12 +253,12 @@ var testCases = [
}
],
"date": "2021-08-16",
"DOI": "10.12688/f1000research.50938.2",
"abstractNote": "Background: In Indonesia, maternal mortality remains high, significantly 61.59% occur in the postnatal period. Postnatal care (PNC) provision is a critical intervention between six hours and 42 days after childbirth and is the primary strategy to reduce maternal mortality rates. However, underutilisation of PNC in Indonesia still remains high, and limited studies have shown the regional disparities of PNC in Indonesia. Methods: This study aims to explore the gaps between regions in PNC service for mothers who have had live births during the last five years in Indonesia. This study was a secondary data analysis study using the Indonesian Demographic and Health Survey (IDHS) in 2017. A total of 13,901 mothers aged 15-49 years having had live births within five years were included. Chi-squared test and binary logistic regression were performed to determine regional disparities in PNC. Results: Results indicated that the prevalence of PNC service utilisation among mothers aged 15-49 years was 70.94%. However, regional gaps in the utilisation of PNC service were indicated. Mothers in the Central of Indonesia have used PNC services 2.54 times compared to mothers in the Eastern of Indonesia (OR = 2.54; 95% CI = 1.77-3.65, p&lt;0.001). Apart from the region, other variables have a positive relationship with PNC service, including wealth quintile, accessibility health facilities, age of children, childbirth order, mother's education, maternal occupation, spouse's age, and spouse's education. Conclusion: The results suggest the need for national policy focuses on service equality, accessible, and reliable implementation to improve postnatal care utilisation among mothers to achieve the maximum results for the Indonesian Universal Health Coverage plan.",
"extra": "Type: article",
"institution": "F1000Research",
"archiveID": "10:153",
"language": "en",
"libraryCatalog": "f1000research.com",
"reportNumber": "10:153",
"repository": "F1000Research",
"rights": "http://creativecommons.org/licenses/by/4.0/",
"shortTitle": "Regional disparities in postnatal care among mothers aged 15-49 years old",
"url": "https://f1000research.com/articles/10-153",
@ -475,7 +476,7 @@ var testCases = [
"url": "https://hrbopenresearch.org/articles/4-87",
"items": [
{
"itemType": "report",
"itemType": "preprint",
"title": "Effectiveness of quality improvement strategies for type 1 diabetes in children and adolescents: a systematic review protocol",
"creators": [
{
@ -525,12 +526,12 @@ var testCases = [
}
],
"date": "2021-08-10",
"DOI": "10.12688/hrbopenres.13223.1",
"abstractNote": "Introduction: Optimal glycaemic control is often a challenge in children and adolescents with type 1 diabetes (T1D). Implementation of patient, clinician or organisation-targeted quality improvement (QI) strategies has been proven to be beneficial in terms of improving glycaemic outcomes in adults living with diabetes. This review aims to assess the effectiveness of such QI interventions in improving glycaemic control, care delivery, and screening rates in children and adolescents with T1D. Methods and analysis: MEDLINE, EMBASE, CINAHL and Cochrane CENTRAL databases will be searched for relevant studies up to January 2021. Trial registries, ClinicalTrials.gov and ICTRP, will also be explored for any ongoing trials of relevance. We will include trials which examine QI strategies as defined by a modified version of the Cochrane Effective Practice and Organisation of Care 2015 Taxonomy in children (&lt;18 years) with a diagnosis of T1D. The primary outcome to be assessed is glycated haemoglobin (HbA1c), although a range of secondary outcomes relating to clinical management, adverse events, healthcare engagement, screening rates and psychosocial parameters will also be assessed. Our primary intention is to generate a best-evidence narrative to summarise and synthesise the resulting studies. If a group of studies are deemed to be highly similar, then a meta-analysis using a random effects model will be considered. Cochrane Risk of Bias 1.0 tool will be applied for quality assessment. All screening, data extraction and quality assessment will be performed by two independent researchers. Dissemination: The results of this review will be disseminated through peer-reviewed publication in order to inform invested partners (e.g., Paediatric Endocrinologists) on the potential of QI strategies to improve glycaemic management and other related health outcomes in children with T1D, thereby guiding best practices in the outpatient management of the disorder. PROSPERO registration number: CRD42021233974 (28/02/2021).",
"extra": "Type: article",
"institution": "HRB Open Research",
"archiveID": "4:87",
"language": "en",
"libraryCatalog": "hrbopenresearch.org",
"reportNumber": "4:87",
"repository": "HRB Open Research",
"rights": "http://creativecommons.org/licenses/by/4.0/",
"shortTitle": "Effectiveness of quality improvement strategies for type 1 diabetes in children and adolescents",
"url": "https://hrbopenresearch.org/articles/4-87",
@ -569,6 +570,7 @@ var testCases = [
},
{
"type": "web",
"defer": true,
"url": "https://f1000research.com/search?q=test",
"items": "multiple"
},
@ -577,7 +579,7 @@ var testCases = [
"url": "https://gatesopenresearch.org/articles/5-122",
"items": [
{
"itemType": "report",
"itemType": "preprint",
"title": "Young infant clinical signs study&shy;&shy;, Pakistan: a data note",
"creators": [
{
@ -612,12 +614,12 @@ var testCases = [
}
],
"date": "2021-08-12",
"DOI": "10.12688/gatesopenres.13317.1",
"abstractNote": "Neonatal sepsis is the leading cause of child death globally with most of these deaths occurring in the first week of life. &nbsp;It is of utmost public health importance that clinical signs predictive of severe illness and need for referral are identified early in the course of illness. From 2002-2005, a multi country trial called the Young Infant Clinical Signs Study (YICSS) was conducted in seven sites across three South-Asian (Bangladesh, India, and Pakistan), two African (Ghana, and South Africa), and one South American (Bolivia) country. The study aimed to develop a simplified algorithm to be used by primary healthcare workers for the identification of sick young infants needing prompt referral and treatment. The main study enrolled 8,889 young infants between the ages of 0-59 days old. This dataset contains observations on 2950 young infants aged 0-59 days from the Pakistan site. The data was collected between 2003-2004 with information on the most prevalent signs and symptoms. The data from this study was used to update the Integrated Management of Childhood Illness guidelines. The World Health Organisation (WHO) seven-sign algorithm has been used in other major community-based trials to study possible serious bacterial infection and its treatment regimens.",
"extra": "Type: article",
"institution": "Gates Open Research",
"archiveID": "5:122",
"language": "en",
"libraryCatalog": "gatesopenresearch.org",
"reportNumber": "5:122",
"repository": "Gates Open Research",
"rights": "http://creativecommons.org/licenses/by/4.0/",
"shortTitle": "Young infant clinical signs study&shy;&shy;, Pakistan",
"url": "https://gatesopenresearch.org/articles/5-122",

Some files were not shown because too many files have changed in this diff Show More