Replace attachmentPageIndex with synced-setting-based mechanism
The page index needs to be per-person in group libraries, and it should still work in read-only libraries, so it doesn't make sense to store it on the item. This uses a synced setting in the user's library instead.
This commit is contained in:
parent
3b61214dad
commit
c8ee3196cd
5 changed files with 97 additions and 60 deletions
|
@ -50,7 +50,6 @@ Zotero.Item = function(itemTypeOrID) {
|
||||||
this._attachmentSyncedModificationTime = null;
|
this._attachmentSyncedModificationTime = null;
|
||||||
this._attachmentSyncedHash = null;
|
this._attachmentSyncedHash = null;
|
||||||
this._attachmentLastProcessedModificationTime = null;
|
this._attachmentLastProcessedModificationTime = null;
|
||||||
this._attachmentPageIndex = null;
|
|
||||||
|
|
||||||
// loadCreators
|
// loadCreators
|
||||||
this._creators = [];
|
this._creators = [];
|
||||||
|
@ -342,7 +341,6 @@ Zotero.Item.prototype._parseRowData = function(row) {
|
||||||
case 'attachmentSyncedModificationTime':
|
case 'attachmentSyncedModificationTime':
|
||||||
case 'attachmentSyncedHash':
|
case 'attachmentSyncedHash':
|
||||||
case 'attachmentLastProcessedModificationTime':
|
case 'attachmentLastProcessedModificationTime':
|
||||||
case 'attachmentPageIndex':
|
|
||||||
case 'createdByUserID':
|
case 'createdByUserID':
|
||||||
case 'lastModifiedByUserID':
|
case 'lastModifiedByUserID':
|
||||||
break;
|
break;
|
||||||
|
@ -1728,13 +1726,13 @@ Zotero.Item.prototype._saveData = Zotero.Promise.coroutine(function* (env) {
|
||||||
let sql = "";
|
let sql = "";
|
||||||
let cols = [
|
let cols = [
|
||||||
'parentItemID', 'linkMode', 'contentType', 'charsetID', 'path', 'syncState',
|
'parentItemID', 'linkMode', 'contentType', 'charsetID', 'path', 'syncState',
|
||||||
'storageModTime', 'storageHash', 'lastProcessedModificationTime', 'pageIndex'
|
'storageModTime', 'storageHash', 'lastProcessedModificationTime'
|
||||||
];
|
];
|
||||||
// TODO: Replace with UPSERT after SQLite 3.24.0
|
// TODO: Replace with UPSERT after SQLite 3.24.0
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
sql = "INSERT INTO itemAttachments "
|
sql = "INSERT INTO itemAttachments "
|
||||||
+ "(itemID, " + cols.join(", ") + ") "
|
+ "(itemID, " + cols.join(", ") + ") "
|
||||||
+ "VALUES (?,?,?,?,?,?,?,?,?,?,?)";
|
+ "VALUES (?,?,?,?,?,?,?,?,?,?)";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sql = "UPDATE itemAttachments SET " + cols.join("=?, ") + "=? WHERE itemID=?";
|
sql = "UPDATE itemAttachments SET " + cols.join("=?, ") + "=? WHERE itemID=?";
|
||||||
|
@ -1749,7 +1747,6 @@ Zotero.Item.prototype._saveData = Zotero.Promise.coroutine(function* (env) {
|
||||||
let storageModTime = this.attachmentSyncedModificationTime;
|
let storageModTime = this.attachmentSyncedModificationTime;
|
||||||
let storageHash = this.attachmentSyncedHash;
|
let storageHash = this.attachmentSyncedHash;
|
||||||
let lastProcessedModificationTime = this.attachmentLastProcessedModificationTime;
|
let lastProcessedModificationTime = this.attachmentLastProcessedModificationTime;
|
||||||
let pageIndex = this.attachmentPageIndex;
|
|
||||||
|
|
||||||
if (linkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE && libraryType != 'user') {
|
if (linkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE && libraryType != 'user') {
|
||||||
throw new Error("Linked files can only be added to user library");
|
throw new Error("Linked files can only be added to user library");
|
||||||
|
@ -1765,7 +1762,6 @@ Zotero.Item.prototype._saveData = Zotero.Promise.coroutine(function* (env) {
|
||||||
storageModTime !== undefined ? storageModTime : null,
|
storageModTime !== undefined ? storageModTime : null,
|
||||||
storageHash || null,
|
storageHash || null,
|
||||||
lastProcessedModificationTime || null,
|
lastProcessedModificationTime || null,
|
||||||
typeof pageIndex === 'number' ? pageIndex : null
|
|
||||||
];
|
];
|
||||||
if (isNew) {
|
if (isNew) {
|
||||||
params.unshift(itemID);
|
params.unshift(itemID);
|
||||||
|
@ -3222,7 +3218,7 @@ Zotero.defineProperty(Zotero.Item.prototype, 'attachmentSyncedHash', {
|
||||||
//
|
//
|
||||||
// PDF attachment properties
|
// PDF attachment properties
|
||||||
//
|
//
|
||||||
for (let name of ['lastProcessedModificationTime', 'pageIndex']) {
|
for (let name of ['lastProcessedModificationTime']) {
|
||||||
let prop = 'attachment' + Zotero.Utilities.capitalize(name);
|
let prop = 'attachment' + Zotero.Utilities.capitalize(name);
|
||||||
|
|
||||||
Zotero.defineProperty(Zotero.Item.prototype, prop, {
|
Zotero.defineProperty(Zotero.Item.prototype, prop, {
|
||||||
|
@ -3257,13 +3253,6 @@ for (let name of ['lastProcessedModificationTime', 'pageIndex']) {
|
||||||
+ "-- " + val + " given");
|
+ "-- " + val + " given");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'pageIndex':
|
|
||||||
if (typeof val != 'number') {
|
|
||||||
Zotero.debug(val, 2);
|
|
||||||
throw new Error(`${prop} must be a number`);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (val == this['_' + prop]) {
|
if (val == this['_' + prop]) {
|
||||||
|
@ -3280,6 +3269,59 @@ for (let name of ['lastProcessedModificationTime', 'pageIndex']) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Zotero.Item.prototype.getAttachmentPageIndex = function () {
|
||||||
|
if (!this.isFileAttachment()) {
|
||||||
|
throw new Error("getAttachmentPageIndex() can only be called on file attachments");
|
||||||
|
}
|
||||||
|
|
||||||
|
var id = this._getPageIndexSettingKey();
|
||||||
|
var val = Zotero.SyncedSettings.get(Zotero.Libraries.userLibraryID, id);
|
||||||
|
if (val !== null && typeof val != 'number' || val != parseInt(val)) {
|
||||||
|
Zotero.logError(`Setting contains an invalid attachment page index ('${val}') -- discarding`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return val;
|
||||||
|
};
|
||||||
|
|
||||||
|
Zotero.Item.prototype.setAttachmentPageIndex = async function (val) {
|
||||||
|
if (!this.isFileAttachment()) {
|
||||||
|
throw new Error("setAttachmentPageIndex() can only be called on file attachments");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof val != 'number' || val != parseInt(val)) {
|
||||||
|
Zotero.debug(val, 2);
|
||||||
|
throw new Error(`setAttachmentPageIndex() must be passed an integer`);
|
||||||
|
}
|
||||||
|
|
||||||
|
var id = this._getPageIndexSettingKey();
|
||||||
|
if (val === null) {
|
||||||
|
return Zotero.SyncedSettings.clear(id);
|
||||||
|
}
|
||||||
|
return Zotero.SyncedSettings.set(Zotero.Libraries.userLibraryID, id, val);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// pageIndex_u_ABCD2345
|
||||||
|
Zotero.Item.prototype._getPageIndexSettingKey = function () {
|
||||||
|
var library = Zotero.Libraries.get(this.libraryID);
|
||||||
|
var id = 'pageIndex_';
|
||||||
|
switch (library.libraryType) {
|
||||||
|
case 'user':
|
||||||
|
id += 'u';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'group':
|
||||||
|
id += 'g' + library.libraryTypeID;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error(`Can't get page index id for ${library.libraryType} item`);
|
||||||
|
}
|
||||||
|
id += "_" + this.key;
|
||||||
|
return id;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Modification time of an attachment file
|
* Modification time of an attachment file
|
||||||
*
|
*
|
||||||
|
@ -4560,6 +4602,11 @@ Zotero.Item.prototype._eraseData = Zotero.Promise.coroutine(function* (env) {
|
||||||
|
|
||||||
// Zotero.Sync.EventListeners.ChangeListener needs to know if this was a storage file
|
// Zotero.Sync.EventListeners.ChangeListener needs to know if this was a storage file
|
||||||
env.notifierData[this.id].storageDeleteLog = this.isStoredFileAttachment();
|
env.notifierData[this.id].storageDeleteLog = this.isStoredFileAttachment();
|
||||||
|
|
||||||
|
if (this.isFileAttachment()) {
|
||||||
|
let id = this._getPageIndexSettingKey();
|
||||||
|
yield Zotero.SyncedSettings.clear(Zotero.Libraries.userLibraryID, id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Delete cached file for image annotation
|
// Delete cached file for image annotation
|
||||||
else if (this.isAnnotation()) {
|
else if (this.isAnnotation()) {
|
||||||
|
@ -4760,10 +4807,6 @@ Zotero.Item.prototype.fromJSON = function (json, options = {}) {
|
||||||
this['attachment' + field[0].toUpperCase() + field.substr(1)] = val;
|
this['attachment' + field[0].toUpperCase() + field.substr(1)] = val;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'attachmentPageIndex':
|
|
||||||
this[field] = val;
|
|
||||||
break;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Annotation fields
|
// Annotation fields
|
||||||
//
|
//
|
||||||
|
@ -5032,18 +5075,6 @@ Zotero.Item.prototype.toJSON = function (options = {}) {
|
||||||
//obj.md5 = (yield this.attachmentHash) || null;
|
//obj.md5 = (yield this.attachmentHash) || null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// PDF attachment properties
|
|
||||||
if (this.isFileAttachment()) {
|
|
||||||
let props = ['pageIndex'];
|
|
||||||
for (let prop of props) {
|
|
||||||
let fullProp = 'attachment' + Zotero.Utilities.capitalize(prop);
|
|
||||||
let val = this[fullProp];
|
|
||||||
if (val !== null && val !== undefined) {
|
|
||||||
obj[fullProp] = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notes and embedded attachment notes
|
// Notes and embedded attachment notes
|
||||||
|
|
|
@ -78,7 +78,6 @@ Zotero.Items = function() {
|
||||||
attachmentSyncedModificationTime: "IA.storageModTime AS attachmentSyncedModificationTime",
|
attachmentSyncedModificationTime: "IA.storageModTime AS attachmentSyncedModificationTime",
|
||||||
attachmentSyncedHash: "IA.storageHash AS attachmentSyncedHash",
|
attachmentSyncedHash: "IA.storageHash AS attachmentSyncedHash",
|
||||||
attachmentLastProcessedModificationTime: "IA.lastProcessedModificationTime AS attachmentLastProcessedModificationTime",
|
attachmentLastProcessedModificationTime: "IA.lastProcessedModificationTime AS attachmentLastProcessedModificationTime",
|
||||||
attachmentPageIndex: "IA.pageIndex AS attachmentPageIndex"
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}, {lazy: true});
|
}, {lazy: true});
|
||||||
|
|
|
@ -3241,7 +3241,6 @@ Zotero.Schema = new function(){
|
||||||
|
|
||||||
yield Zotero.DB.queryAsync("ALTER TABLE itemAttachments ADD COLUMN lastProcessedModificationTime INT");
|
yield Zotero.DB.queryAsync("ALTER TABLE itemAttachments ADD COLUMN lastProcessedModificationTime INT");
|
||||||
yield Zotero.DB.queryAsync("CREATE INDEX itemAttachments_lastProcessedModificationTime ON itemAttachments(lastProcessedModificationTime)");
|
yield Zotero.DB.queryAsync("CREATE INDEX itemAttachments_lastProcessedModificationTime ON itemAttachments(lastProcessedModificationTime)");
|
||||||
yield Zotero.DB.queryAsync("ALTER TABLE itemAttachments ADD COLUMN pageIndex INT");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If breaking compatibility or doing anything dangerous, clear minorUpdateFrom
|
// If breaking compatibility or doing anything dangerous, clear minorUpdateFrom
|
||||||
|
|
|
@ -105,7 +105,6 @@ CREATE TABLE itemAttachments (
|
||||||
storageModTime INT,
|
storageModTime INT,
|
||||||
storageHash TEXT,
|
storageHash TEXT,
|
||||||
lastProcessedModificationTime INT,
|
lastProcessedModificationTime INT,
|
||||||
pageIndex INT,
|
|
||||||
FOREIGN KEY (itemID) REFERENCES items(itemID) ON DELETE CASCADE,
|
FOREIGN KEY (itemID) REFERENCES items(itemID) ON DELETE CASCADE,
|
||||||
FOREIGN KEY (parentItemID) REFERENCES items(itemID) ON DELETE CASCADE,
|
FOREIGN KEY (parentItemID) REFERENCES items(itemID) ON DELETE CASCADE,
|
||||||
FOREIGN KEY (charsetID) REFERENCES charsets(charsetID) ON DELETE SET NULL
|
FOREIGN KEY (charsetID) REFERENCES charsets(charsetID) ON DELETE SET NULL
|
||||||
|
|
|
@ -1205,6 +1205,42 @@ describe("Zotero.Item", function () {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe("Attachment Page Index", function () {
|
||||||
|
describe("#getAttachmentPageIndex()", function () {
|
||||||
|
it("should get the page index", async function () {
|
||||||
|
var attachment = await importFileAttachment('test.pdf');
|
||||||
|
assert.isNull(attachment.getAttachmentPageIndex());
|
||||||
|
await attachment.setAttachmentPageIndex(2);
|
||||||
|
assert.equal(2, attachment.getAttachmentPageIndex());
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should throw an error if called on a regular item", async function () {
|
||||||
|
var item = createUnsavedDataObject('item');
|
||||||
|
assert.throws(
|
||||||
|
() => item.getAttachmentPageIndex(),
|
||||||
|
"getAttachmentPageIndex() can only be called on file attachments"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should discard invalid page index", async function () {
|
||||||
|
var attachment = await importFileAttachment('test.pdf');
|
||||||
|
var id = attachment._getPageIndexSettingKey();
|
||||||
|
await Zotero.SyncedSettings.set(Zotero.Libraries.userLibraryID, id, '"1"');
|
||||||
|
assert.isNull(attachment.getAttachmentPageIndex());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should be cleared when item is deleted", async function () {
|
||||||
|
var attachment = await importFileAttachment('test.pdf');
|
||||||
|
await attachment.setAttachmentPageIndex(2);
|
||||||
|
var id = attachment._getPageIndexSettingKey();
|
||||||
|
assert.equal(2, Zotero.SyncedSettings.get(Zotero.Libraries.userLibraryID, id));
|
||||||
|
await attachment.eraseTx();
|
||||||
|
assert.isNull(Zotero.SyncedSettings.get(Zotero.Libraries.userLibraryID, id));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
describe("Annotations", function () {
|
describe("Annotations", function () {
|
||||||
var item;
|
var item;
|
||||||
var attachment;
|
var attachment;
|
||||||
|
@ -1808,13 +1844,6 @@ describe("Zotero.Item", function () {
|
||||||
assert.isNull(json.md5);
|
assert.isNull(json.md5);
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should include PDF properties", async function () {
|
|
||||||
var item = await importPDFAttachment();
|
|
||||||
item.attachmentPageIndex = 4;
|
|
||||||
var json = item.toJSON();
|
|
||||||
assert.propertyVal(json, 'attachmentPageIndex', 4);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("shouldn't include filename, path, or PDF properties for linked_url attachments", function* () {
|
it("shouldn't include filename, path, or PDF properties for linked_url attachments", function* () {
|
||||||
var item = new Zotero.Item('attachment');
|
var item = new Zotero.Item('attachment');
|
||||||
item.attachmentLinkMode = 'linked_url';
|
item.attachmentLinkMode = 'linked_url';
|
||||||
|
@ -1822,7 +1851,6 @@ describe("Zotero.Item", function () {
|
||||||
var json = item.toJSON();
|
var json = item.toJSON();
|
||||||
assert.notProperty(json, "filename");
|
assert.notProperty(json, "filename");
|
||||||
assert.notProperty(json, "path");
|
assert.notProperty(json, "path");
|
||||||
assert.notProperty(json, 'attachmentPageIndex');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shouldn't include various properties on embedded-image attachments", async function () {
|
it("shouldn't include various properties on embedded-image attachments", async function () {
|
||||||
|
@ -1838,7 +1866,6 @@ describe("Zotero.Item", function () {
|
||||||
assert.notProperty(json, 'note');
|
assert.notProperty(json, 'note');
|
||||||
assert.notProperty(json, 'charset');
|
assert.notProperty(json, 'charset');
|
||||||
assert.notProperty(json, 'path');
|
assert.notProperty(json, 'path');
|
||||||
assert.notProperty(json, 'attachmentPageIndex');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -2502,24 +2529,6 @@ describe("Zotero.Item", function () {
|
||||||
assert.propertyVal(item, 'attachmentCharset', 'utf-8');
|
assert.propertyVal(item, 'attachmentCharset', 'utf-8');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should import PDF fields", async function () {
|
|
||||||
var attachment = await importPDFAttachment();
|
|
||||||
var json = attachment.toJSON();
|
|
||||||
|
|
||||||
var item = new Zotero.Item();
|
|
||||||
item.libraryID = attachment.libraryID;
|
|
||||||
item.fromJSON(json, { strict: true });
|
|
||||||
assert.propertyVal(item, 'attachmentPageIndex', null);
|
|
||||||
|
|
||||||
json.attachmentPageIndex = 4;
|
|
||||||
|
|
||||||
item = new Zotero.Item();
|
|
||||||
item.libraryID = attachment.libraryID;
|
|
||||||
item.fromJSON(json, { strict: true });
|
|
||||||
|
|
||||||
assert.propertyVal(item, 'attachmentPageIndex', json.attachmentPageIndex);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("should import annotation fields", async function () {
|
it("should import annotation fields", async function () {
|
||||||
var attachment = await importPDFAttachment();
|
var attachment = await importPDFAttachment();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue