Skip to content

Commit

Permalink
Fixes to Citation editor, syncing between tabs and translations for Z…
Browse files Browse the repository at this point in the history
…otero 7 (#308)

* Translation fixes

* Get the title-related popups to work in the citation editor

* Get tooltips to work for PIDRows in citation editor

* Cleanup

* Fix citation editor not re-rendering when refreshing metadata

* Make the citation editor more informative

* Improve button display in citation editor

* Add support for adding PIDs in citation editor

* Finally make showing/hiding PIDRows stateful

* Cleanup

* Binding fixes

* Fix error `Cannot wrap non-regular items` when clicking on raw attachments (without parent items) in the Zotero pane

* Reduce reliance on useEffect

* Cleanup

* Cleanup and prevent "blinking" by enforcing UUIDs for citations

* Improve citation row line clamping logic

* Improve PID row ordering and management

* Improve line count recalculation triggers

* Improve toolbarbutton focus-ring

* Improve keyboard navigation slightly

* CSS cleanup and fixes

* Fix grippy drag handle

* Optimize drag and drop

* Slight tweaks

* Fix and improve PID add menu

* Fix line height calculation to account for "normal" case

* Fix multiple additions of menupopups and stylesheets by relying entirely on ztoolkit

* Fix reference to ztoolkit for CitationEditor

* Style refresh for progress windows

* Further menu-related optimizations

* Fix rows staying draggable after drag ends

* Update zotero-types to remove old patch

* Refactor `zoteroPopup.showSubmenu`

* Refactor `availablePIDTypes`

* Update zotero-plugin-tolkit (and further streamline menu creation)

* Cleanup

* Improve reporting that syncing single citation with Wikidata is not supported

* Added comments on React lifecycle in Zotero overlay
  • Loading branch information
thebluepotato authored Dec 31, 2024
1 parent 42516af commit c4870d2
Show file tree
Hide file tree
Showing 60 changed files with 893 additions and 1,008 deletions.
61 changes: 23 additions & 38 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"homepage": "https://github.com/diegodlh/zotero-cita",
"dependencies": {
"@react-hook/resize-observer": "^2.0.2",
"core-js": "^3.39.0",
"openalex-sdk": "^1.1.6",
"prop-types": "^15.7.2",
"quickstatements-to-wikibase-edit": "^1.2.1",
Expand All @@ -47,9 +48,10 @@
"semver-parser": "^4.1.6",
"wikibase-edit": "^7.0.4",
"wikibase-sdk": "^10.0.2",
"zotero-plugin-toolkit": "^4.0.6"
"zotero-plugin-toolkit": "^4.0.14"
},
"devDependencies": {
"@types/core-js": "^2.5.8",
"@types/language-tags": "^1.0.4",
"@types/lodash": "^4.17.9",
"@types/node": "^20.10.4",
Expand All @@ -64,7 +66,7 @@
"typescript": "^5.3.3",
"typescript-eslint": "^7.14.1",
"zotero-plugin-scaffold": "^0.0.34",
"zotero-types": "^3.0.1"
"zotero-types": "^3.0.3"
},
"engines": {
"npm": ">=8.1"
Expand Down
23 changes: 0 additions & 23 deletions patches/zotero-types+3.0.1.patch

This file was deleted.

14 changes: 8 additions & 6 deletions src/cita/PID.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export default class PID {
return rawID ? `${this.type}:${rawID}` : undefined;
}

static readonly allTypes: PIDType[] = [
static readonly allTypes: Set<PIDType> = new Set([
"DOI",
"ISBN",
"QID",
Expand All @@ -134,9 +134,9 @@ export default class PID {
"CorpusID",
"PMID",
"PMCID",
];
]);

static readonly showable: PIDType[] = [
static readonly showable: Set<PIDType> = new Set([
"DOI",
"ISBN",
"QID",
Expand All @@ -145,15 +145,17 @@ export default class PID {
"OpenAlex",
"CorpusID",
// Don't show PMID or PMCID because we can't fetch citations from them
];
]);

static readonly fetchable: PIDType[] = [
static readonly alwaysShown: Set<PIDType> = new Set(["DOI", "QID"]);

static readonly fetchable: Set<PIDType> = new Set([
"QID",
"OMID",
"OpenAlex",
"DOI",
"CorpusID",
];
]);

static isEqual(a: PID, b: PID): boolean {
if (a.type !== b.type) return false;
Expand Down
41 changes: 39 additions & 2 deletions src/cita/citation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ class Citation {
item,
ocis,
zotero,
uuid,
}: {
item:
| Zotero.Item
Expand All @@ -48,6 +49,7 @@ class Citation {
};
ocis: string[];
zotero?: string;
uuid?: string;
},
// index, // knowing the index in the citationList may be important
sourceItem: SourceItemWrapper, // should the parent CitationList (with its source item and methods to save) be passed instead?
Expand Down Expand Up @@ -94,8 +96,8 @@ class Citation {
// // crosref does provide a citation key which seems to have some ordinal information
// // but I say to leave this out for now

// generate a unique identifier for this citation
this.uuid = crypto.randomUUID();
// generate a unique identifier for this citation if needed
this.uuid = uuid ?? crypto.randomUUID();
}

addCreator(creatorType: any, creatorName: string) {
Expand Down Expand Up @@ -235,6 +237,7 @@ class Citation {
item: this.target.toJSON(),
ocis: this.ocis.map((oci) => oci.oci),
zotero: this.target.key,
uuid: this.uuid,
};
}

Expand All @@ -249,6 +252,40 @@ class Citation {
// I need access to the parent CitationList
}

wikidataSync(index: number) {
const syncable = this.source.qid && this.target.qid;
const oci = this.getOCI("wikidata");
if (oci) {
if (oci.valid) {
this.resolveOCI("wikidata");
} else {
// oci is invalid, i.e., citing or cited id do not match with
// local source or target id
Services.prompt.alert(
window as mozIDOMWindowProxy,
Wikicite.getString("wikicite.oci.mismatch.title"),
Wikicite.formatString("wikicite.oci.mismatch.message", [
oci.supplierName.charAt(0).toUpperCase() +
oci.supplierName.slice(1),
oci.idType.toUpperCase(),
oci.citingId,
oci.citedId,
]),
);
}
} else if (syncable) {
this.source.syncWithWikidata(index);
// Note: this function was taken from CitationRow.tsx
// Yet, calling syncWithWikidata with an index is not implemented anyway
} else {
Services.prompt.alert(
window as mozIDOMWindowProxy,
Wikicite.getString("wikicite.citation.sync.error"),
Wikicite.getString("wikicite.citation.sync.error.qid"),
);
}
}

/**
* Automatically link citation with matching Zotero item
* @param {Object} [matcher] Initialized Matcher object for batch operations
Expand Down
3 changes: 0 additions & 3 deletions src/cita/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
import Citations from "./citations";
import Wikicite from "./wikicite";
import WikiciteChrome from "./wikiciteChrome";
import Wikidata from "./wikidata";
import zoteroOverlay from "./zoteroOverlay";
/* global window */

Expand Down
51 changes: 42 additions & 9 deletions src/cita/itemWrapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import Semantic from "./semantic";
import Wikicite from "./wikicite";
import Wikidata from "./wikidata";
import PID from "./PID";
import "core-js/proposals/set-methods-v2";

// maybe pass a save handler to the constructor
// to be run after each setter. This would be the item's saveTx
Expand Down Expand Up @@ -111,31 +112,63 @@ export default class ItemWrapper {
);
}

get validPIDTypes(): PIDType[] {
const pidTypes: PIDType[] = [];
for (const type of PID.showable) {
/**
* All PID Types that are valid for the item type
*/
get validPIDTypes(): Set<PIDType> {
const pidTypes = new Set<PIDType>();
for (const type of PID.allTypes) {
switch (type) {
case "ISBN":
if (this.isValidField(type)) {
pidTypes.push(type);
pidTypes.add(type);
}
break;
case "arXiv":
if (this.item.itemType === "preprint") {
pidTypes.push(type);
pidTypes.add(type);
}
break;
default:
pidTypes.push(type);
pidTypes.add(type);
}
}
return pidTypes;
}

/**
* All PID Types that the item has a PID for
*/
get availablePIDTypes(): Set<PIDType> {
return new Set(
Array.from(PID.allTypes.values()).filter((type: PIDType) =>
this.getPID(type),
),
);
}

/**
* All PID Types that the item has a PID for and are valid for the item type
*/
get validAvailablePIDTypes(): Set<PIDType> {
return this.validPIDTypes.intersection(this.availablePIDTypes);
}

get allTypesToShow(): Set<PIDType> {
return PID.alwaysShown.union(
PID.showable.intersection(this.validAvailablePIDTypes),
);
}

canFetchPid(type: PIDType) {
return PID.fetchable.includes(type);
return PID.fetchable.has(type);
}

/**
* Fetch a PID for the item.
* @param type The PID type to fetch
* @param autosave Whether to save the item after fetching the PID
*/
async fetchPID(type: PIDType, autosave = true) {
if (!this.canFetchPid(type)) {
Services.prompt.alert(
Expand Down Expand Up @@ -221,8 +254,8 @@ export default class ItemWrapper {
}
}

/*
* Get PID (QID, DOI, ISBN, OMID, ...) from item. If it doesn't have this PID, return undefined
/**
* Get PID (QID, DOI, ISBN, OMID, ...) from item. If it doesn't have this PID, return null
*/
getPID(type: PIDType, clean = false): PID | null {
let _pid: string;
Expand Down
Loading

0 comments on commit c4870d2

Please sign in to comment.