Split annotation if position data exceeds the limit
This commit is contained in:
parent
b54466f089
commit
b7f26c47c1
2 changed files with 171 additions and 0 deletions
|
@ -26,6 +26,7 @@
|
|||
"use strict";
|
||||
|
||||
Zotero.Annotations = new function () {
|
||||
Zotero.defineProperty(this, 'ANNOTATION_POSITION_MAX_SIZE', { value: 65000 });
|
||||
// Keep in sync with items.js::loadAnnotations()
|
||||
Zotero.defineProperty(this, 'ANNOTATION_TYPE_HIGHLIGHT', { value: 1 });
|
||||
Zotero.defineProperty(this, 'ANNOTATION_TYPE_NOTE', { value: 2 });
|
||||
|
@ -234,4 +235,109 @@ Zotero.Annotations = new function () {
|
|||
|
||||
return item;
|
||||
};
|
||||
|
||||
/**
|
||||
* Split annotation if position exceed the limit
|
||||
*
|
||||
* @param {Object} annotation
|
||||
* @returns {Array<Object>} annotations
|
||||
*/
|
||||
this.splitAnnotationJSON = function (annotation) {
|
||||
let splitAnnotations = [];
|
||||
let tmpAnnotation = null;
|
||||
let totalLength = 0;
|
||||
if (annotation.position.rects) {
|
||||
for (let i = 0; i < annotation.position.rects.length; i++) {
|
||||
let rect = annotation.position.rects[i];
|
||||
if (!tmpAnnotation) {
|
||||
tmpAnnotation = JSON.parse(JSON.stringify(annotation));
|
||||
tmpAnnotation.key = Zotero.DataObjectUtilities.generateKey();
|
||||
tmpAnnotation.position.rects = [];
|
||||
totalLength = JSON.stringify(tmpAnnotation.position).length;
|
||||
}
|
||||
// [],
|
||||
let length = rect.join(',').length + 3;
|
||||
if (totalLength + length <= this.ANNOTATION_POSITION_MAX_SIZE) {
|
||||
tmpAnnotation.position.rects.push(rect);
|
||||
totalLength += length;
|
||||
}
|
||||
else if (!tmpAnnotation.position.rects.length) {
|
||||
throw new Error(`Cannot fit single 'rect' into 'position'`);
|
||||
}
|
||||
else {
|
||||
splitAnnotations.push(tmpAnnotation);
|
||||
tmpAnnotation = null;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
if (tmpAnnotation) {
|
||||
splitAnnotations.push(tmpAnnotation);
|
||||
}
|
||||
}
|
||||
else if (annotation.position.paths) {
|
||||
for (let i = 0; i < annotation.position.paths.length; i++) {
|
||||
let path = annotation.position.paths[i];
|
||||
for (let j = 0; j < path.length; j += 2) {
|
||||
if (!tmpAnnotation) {
|
||||
tmpAnnotation = JSON.parse(JSON.stringify(annotation));
|
||||
tmpAnnotation.key = Zotero.DataObjectUtilities.generateKey();
|
||||
tmpAnnotation.position.paths = [[]];
|
||||
totalLength = JSON.stringify(tmpAnnotation.position).length;
|
||||
}
|
||||
let point = [path[j], path[j + 1]];
|
||||
// 1,2,
|
||||
let length = point.join(',').length + 1;
|
||||
if (totalLength + length <= this.ANNOTATION_POSITION_MAX_SIZE) {
|
||||
tmpAnnotation.position.paths[tmpAnnotation.position.paths.length - 1].push(...point);
|
||||
totalLength += length;
|
||||
}
|
||||
else if (tmpAnnotation.position.paths.length === 1
|
||||
&& !tmpAnnotation.position.paths[tmpAnnotation.position.paths.length - 1].length) {
|
||||
throw new Error(`Cannot fit single point into 'position'`);
|
||||
}
|
||||
else {
|
||||
splitAnnotations.push(tmpAnnotation);
|
||||
tmpAnnotation = null;
|
||||
j -= 2;
|
||||
}
|
||||
}
|
||||
// If not the last path
|
||||
if (i !== annotation.position.paths.length - 1) {
|
||||
// [],
|
||||
totalLength += 3;
|
||||
tmpAnnotation.position.paths.push([]);
|
||||
}
|
||||
}
|
||||
if (tmpAnnotation) {
|
||||
splitAnnotations.push(tmpAnnotation);
|
||||
}
|
||||
}
|
||||
return splitAnnotations;
|
||||
};
|
||||
|
||||
/**
|
||||
* Split annotations
|
||||
*
|
||||
* @param {Zotero.Item[]} items
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
this.splitAnnotations = async function (items) {
|
||||
if (!Array.isArray(items)) {
|
||||
items = [items];
|
||||
}
|
||||
if (!items.every(item => item.isAnnotation())) {
|
||||
throw new Error('All items must be annotations');
|
||||
}
|
||||
for (let item of items) {
|
||||
if (item.annotationPosition.length <= this.ANNOTATION_POSITION_MAX_SIZE) {
|
||||
continue;
|
||||
}
|
||||
let annotation = await this.toJSON(item);
|
||||
let splitAnnotations = this.splitAnnotationJSON(annotation);
|
||||
for (let splitAnnotation of splitAnnotations) {
|
||||
await this.saveFromJSON(item.parentItem, splitAnnotation);
|
||||
}
|
||||
await item.eraseTx();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -338,4 +338,69 @@ describe("Zotero.Annotations", function() {
|
|||
assert.isNull(annotation.annotationPageLabel);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#splitAnnotations()", function () {
|
||||
it("should split a highlight annotation", async function () {
|
||||
await Zotero.Items.erase(attachment.getAnnotations().map(x => x.id));
|
||||
let annotation = await createAnnotation('highlight', attachment);
|
||||
let position = {
|
||||
pageIndex: 1,
|
||||
rects: []
|
||||
};
|
||||
for (let i = 0; i < 10000; i++) {
|
||||
position.rects.push([100, 200, 100, 200]);
|
||||
}
|
||||
annotation.annotationPosition = JSON.stringify(position);
|
||||
annotation.annotationText = 'test';
|
||||
await annotation.saveTx();
|
||||
|
||||
await Zotero.Annotations.splitAnnotations([annotation]);
|
||||
|
||||
let splitAnnotations = attachment.getAnnotations();
|
||||
assert.equal(splitAnnotations.length, 3);
|
||||
assert.equal(splitAnnotations[0].annotationPosition.length, 64987);
|
||||
assert.equal(splitAnnotations[1].annotationPosition.length, 64987);
|
||||
assert.equal(splitAnnotations[2].annotationPosition.length, 50101);
|
||||
assert.equal(splitAnnotations[0].annotationText, 'test');
|
||||
assert.equal(splitAnnotations[1].annotationText, 'test');
|
||||
assert.equal(splitAnnotations[2].annotationText, 'test');
|
||||
|
||||
assert.equal(Zotero.Items.get(annotation.id), false);
|
||||
await Zotero.Items.erase(splitAnnotations.map(x => x.id));
|
||||
});
|
||||
|
||||
it("should split an ink annotation", async function () {
|
||||
await Zotero.Items.erase(attachment.getAnnotations().map(x => x.id));
|
||||
let annotation = await createAnnotation('ink', attachment);
|
||||
let position = {
|
||||
pageIndex: 1,
|
||||
width: 2,
|
||||
paths: []
|
||||
};
|
||||
for (let i = 0; i < 100; i++) {
|
||||
let path = [];
|
||||
for (let j = 0; j < 200; j++) {
|
||||
path.push(100, 200);
|
||||
}
|
||||
position.paths.push(path);
|
||||
}
|
||||
annotation.annotationPosition = JSON.stringify(position);
|
||||
annotation.annotationComment = 'test';
|
||||
await annotation.saveTx();
|
||||
|
||||
await Zotero.Annotations.splitAnnotations([annotation]);
|
||||
|
||||
let splitAnnotations = attachment.getAnnotations();
|
||||
assert.equal(splitAnnotations.length, 3);
|
||||
assert.equal(splitAnnotations[0].annotationPosition.length, 64957);
|
||||
assert.equal(splitAnnotations[1].annotationPosition.length, 64951);
|
||||
assert.equal(splitAnnotations[2].annotationPosition.length, 30401);
|
||||
assert.equal(splitAnnotations[0].annotationComment, 'test');
|
||||
assert.equal(splitAnnotations[1].annotationComment, 'test');
|
||||
assert.equal(splitAnnotations[2].annotationComment, 'test');
|
||||
|
||||
assert.equal(Zotero.Items.get(annotation.id), false);
|
||||
await Zotero.Items.erase(splitAnnotations.map(x => x.id));
|
||||
});
|
||||
});
|
||||
})
|
Loading…
Reference in a new issue