Add support for importing Citavi annotatons (#2351)
This commit is contained in:
parent
d65e4f7f1d
commit
1ad2056674
5 changed files with 601 additions and 2 deletions
|
@ -26,6 +26,7 @@
|
||||||
Components.utils.import("resource://gre/modules/osfile.jsm");
|
Components.utils.import("resource://gre/modules/osfile.jsm");
|
||||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||||
import FilePicker from 'zotero/modules/filePicker';
|
import FilePicker from 'zotero/modules/filePicker';
|
||||||
|
import { ImportCitaviAnnotatons } from 'zotero/import/citavi';
|
||||||
|
|
||||||
/****Zotero_File_Exporter****
|
/****Zotero_File_Exporter****
|
||||||
**
|
**
|
||||||
|
@ -606,7 +607,7 @@ var Zotero_File_Interface = new function() {
|
||||||
importCollection.name = collectionName;
|
importCollection.name = collectionName;
|
||||||
yield importCollection.saveTx();
|
yield importCollection.saveTx();
|
||||||
}
|
}
|
||||||
|
|
||||||
translation.setTranslator(translators[0]);
|
translation.setTranslator(translators[0]);
|
||||||
|
|
||||||
// Show progress popup
|
// Show progress popup
|
||||||
|
@ -660,6 +661,10 @@ var Zotero_File_Interface = new function() {
|
||||||
finally {
|
finally {
|
||||||
yield Zotero.Notifier.commit(notifierQueue);
|
yield Zotero.Notifier.commit(notifierQueue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (translators[0].label.match(/^Citavi (?:[56]) XML/i)) {
|
||||||
|
yield ImportCitaviAnnotatons(translation);
|
||||||
|
}
|
||||||
|
|
||||||
var numItems = translation.newItems.length;
|
var numItems = translation.newItems.length;
|
||||||
|
|
||||||
|
|
156
chrome/content/zotero/import/citavi.js
Normal file
156
chrome/content/zotero/import/citavi.js
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
const parseCitavi5Quads = (quadsRaw) => {
|
||||||
|
return quadsRaw.split('|').map((quadRaw) => {
|
||||||
|
const [PageIndex, IsContainer, X1, Y1, X2, Y2] = quadRaw.split(';');
|
||||||
|
return { PageIndex: parseInt(PageIndex), IsContainer: IsContainer === "True", X1:
|
||||||
|
parseFloat(X1), Y1: parseFloat(Y1), X2: parseFloat(X2), Y2: parseFloat(Y2) };
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const ImportCitaviAnnotatons = async (translation) => {
|
||||||
|
const IDMap = translation._itemSaver._IDMap;
|
||||||
|
const ZU = translation._sandboxZotero.Utilities;
|
||||||
|
const doc = translation._sandboxZotero.getXML();
|
||||||
|
const isCitavi5 = ZU.xpathText(doc, '//CitaviExchangeData/@Version').startsWith('5');
|
||||||
|
var annotationNodes = ZU.xpath(doc, '//Annotations/Annotation');
|
||||||
|
|
||||||
|
const xpathTextOrNull = (...args) => {
|
||||||
|
try {
|
||||||
|
return ZU.xpathText(...args);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const promises = [];
|
||||||
|
|
||||||
|
// no progress report from translator so let's say importing items etc. is 50%
|
||||||
|
const baseProgress = 50;
|
||||||
|
const stageProgress = 50;
|
||||||
|
let progress = baseProgress;
|
||||||
|
translation.getProgress = () => progress;
|
||||||
|
|
||||||
|
for (var i = 0, n = annotationNodes.length; i < n; i++) {
|
||||||
|
const id = ZU.xpathText(annotationNodes[i], '@id');
|
||||||
|
const quadsRaw = ZU.xpathText(annotationNodes[i], './Quads');
|
||||||
|
const locationID = ZU.xpathText(annotationNodes[i], './LocationID');
|
||||||
|
|
||||||
|
const location = ZU.xpath(doc, `//Locations/Location[@${isCitavi5 ? 'ID' : 'id'}='${locationID}']`)[0];
|
||||||
|
const referenceID = ZU.xpathText(location, './ReferenceID');
|
||||||
|
const entityLink = ZU.xpath(doc, `//EntityLinks/EntityLink[TargetID='${id}']`)[0];
|
||||||
|
const entitySourceID = ZU.xpathText(entityLink, './SourceID');
|
||||||
|
const knowledgeItem = ZU.xpath(doc, `//KnowledgeItems/KnowledgeItem[@${isCitavi5 ? 'ID' : 'id'}='${entitySourceID}']`)[0];
|
||||||
|
const keywordsIDsText = ZU.xpathText(doc, `//KnowledgeItemKeywords/OnetoN[starts-with(text(), "${entitySourceID}")]`);
|
||||||
|
const keywords = keywordsIDsText
|
||||||
|
? keywordsIDsText
|
||||||
|
.split(';')
|
||||||
|
.map(keywordText => keywordText.split(':')[0])
|
||||||
|
.slice(1)
|
||||||
|
.map(keywordID => ZU.xpathText(doc, `.//Keyword[@id='${keywordID}']/Name`))
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const createdOn = xpathTextOrNull(knowledgeItem, './CreatedOn');
|
||||||
|
const modifiedOn = xpathTextOrNull(knowledgeItem, './ModifiedOn');
|
||||||
|
const coreStatement = xpathTextOrNull(knowledgeItem, './CoreStatement');
|
||||||
|
const pageRange = xpathTextOrNull(knowledgeItem, './PageRange');
|
||||||
|
const quotationType = xpathTextOrNull(knowledgeItem, './QuotationType');
|
||||||
|
const text = xpathTextOrNull(knowledgeItem, './Text');
|
||||||
|
const itemID = IDMap[referenceID];
|
||||||
|
const item = await Zotero.Items.getAsync(itemID);
|
||||||
|
const quads = isCitavi5 ? parseCitavi5Quads(quadsRaw) : JSON.parse(quadsRaw);
|
||||||
|
|
||||||
|
const itemAttachmentIDs = item.getAttachments();
|
||||||
|
|
||||||
|
if (itemAttachmentIDs.length === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const itemAttachment = await Zotero.Items.getAsync(itemAttachmentIDs[0]);
|
||||||
|
|
||||||
|
const rectsMappedByPage = quads.reduce((acc, quad) => {
|
||||||
|
const pageIndex = parseInt(quad.PageIndex) - 1;
|
||||||
|
if (Number.isNaN(pageIndex)) {
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
const rect = [quad.X1, quad.Y1, quad.X2, quad.Y2];
|
||||||
|
acc.set(pageIndex, acc.has(pageIndex) ? [...acc.get(pageIndex), rect] : [rect]);
|
||||||
|
return acc;
|
||||||
|
}, new Map());
|
||||||
|
|
||||||
|
if (rectsMappedByPage.keys().length === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let annotations = [];
|
||||||
|
|
||||||
|
Array.from(rectsMappedByPage.keys()).forEach((pageIndex, index) => {
|
||||||
|
//for multi-page highlights, we put text & comments on the first highlight
|
||||||
|
const isFirstPage = index === 0;
|
||||||
|
const pageRects = rectsMappedByPage.get(pageIndex);
|
||||||
|
pageRects.sort((a, b) => b[1] - a[1] || a[0] - b[0]);
|
||||||
|
const annotation = {
|
||||||
|
key: Zotero.DataObjectUtilities.generateKey(),
|
||||||
|
type: 'highlight',
|
||||||
|
comment: isFirstPage ? coreStatement : '',
|
||||||
|
text: isFirstPage ? text : '',
|
||||||
|
position: { pageIndex, rects: pageRects },
|
||||||
|
pageLabel: pageRange || '',
|
||||||
|
dateAdded: createdOn,
|
||||||
|
dateModified: modifiedOn,
|
||||||
|
tags: keywords.map(keyword => ({ name: keyword }))
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (quotationType) {
|
||||||
|
default:
|
||||||
|
case '1':
|
||||||
|
// citavi's "direct quotation"
|
||||||
|
annotation.color = '#2ea8e5';
|
||||||
|
break;
|
||||||
|
case '2':
|
||||||
|
// citavi's "indirect quotation"
|
||||||
|
annotation.color = '#a6507b';
|
||||||
|
// special treatment for indirect quotation
|
||||||
|
annotation.text = coreStatement;
|
||||||
|
annotation.comment = text;
|
||||||
|
break;
|
||||||
|
case '3':
|
||||||
|
// citavi's "summary"
|
||||||
|
annotation.color = '#5fb236';
|
||||||
|
break;
|
||||||
|
case '4':
|
||||||
|
// citavi's "comment"
|
||||||
|
annotation.color = '#ff8c19';
|
||||||
|
break;
|
||||||
|
case '5':
|
||||||
|
// citavi's "highlight in yellow"
|
||||||
|
annotation.color = '#ffd400';
|
||||||
|
delete annotation.comment;
|
||||||
|
break;
|
||||||
|
case '6':
|
||||||
|
// citavi's "highlight in red"
|
||||||
|
annotation.color = '#ff6666';
|
||||||
|
delete annotation.comment;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
annotations.push(annotation);
|
||||||
|
});
|
||||||
|
|
||||||
|
annotations = await Zotero.PDFWorker.processCitaviAnnotations(
|
||||||
|
itemAttachment.getFilePath(), annotations
|
||||||
|
);
|
||||||
|
|
||||||
|
annotations.forEach((annotation) => {
|
||||||
|
promises.push(Zotero.Annotations.saveFromJSON(
|
||||||
|
itemAttachment, annotation, { skipSelect: true }
|
||||||
|
));
|
||||||
|
});
|
||||||
|
|
||||||
|
progress = baseProgress + Math.ceil((i / annotationNodes.length) * stageProgress);
|
||||||
|
translation._runHandler('itemDone', []);
|
||||||
|
}
|
||||||
|
await Promise.all(promises);
|
||||||
|
};
|
||||||
|
|
||||||
|
export { ImportCitaviAnnotatons };
|
|
@ -332,6 +332,27 @@ class PDFWorker {
|
||||||
return !!(imported.length || deleted.length);
|
return !!(imported.length || deleted.length);
|
||||||
}, isPriority);
|
}, isPriority);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async processCitaviAnnotations(pdfPath, citaviAnnotations, isPriority, password) {
|
||||||
|
return this._enqueue(async () => {
|
||||||
|
let buf = await OS.File.read(pdfPath, {});
|
||||||
|
buf = new Uint8Array(buf).buffer;
|
||||||
|
try {
|
||||||
|
var annotations = await this._query('importCitavi', {
|
||||||
|
buf, citaviAnnotations, password
|
||||||
|
}, [buf]);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
let error = new Error(`Worker 'importCitavi' failed: ${JSON.stringify({
|
||||||
|
citaviAnnotations,
|
||||||
|
error: e.message
|
||||||
|
})}`);
|
||||||
|
Zotero.logError(error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
return annotations;
|
||||||
|
}, isPriority);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process Mendeley annotations by extending with data from PDF file
|
* Process Mendeley annotations by extending with data from PDF file
|
||||||
|
|
371
test/tests/data/citavi-test-project.ctv6
Normal file
371
test/tests/data/citavi-test-project.ctv6
Normal file
|
@ -0,0 +1,371 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<CitaviExchangeData Version="6.11.0.0" ConnectionIdentifier="citavi-test-project.ctv6" Changeset="10">
|
||||||
|
<ProjectSettings>
|
||||||
|
<AttachmentsFolderPath></AttachmentsFolderPath>
|
||||||
|
<ColorScheme><![CDATA[Blue]]></ColorScheme>
|
||||||
|
<CustomFields>
|
||||||
|
<CustomFieldSettings>
|
||||||
|
<CompareType>Text</CompareType>
|
||||||
|
<DefaultValue />
|
||||||
|
<DropDownStyle>None</DropDownStyle>
|
||||||
|
<PropertyName>CustomField1</PropertyName>
|
||||||
|
</CustomFieldSettings>
|
||||||
|
<CustomFieldSettings>
|
||||||
|
<CompareType>Text</CompareType>
|
||||||
|
<DefaultValue />
|
||||||
|
<DropDownStyle>None</DropDownStyle>
|
||||||
|
<PropertyName>CustomField2</PropertyName>
|
||||||
|
</CustomFieldSettings>
|
||||||
|
<CustomFieldSettings>
|
||||||
|
<CompareType>Text</CompareType>
|
||||||
|
<DefaultValue />
|
||||||
|
<DropDownStyle>None</DropDownStyle>
|
||||||
|
<PropertyName>CustomField3</PropertyName>
|
||||||
|
</CustomFieldSettings>
|
||||||
|
<CustomFieldSettings>
|
||||||
|
<CompareType>Text</CompareType>
|
||||||
|
<DefaultValue />
|
||||||
|
<DropDownStyle>None</DropDownStyle>
|
||||||
|
<PropertyName>CustomField4</PropertyName>
|
||||||
|
</CustomFieldSettings>
|
||||||
|
<CustomFieldSettings>
|
||||||
|
<CompareType>Text</CompareType>
|
||||||
|
<DefaultValue />
|
||||||
|
<DropDownStyle>None</DropDownStyle>
|
||||||
|
<PropertyName>CustomField5</PropertyName>
|
||||||
|
</CustomFieldSettings>
|
||||||
|
<CustomFieldSettings>
|
||||||
|
<CompareType>Text</CompareType>
|
||||||
|
<DefaultValue />
|
||||||
|
<DropDownStyle>None</DropDownStyle>
|
||||||
|
<PropertyName>CustomField6</PropertyName>
|
||||||
|
</CustomFieldSettings>
|
||||||
|
<CustomFieldSettings>
|
||||||
|
<CompareType>Text</CompareType>
|
||||||
|
<DefaultValue />
|
||||||
|
<DropDownStyle>None</DropDownStyle>
|
||||||
|
<PropertyName>CustomField7</PropertyName>
|
||||||
|
</CustomFieldSettings>
|
||||||
|
<CustomFieldSettings>
|
||||||
|
<CompareType>Text</CompareType>
|
||||||
|
<DefaultValue />
|
||||||
|
<DropDownStyle>None</DropDownStyle>
|
||||||
|
<PropertyName>CustomField8</PropertyName>
|
||||||
|
</CustomFieldSettings>
|
||||||
|
<CustomFieldSettings>
|
||||||
|
<CompareType>Text</CompareType>
|
||||||
|
<DefaultValue />
|
||||||
|
<DropDownStyle>None</DropDownStyle>
|
||||||
|
<PropertyName>CustomField9</PropertyName>
|
||||||
|
</CustomFieldSettings>
|
||||||
|
</CustomFields>
|
||||||
|
<Description><![CDATA[]]></Description>
|
||||||
|
<IsUtc>true</IsUtc>
|
||||||
|
<LastChangeTime>18/02/2022 18:26:19</LastChangeTime>
|
||||||
|
</ProjectSettings>
|
||||||
|
<ProjectUserSettings>
|
||||||
|
<LastReferenceId>26ab57d9-2082-4978-bdd2-323e1889381e</LastReferenceId>
|
||||||
|
<ShowCategoryClassification>true</ShowCategoryClassification>
|
||||||
|
<SortOrder>
|
||||||
|
<SortProperty>
|
||||||
|
<ReferencePropertyId>AuthorsOrEditorsOrOrganizations</ReferencePropertyId>
|
||||||
|
<SortDirection>Ascending</SortDirection>
|
||||||
|
</SortProperty>
|
||||||
|
<SortProperty>
|
||||||
|
<ReferencePropertyId>YearResolved</ReferencePropertyId>
|
||||||
|
<SortDirection>Ascending</SortDirection>
|
||||||
|
</SortProperty>
|
||||||
|
<SortProperty>
|
||||||
|
<ReferencePropertyId>Title</ReferencePropertyId>
|
||||||
|
<SortDirection>Ascending</SortDirection>
|
||||||
|
</SortProperty>
|
||||||
|
<SortProperty>
|
||||||
|
<ReferencePropertyId>Volume</ReferencePropertyId>
|
||||||
|
<SortDirection>Ascending</SortDirection>
|
||||||
|
</SortProperty>
|
||||||
|
<SortProperty>
|
||||||
|
<ReferencePropertyId>Number</ReferencePropertyId>
|
||||||
|
<SortDirection>Ascending</SortDirection>
|
||||||
|
</SortProperty>
|
||||||
|
</SortOrder>
|
||||||
|
<SortOrderImport>
|
||||||
|
<SortProperty>
|
||||||
|
<ReferencePropertyId>AuthorsOrEditorsOrOrganizations</ReferencePropertyId>
|
||||||
|
<SortDirection>Ascending</SortDirection>
|
||||||
|
</SortProperty>
|
||||||
|
<SortProperty>
|
||||||
|
<ReferencePropertyId>YearResolved</ReferencePropertyId>
|
||||||
|
<SortDirection>Ascending</SortDirection>
|
||||||
|
</SortProperty>
|
||||||
|
<SortProperty>
|
||||||
|
<ReferencePropertyId>Title</ReferencePropertyId>
|
||||||
|
<SortDirection>Ascending</SortDirection>
|
||||||
|
</SortProperty>
|
||||||
|
<SortProperty>
|
||||||
|
<ReferencePropertyId>Volume</ReferencePropertyId>
|
||||||
|
<SortDirection>Ascending</SortDirection>
|
||||||
|
</SortProperty>
|
||||||
|
<SortProperty>
|
||||||
|
<ReferencePropertyId>Number</ReferencePropertyId>
|
||||||
|
<SortDirection>Ascending</SortDirection>
|
||||||
|
</SortProperty>
|
||||||
|
</SortOrderImport>
|
||||||
|
</ProjectUserSettings>
|
||||||
|
<Keywords>
|
||||||
|
<Keyword id="b07dfd83-135c-4cb6-977b-864c0f59856d">
|
||||||
|
<CreatedBy>_Vexli</CreatedBy>
|
||||||
|
<CreatedOn>2022-02-18T17:25:29</CreatedOn>
|
||||||
|
<ModifiedBy>_Vexli</ModifiedBy>
|
||||||
|
<ModifiedOn>2022-02-18T17:25:29</ModifiedOn>
|
||||||
|
<Name>blue</Name>
|
||||||
|
<Protected>false</Protected>
|
||||||
|
<SortFullName>blue</SortFullName>
|
||||||
|
<UniqueFullName>9b736a9739934a4acd0d222f5edab3ab0209f008</UniqueFullName>
|
||||||
|
</Keyword>
|
||||||
|
<Keyword id="669dc1b6-694b-4eb8-95b2-2c4e8e2f9055">
|
||||||
|
<CreatedBy>_Vexli</CreatedBy>
|
||||||
|
<CreatedOn>2022-02-18T17:26:03</CreatedOn>
|
||||||
|
<ModifiedBy>_Vexli</ModifiedBy>
|
||||||
|
<ModifiedOn>2022-02-18T17:26:03</ModifiedOn>
|
||||||
|
<Name>comment</Name>
|
||||||
|
<Protected>false</Protected>
|
||||||
|
<SortFullName>comment</SortFullName>
|
||||||
|
<UniqueFullName>60fcdfd0c330a0636db449998f8c8f58c7522826</UniqueFullName>
|
||||||
|
</Keyword>
|
||||||
|
<Keyword id="c36f7ee8-02d1-49f2-9cd7-6c96e441542f">
|
||||||
|
<CreatedBy>_Vexli</CreatedBy>
|
||||||
|
<CreatedOn>2022-02-18T17:24:22</CreatedOn>
|
||||||
|
<ModifiedBy>_Vexli</ModifiedBy>
|
||||||
|
<ModifiedOn>2022-02-18T17:24:22</ModifiedOn>
|
||||||
|
<Name>red</Name>
|
||||||
|
<Protected>false</Protected>
|
||||||
|
<SortFullName>red</SortFullName>
|
||||||
|
<UniqueFullName>31a0d7054359216efe7213aea1e910eefc934b74</UniqueFullName>
|
||||||
|
</Keyword>
|
||||||
|
</Keywords>
|
||||||
|
<Persons>
|
||||||
|
<Person id="840dd435-d9e6-4d49-84a8-be953b018194">
|
||||||
|
<CreatedBy>_Vexli</CreatedBy>
|
||||||
|
<CreatedOn>2022-02-18T17:24:05</CreatedOn>
|
||||||
|
<ModifiedBy>_Vexli</ModifiedBy>
|
||||||
|
<ModifiedOn>2022-02-18T17:24:05</ModifiedOn>
|
||||||
|
<LastName>Satoshi Nakamoto</LastName>
|
||||||
|
<Protected>false</Protected>
|
||||||
|
<Sex>0</Sex>
|
||||||
|
<SortFullName>satoshi nakamoto</SortFullName>
|
||||||
|
<UniqueFullName>f1130583fb990563e3e5c23c120140f2dfc011ac</UniqueFullName>
|
||||||
|
</Person>
|
||||||
|
</Persons>
|
||||||
|
<References>
|
||||||
|
<Reference id="26ab57d9-2082-4978-bdd2-323e1889381e">
|
||||||
|
<CreatedBy>_Vexli</CreatedBy>
|
||||||
|
<CreatedOn>2022-02-18T17:15:05</CreatedOn>
|
||||||
|
<ModifiedBy>_Vexli</ModifiedBy>
|
||||||
|
<ModifiedOn>2022-02-18T17:24:05</ModifiedOn>
|
||||||
|
<AbstractComplexity>0</AbstractComplexity>
|
||||||
|
<AbstractSourceTextFormat>0</AbstractSourceTextFormat>
|
||||||
|
<CitationKeyUpdateType>0</CitationKeyUpdateType>
|
||||||
|
<CoverPath>{"$type":"SwissAcademic.Citavi.LinkedResource, SwissAcademic.Citavi","LinkedResourceType":1,"UriString":"d2e3vn4p.jpg","LinkedResourceStatus":8,"Properties":{"$type":"SwissAcademic.Citavi.LinkedResourceProperties, SwissAcademic.Citavi"},"SyncFolderType":0,"IsLocalCloudProjectFileLink":false,"IsCloudRestore":false,"IsCloudCopy":false,"AttachmentFolderWasInFallbackMode":false}</CoverPath>
|
||||||
|
<EvaluationComplexity>0</EvaluationComplexity>
|
||||||
|
<EvaluationSourceTextFormat>0</EvaluationSourceTextFormat>
|
||||||
|
<HasLabel1>false</HasLabel1>
|
||||||
|
<HasLabel2>false</HasLabel2>
|
||||||
|
<PageCount><c>9</c>
|
||||||
|
<in>true</in>
|
||||||
|
<os>9</os>
|
||||||
|
<ps>9</ps></PageCount>
|
||||||
|
<PageRangeNumber>-1</PageRangeNumber>
|
||||||
|
<Rating>0</Rating>
|
||||||
|
<ReferenceType>JournalArticle</ReferenceType>
|
||||||
|
<ShortTitle>Satoshi Nakamoto – Bitcoin: A Peer-to-Peer Electronic Cash</ShortTitle>
|
||||||
|
<ShortTitleUpdateType>0</ShortTitleUpdateType>
|
||||||
|
<StaticIDs>["8657ab2f-a833-4354-92cb-39e8a72a6ec7"]</StaticIDs>
|
||||||
|
<TableOfContentsComplexity>0</TableOfContentsComplexity>
|
||||||
|
<TableOfContentsSourceTextFormat>0</TableOfContentsSourceTextFormat>
|
||||||
|
<Title>Bitcoin: A Peer-to-Peer Electronic Cash System</Title>
|
||||||
|
</Reference>
|
||||||
|
</References>
|
||||||
|
<ReferenceAuthors>
|
||||||
|
<OnetoN>26ab57d9-2082-4978-bdd2-323e1889381e;840dd435-d9e6-4d49-84a8-be953b018194</OnetoN>
|
||||||
|
</ReferenceAuthors>
|
||||||
|
<Locations>
|
||||||
|
<Location id="06737ac8-3637-4534-9cb2-a1e551901ce7">
|
||||||
|
<CreatedBy>_Vexli</CreatedBy>
|
||||||
|
<CreatedOn>2022-02-18T17:17:22</CreatedOn>
|
||||||
|
<ModifiedBy>_Vexli</ModifiedBy>
|
||||||
|
<ModifiedOn>2022-02-18T17:17:22</ModifiedOn>
|
||||||
|
<Address>{"$id":"1","$type":"SwissAcademic.Citavi.LinkedResource, SwissAcademic.Citavi","LinkedResourceType":1,"UriString":"recognizePDF_test_title.pdf","LinkedResourceStatus":8}</Address>
|
||||||
|
<LocationType>0</LocationType>
|
||||||
|
<PreviewBehaviour>0</PreviewBehaviour>
|
||||||
|
<ReferenceID>26ab57d9-2082-4978-bdd2-323e1889381e</ReferenceID>
|
||||||
|
</Location>
|
||||||
|
</Locations>
|
||||||
|
<Annotations>
|
||||||
|
<Annotation id="f08dbaec-6e7e-41f6-b46b-5f9855cd93ac">
|
||||||
|
<CreatedBy>_Vexli</CreatedBy>
|
||||||
|
<CreatedOn>2022-02-18T17:24:15</CreatedOn>
|
||||||
|
<ModifiedBy>_Vexli</ModifiedBy>
|
||||||
|
<ModifiedOn>2022-02-18T17:24:15</ModifiedOn>
|
||||||
|
<LocationID>06737ac8-3637-4534-9cb2-a1e551901ce7</LocationID>
|
||||||
|
<Quads>[{"IsContainer":false,"PageIndex":1,"X1":230.20219999999998,"X2":275.47790585937497,"Y1":578.879472,"Y2":585.816528},{"IsContainer":true,"PageIndex":1,"X1":230.20219999999998,"X2":275.47790585937497,"Y1":578.879472,"Y2":585.816528}]</Quads>
|
||||||
|
<Visible>false</Visible>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation id="7a8c8a33-5902-48f7-8f6d-03e91d852434">
|
||||||
|
<CreatedBy>_Vexli</CreatedBy>
|
||||||
|
<CreatedOn>2022-02-18T17:25:17</CreatedOn>
|
||||||
|
<ModifiedBy>_Vexli</ModifiedBy>
|
||||||
|
<ModifiedOn>2022-02-18T17:25:17</ModifiedOn>
|
||||||
|
<LocationID>06737ac8-3637-4534-9cb2-a1e551901ce7</LocationID>
|
||||||
|
<Quads>[{"IsContainer":false,"PageIndex":1,"X1":228.3353,"X2":461.75599999999912,"Y1":475.340598,"Y2":482.178702},{"IsContainer":false,"PageIndex":1,"X1":146.3,"X2":437.5108999999992,"Y1":463.840598,"Y2":470.678702},{"IsContainer":true,"PageIndex":1,"X1":146.3,"X2":461.75599999999912,"Y1":463.840598,"Y2":482.178702}]</Quads>
|
||||||
|
<Visible>false</Visible>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation id="9d09af5e-a2bc-4188-a5be-8051cafa348c">
|
||||||
|
<CreatedBy>_Vexli</CreatedBy>
|
||||||
|
<CreatedOn>2022-02-18T17:25:35</CreatedOn>
|
||||||
|
<ModifiedBy>_Vexli</ModifiedBy>
|
||||||
|
<ModifiedOn>2022-02-18T17:25:35</ModifiedOn>
|
||||||
|
<LocationID>06737ac8-3637-4534-9cb2-a1e551901ce7</LocationID>
|
||||||
|
<Quads>[{"IsContainer":false,"PageIndex":1,"X1":254.51480000000004,"X2":316.46209999999974,"Y1":532.840598,"Y2":539.67870199999993},{"IsContainer":true,"PageIndex":1,"X1":254.51480000000004,"X2":316.46209999999974,"Y1":532.840598,"Y2":539.67870199999993}]</Quads>
|
||||||
|
<Visible>false</Visible>
|
||||||
|
</Annotation>
|
||||||
|
<Annotation id="73b76ed5-b1ec-433c-afdd-2f1a08168dd5">
|
||||||
|
<CreatedBy>_Vexli</CreatedBy>
|
||||||
|
<CreatedOn>2022-02-18T17:25:56</CreatedOn>
|
||||||
|
<ModifiedBy>_Vexli</ModifiedBy>
|
||||||
|
<ModifiedOn>2022-02-18T17:25:56</ModifiedOn>
|
||||||
|
<LocationID>06737ac8-3637-4534-9cb2-a1e551901ce7</LocationID>
|
||||||
|
<Quads>[{"IsContainer":false,"PageIndex":1,"X1":146.3,"X2":199.49469218750005,"Y1":429.340598,"Y2":436.178702},{"IsContainer":true,"PageIndex":1,"X1":146.3,"X2":199.49469218750005,"Y1":429.340598,"Y2":436.178702}]</Quads>
|
||||||
|
<Visible>false</Visible>
|
||||||
|
</Annotation>
|
||||||
|
</Annotations>
|
||||||
|
<KnowledgeItems>
|
||||||
|
<KnowledgeItem id="6c72f24c-43dc-43d5-9e14-3a192fc9325c">
|
||||||
|
<CreatedBy>_Vexli</CreatedBy>
|
||||||
|
<CreatedOn>2022-02-18T17:24:15</CreatedOn>
|
||||||
|
<ModifiedBy>_Vexli</ModifiedBy>
|
||||||
|
<ModifiedOn>2022-02-18T17:24:24</ModifiedOn>
|
||||||
|
<CoreStatement>peer-to-peer</CoreStatement>
|
||||||
|
<CoreStatementUpdateType>1</CoreStatementUpdateType>
|
||||||
|
<KnowledgeItemType>0</KnowledgeItemType>
|
||||||
|
<PageRangeNumber>-1</PageRangeNumber>
|
||||||
|
<QuotationIndex>0</QuotationIndex>
|
||||||
|
<QuotationType>6</QuotationType>
|
||||||
|
<ReferenceID>26ab57d9-2082-4978-bdd2-323e1889381e</ReferenceID>
|
||||||
|
<Relevance>0</Relevance>
|
||||||
|
<SortFullName>peer-to-peer</SortFullName>
|
||||||
|
<StaticIDs>["52cbbd8c-80d2-4848-9374-6b435d4719bf"]</StaticIDs>
|
||||||
|
<TextSourceTextFormat>0</TextSourceTextFormat>
|
||||||
|
<TextComplexity>0</TextComplexity>
|
||||||
|
</KnowledgeItem>
|
||||||
|
<KnowledgeItem id="e5b80a60-344c-4b29-b888-e97205753567">
|
||||||
|
<CreatedBy>_Vexli</CreatedBy>
|
||||||
|
<CreatedOn>2022-02-18T17:25:17</CreatedOn>
|
||||||
|
<ModifiedBy>_Vexli</ModifiedBy>
|
||||||
|
<ModifiedOn>2022-02-18T17:25:29</ModifiedOn>
|
||||||
|
<CoreStatement>CPU power is controlled by nodes that are …</CoreStatement>
|
||||||
|
<CoreStatementUpdateType>0</CoreStatementUpdateType>
|
||||||
|
<KnowledgeItemType>0</KnowledgeItemType>
|
||||||
|
<PageRangeNumber>-1</PageRangeNumber>
|
||||||
|
<QuotationIndex>1</QuotationIndex>
|
||||||
|
<QuotationType>1</QuotationType>
|
||||||
|
<ReferenceID>26ab57d9-2082-4978-bdd2-323e1889381e</ReferenceID>
|
||||||
|
<Relevance>0</Relevance>
|
||||||
|
<SortFullName>cpu power is controlled by nodes that are …</SortFullName>
|
||||||
|
<StaticIDs>["427b6a09-a648-4453-8317-d7735ec2e83e"]</StaticIDs>
|
||||||
|
<TextSourceTextFormat>0</TextSourceTextFormat>
|
||||||
|
<Text>CPU power is controlled by nodes that are not cooperating to attack the network, they'll generate the longest chain and outpace attackers.</Text>
|
||||||
|
<TextComplexity>0</TextComplexity>
|
||||||
|
</KnowledgeItem>
|
||||||
|
<KnowledgeItem id="32954e21-0303-4365-9f17-ca967e9bb0c7">
|
||||||
|
<CreatedBy>_Vexli</CreatedBy>
|
||||||
|
<CreatedOn>2022-02-18T17:25:35</CreatedOn>
|
||||||
|
<ModifiedBy>_Vexli</ModifiedBy>
|
||||||
|
<ModifiedOn>2022-02-18T17:25:35</ModifiedOn>
|
||||||
|
<CoreStatementUpdateType>0</CoreStatementUpdateType>
|
||||||
|
<KnowledgeItemType>0</KnowledgeItemType>
|
||||||
|
<PageRangeNumber>-1</PageRangeNumber>
|
||||||
|
<QuotationIndex>2</QuotationIndex>
|
||||||
|
<QuotationType>5</QuotationType>
|
||||||
|
<ReferenceID>26ab57d9-2082-4978-bdd2-323e1889381e</ReferenceID>
|
||||||
|
<Relevance>0</Relevance>
|
||||||
|
<SortFullName>_</SortFullName>
|
||||||
|
<StaticIDs>["77efd7da-f246-44dd-80a2-82e9c372b267"]</StaticIDs>
|
||||||
|
<TextSourceTextFormat>0</TextSourceTextFormat>
|
||||||
|
<TextComplexity>0</TextComplexity>
|
||||||
|
</KnowledgeItem>
|
||||||
|
<KnowledgeItem id="a113a66b-2c16-43e2-968c-e530ed9ac5eb">
|
||||||
|
<CreatedBy>_Vexli</CreatedBy>
|
||||||
|
<CreatedOn>2022-02-18T17:25:56</CreatedOn>
|
||||||
|
<ModifiedBy>_Vexli</ModifiedBy>
|
||||||
|
<ModifiedOn>2022-02-18T17:26:15</ModifiedOn>
|
||||||
|
<CoreStatement>proof-of-work</CoreStatement>
|
||||||
|
<CoreStatementUpdateType>1</CoreStatementUpdateType>
|
||||||
|
<KnowledgeItemType>0</KnowledgeItemType>
|
||||||
|
<PageRangeNumber>-1</PageRangeNumber>
|
||||||
|
<QuotationIndex>3</QuotationIndex>
|
||||||
|
<QuotationType>4</QuotationType>
|
||||||
|
<ReferenceID>26ab57d9-2082-4978-bdd2-323e1889381e</ReferenceID>
|
||||||
|
<Relevance>0</Relevance>
|
||||||
|
<SortFullName>proof-of-work</SortFullName>
|
||||||
|
<StaticIDs>["fab8e0a8-f7a6-4785-ad47-5da0d03d64b6"]</StaticIDs>
|
||||||
|
<TextSourceTextFormat>0</TextSourceTextFormat>
|
||||||
|
<Text>This is a comment</Text>
|
||||||
|
<TextComplexity>0</TextComplexity>
|
||||||
|
</KnowledgeItem>
|
||||||
|
</KnowledgeItems>
|
||||||
|
<KnowledgeItemKeywords>
|
||||||
|
<OnetoN>6c72f24c-43dc-43d5-9e14-3a192fc9325c;c36f7ee8-02d1-49f2-9cd7-6c96e441542f:0</OnetoN>
|
||||||
|
<OnetoN>e5b80a60-344c-4b29-b888-e97205753567;b07dfd83-135c-4cb6-977b-864c0f59856d:0</OnetoN>
|
||||||
|
<OnetoN>a113a66b-2c16-43e2-968c-e530ed9ac5eb;669dc1b6-694b-4eb8-95b2-2c4e8e2f9055:0</OnetoN>
|
||||||
|
</KnowledgeItemKeywords>
|
||||||
|
<EntityLinks>
|
||||||
|
<EntityLink id="2e795435-2861-44e7-95b7-7ba1e2cf9703">
|
||||||
|
<CreatedBy>_Vexli</CreatedBy>
|
||||||
|
<CreatedOn>2022-02-18T17:24:15</CreatedOn>
|
||||||
|
<ModifiedBy>_Vexli</ModifiedBy>
|
||||||
|
<ModifiedOn>2022-02-18T17:24:15</ModifiedOn>
|
||||||
|
<Indication>PdfKnowledgeItem</Indication>
|
||||||
|
<RelationType>0</RelationType>
|
||||||
|
<SourceID>6c72f24c-43dc-43d5-9e14-3a192fc9325c</SourceID>
|
||||||
|
<SourceType>KnowledgeItem</SourceType>
|
||||||
|
<TargetID>f08dbaec-6e7e-41f6-b46b-5f9855cd93ac</TargetID>
|
||||||
|
<TargetType>Annotation</TargetType>
|
||||||
|
</EntityLink>
|
||||||
|
<EntityLink id="3d962eb6-2381-4e96-b9f5-36f0746ff3c5">
|
||||||
|
<CreatedBy>_Vexli</CreatedBy>
|
||||||
|
<CreatedOn>2022-02-18T17:25:17</CreatedOn>
|
||||||
|
<ModifiedBy>_Vexli</ModifiedBy>
|
||||||
|
<ModifiedOn>2022-02-18T17:25:17</ModifiedOn>
|
||||||
|
<Indication>PdfKnowledgeItem</Indication>
|
||||||
|
<RelationType>0</RelationType>
|
||||||
|
<SourceID>e5b80a60-344c-4b29-b888-e97205753567</SourceID>
|
||||||
|
<SourceType>KnowledgeItem</SourceType>
|
||||||
|
<TargetID>7a8c8a33-5902-48f7-8f6d-03e91d852434</TargetID>
|
||||||
|
<TargetType>Annotation</TargetType>
|
||||||
|
</EntityLink>
|
||||||
|
<EntityLink id="b9fd1a44-8c96-4e22-ae46-96a3ac06d554">
|
||||||
|
<CreatedBy>_Vexli</CreatedBy>
|
||||||
|
<CreatedOn>2022-02-18T17:25:35</CreatedOn>
|
||||||
|
<ModifiedBy>_Vexli</ModifiedBy>
|
||||||
|
<ModifiedOn>2022-02-18T17:25:35</ModifiedOn>
|
||||||
|
<Indication>PdfKnowledgeItem</Indication>
|
||||||
|
<RelationType>0</RelationType>
|
||||||
|
<SourceID>32954e21-0303-4365-9f17-ca967e9bb0c7</SourceID>
|
||||||
|
<SourceType>KnowledgeItem</SourceType>
|
||||||
|
<TargetID>9d09af5e-a2bc-4188-a5be-8051cafa348c</TargetID>
|
||||||
|
<TargetType>Annotation</TargetType>
|
||||||
|
</EntityLink>
|
||||||
|
<EntityLink id="7e6d73f3-1386-4f0e-a282-a6cf9b676feb">
|
||||||
|
<CreatedBy>_Vexli</CreatedBy>
|
||||||
|
<CreatedOn>2022-02-18T17:25:56</CreatedOn>
|
||||||
|
<ModifiedBy>_Vexli</ModifiedBy>
|
||||||
|
<ModifiedOn>2022-02-18T17:25:56</ModifiedOn>
|
||||||
|
<Indication>PdfKnowledgeItem</Indication>
|
||||||
|
<RelationType>0</RelationType>
|
||||||
|
<SourceID>a113a66b-2c16-43e2-968c-e530ed9ac5eb</SourceID>
|
||||||
|
<SourceType>KnowledgeItem</SourceType>
|
||||||
|
<TargetID>73b76ed5-b1ec-433c-afdd-2f1a08168dd5</TargetID>
|
||||||
|
<TargetType>Annotation</TargetType>
|
||||||
|
</EntityLink>
|
||||||
|
</EntityLinks>
|
||||||
|
</CitaviExchangeData>
|
|
@ -217,4 +217,50 @@ describe("Zotero_File_Interface", function() {
|
||||||
assert.include(str, '<i>B</i>');
|
assert.include(str, '<i>B</i>');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
describe('Citavi annotations', () => {
|
||||||
|
it('should import Citavi', async () => {
|
||||||
|
var testFile = OS.Path.join(getTestDataDirectory().path, 'citavi-test-project.ctv6');
|
||||||
|
|
||||||
|
const promise = waitForItemEvent('add');
|
||||||
|
await win.Zotero_File_Interface.importFile({
|
||||||
|
file: testFile,
|
||||||
|
createNewCollection: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const itemIDs = await promise;
|
||||||
|
const importedItem = await Zotero.Items.getAsync(itemIDs[0]);
|
||||||
|
assert.equal(importedItem.getField('title'), 'Bitcoin: A Peer-to-Peer Electronic Cash System');
|
||||||
|
const importedPDF = await Zotero.Items.getAsync(importedItem.getAttachments()[0]);
|
||||||
|
const annotations = importedPDF.getAnnotations();
|
||||||
|
assert.lengthOf(annotations, 4);
|
||||||
|
const annotationTexts = importedPDF.getAnnotations().map(a => a.annotationText);
|
||||||
|
const annotationPositions = importedPDF.getAnnotations().map(a => JSON.parse(a.annotationPosition));
|
||||||
|
const annotationSortIndexes = importedPDF.getAnnotations().map(a => a.annotationSortIndex);
|
||||||
|
const annotationTags = importedPDF.getAnnotations().map(a => a.getTags());
|
||||||
|
|
||||||
|
assert.sameMembers(annotationTexts, [
|
||||||
|
'peer-to-peer',
|
||||||
|
'CPU power is controlled by nodes that are not cooperating to attack the network, they\'ll generate the longest chain and outpace attackers.',
|
||||||
|
'double-spending',
|
||||||
|
'This is a comment'
|
||||||
|
]);
|
||||||
|
assert.sameMembers(annotationSortIndexes, [
|
||||||
|
'00000|000103|00206',
|
||||||
|
'00000|000723|00309',
|
||||||
|
'00000|000390|00252',
|
||||||
|
'00000|000981|00355'
|
||||||
|
]);
|
||||||
|
assert.sameDeepMembers(annotationPositions, [
|
||||||
|
{ pageIndex: 0, rects: [[230.20219999999998, 578.879472, 275.47790585937497, 585.816528], [230.20219999999998, 578.879472, 275.47790585937497, 585.816528]]},
|
||||||
|
{ pageIndex: 0, rects: [[254.51480000000004, 532.840598, 316.46209999999974, 539.6787019999999], [254.51480000000004, 532.840598, 316.46209999999974, 539.6787019999999]]},
|
||||||
|
{ pageIndex: 0, rects: [[228.3353, 475.340598, 461.7559999999991, 482.178702], [146.3, 463.840598, 437.5108999999992, 470.678702], [146.3, 463.840598, 461.7559999999991, 482.178702]]},
|
||||||
|
{ pageIndex: 0, rects: [[146.3, 429.340598, 199.49469218750005, 436.178702], [146.3, 429.340598, 199.49469218750005, 436.178702]] }
|
||||||
|
]);
|
||||||
|
|
||||||
|
assert.sameDeepMembers(annotationTags, [
|
||||||
|
[{ tag: 'red' }], [], [{ tag: 'blue' }], [{ tag: 'comment' }]
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
Loading…
Add table
Reference in a new issue