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";
|
"use strict";
|
||||||
|
|
||||||
Zotero.Annotations = new function () {
|
Zotero.Annotations = new function () {
|
||||||
|
Zotero.defineProperty(this, 'ANNOTATION_POSITION_MAX_SIZE', { value: 65000 });
|
||||||
// Keep in sync with items.js::loadAnnotations()
|
// Keep in sync with items.js::loadAnnotations()
|
||||||
Zotero.defineProperty(this, 'ANNOTATION_TYPE_HIGHLIGHT', { value: 1 });
|
Zotero.defineProperty(this, 'ANNOTATION_TYPE_HIGHLIGHT', { value: 1 });
|
||||||
Zotero.defineProperty(this, 'ANNOTATION_TYPE_NOTE', { value: 2 });
|
Zotero.defineProperty(this, 'ANNOTATION_TYPE_NOTE', { value: 2 });
|
||||||
|
@ -234,4 +235,109 @@ Zotero.Annotations = new function () {
|
||||||
|
|
||||||
return item;
|
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);
|
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