Add more features to the file renaming functionality (#4424)
* New `attachmentTitle` field, returns the title of the current attachment (or the future title of the attachment being created) * New function `match` to enable testing values with a regex. * New function `start` to enable truncating from the beginning. * Ignore new line characters in the template for easier editing. * Avoid repeated characters when changing case (snake/dash) * Increase the size of the template input field. Closes #3252
This commit is contained in:
parent
29f4aece24
commit
00ae8bb9b2
7 changed files with 205 additions and 107 deletions
|
@ -43,26 +43,27 @@ Zotero_Preferences.FileRenaming = {
|
|||
this._itemsView.onSelect.removeListener(this._updatePreview);
|
||||
},
|
||||
|
||||
getActiveTopLevelItem() {
|
||||
const selectedItem = Zotero.getActiveZoteroPane()?.getSelectedItems()?.[0];
|
||||
getActiveItem() {
|
||||
let selectedItem = Zotero.getActiveZoteroPane()?.getSelectedItems()?.[0];
|
||||
if (selectedItem) {
|
||||
if (selectedItem.isRegularItem() && !selectedItem.parentKey) {
|
||||
return [selectedItem, this.defaultExt];
|
||||
return [selectedItem, this.defaultExt, ''];
|
||||
}
|
||||
if (selectedItem.isFileAttachment() && selectedItem.parentKey) {
|
||||
const path = selectedItem.getFilePath();
|
||||
const ext = Zotero.File.getExtension(Zotero.File.pathToFile(path));
|
||||
return [Zotero.Items.getByLibraryAndKey(selectedItem.libraryID, selectedItem.parentKey), ext ?? this.defaultExt];
|
||||
if (selectedItem.isFileAttachment()) {
|
||||
let path = selectedItem.getFilePath();
|
||||
let ext = Zotero.File.getExtension(Zotero.File.pathToFile(path));
|
||||
let parentItem = Zotero.Items.getByLibraryAndKey(selectedItem.libraryID, selectedItem.parentKey);
|
||||
return [parentItem, ext ?? this.defaultExt, selectedItem.getField('title')];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
updatePreview() {
|
||||
const [item, ext] = this.getActiveTopLevelItem() ?? [this.mockItem ?? this.makeMockItem(), this.defaultExt];
|
||||
const tpl = document.getElementById('file-renaming-format-template').value;
|
||||
const preview = Zotero.Attachments.getFileBaseNameFromItem(item, tpl);
|
||||
async updatePreview() {
|
||||
const [item, ext, attachmentTitle] = this.getActiveItem() ?? [this.mockItem ?? this.makeMockItem(), this.defaultExt, ''];
|
||||
const formatString = document.getElementById('file-renaming-format-template').value;
|
||||
const preview = Zotero.Attachments.getFileBaseNameFromItem(item, { formatString, attachmentTitle });
|
||||
document.getElementById('file-renaming-format-preview').innerText = `${preview}.${ext}`;
|
||||
},
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
aria-labelledby="file-renaming-format-template-label"
|
||||
id="file-renaming-format-template"
|
||||
preference="extensions.zotero.attachmentRenameTemplate"
|
||||
rows="3"
|
||||
rows="8"
|
||||
/>
|
||||
<html:label id="file-renaming-format-preview-label">
|
||||
<html:h2
|
||||
|
|
|
@ -582,7 +582,7 @@ Zotero.Attachments = new function () {
|
|||
// Rename attachment
|
||||
if (renameIfAllowedType && !fileBaseName && this.isRenameAllowedForType(contentType)) {
|
||||
let parentItem = Zotero.Items.get(parentItemID);
|
||||
fileBaseName = this.getFileBaseNameFromItem(parentItem);
|
||||
fileBaseName = this.getFileBaseNameFromItem(parentItem, { attachmentTitle: title });
|
||||
}
|
||||
if (fileBaseName) {
|
||||
let ext = this._getExtensionFromURL(url, contentType);
|
||||
|
@ -1769,13 +1769,12 @@ Zotero.Attachments = new function () {
|
|||
* @return {Zotero.Item|false} - New Zotero.Item, or false if unsuccessful
|
||||
*/
|
||||
this.addFileFromURLs = async function (item, urlResolvers, options = {}) {
|
||||
var fileBaseName = this.getFileBaseNameFromItem(item);
|
||||
var tmpDir;
|
||||
var tmpFile;
|
||||
var attachmentItem = false;
|
||||
try {
|
||||
tmpDir = (await this.createTemporaryStorageDirectory()).path;
|
||||
tmpFile = OS.Path.join(tmpDir, fileBaseName + '.tmp');
|
||||
tmpFile = OS.Path.join(tmpDir, 'file.tmp');
|
||||
let { title, mimeType, url, props } = await this.downloadFirstAvailableFile(
|
||||
urlResolvers,
|
||||
tmpFile,
|
||||
|
@ -1794,13 +1793,15 @@ Zotero.Attachments = new function () {
|
|||
if (!this.FIND_AVAILABLE_FILE_TYPES.includes(mimeType)) {
|
||||
throw new Error(`Resolved file is unsupported type ${mimeType}`);
|
||||
}
|
||||
let filename = fileBaseName + '.' + (Zotero.MIME.getPrimaryExtension(mimeType) || 'dat');
|
||||
await IOUtils.move(tmpFile, PathUtils.join(tmpDir, filename));
|
||||
title = title || _getTitleFromVersion(props.articleVersion);
|
||||
let fileBaseName = this.getFileBaseNameFromItem(item, { attachmentTitle: title });
|
||||
let ext = Zotero.MIME.getPrimaryExtension(mimeType) || 'dat';
|
||||
let filename = await Zotero.File.rename(tmpFile, `${fileBaseName}.${ext}`);
|
||||
attachmentItem = await this.createURLAttachmentFromTemporaryStorageDirectory({
|
||||
directory: tmpDir,
|
||||
libraryID: item.libraryID,
|
||||
filename,
|
||||
title: title || _getTitleFromVersion(props.articleVersion),
|
||||
title,
|
||||
url,
|
||||
contentType: mimeType,
|
||||
parentItemID: item.id
|
||||
|
@ -2207,10 +2208,16 @@ Zotero.Attachments = new function () {
|
|||
* @param {Zotero.Item} item
|
||||
* @param {String} formatString
|
||||
*/
|
||||
this.getFileBaseNameFromItem = function (item, formatString) {
|
||||
this.getFileBaseNameFromItem = function (item, options = {}) {
|
||||
if (!(item instanceof Zotero.Item)) {
|
||||
throw new Error("'item' must be a Zotero.Item");
|
||||
}
|
||||
if (typeof options === 'string') {
|
||||
Zotero.warn("Zotero.Attachments.getFileBaseNameFromItem(item, formatString) is deprecated -- use Zotero.Attachments(item, options)");
|
||||
options = { formatString: options };
|
||||
}
|
||||
|
||||
let { formatString = null, attachmentTitle = '' } = options;
|
||||
|
||||
if (!formatString) {
|
||||
formatString = Zotero.Prefs.get('attachmentRenameTemplate');
|
||||
|
@ -2219,7 +2226,7 @@ Zotero.Attachments = new function () {
|
|||
let chunks = [];
|
||||
let protectedLiterals = new Set();
|
||||
|
||||
formatString = formatString.trim();
|
||||
formatString = formatString.replace(/\r?\n|\r/g, "").trim();
|
||||
|
||||
const getSlicedCreatorsOfType = (creatorType, slice) => {
|
||||
let creatorTypeIDs;
|
||||
|
@ -2253,7 +2260,7 @@ Zotero.Attachments = new function () {
|
|||
};
|
||||
|
||||
|
||||
const common = (value, { truncate = false, prefix = '', suffix = '', replaceFrom = '', replaceTo = '', regexOpts = '', case: textCase = '' } = {}) => {
|
||||
const common = (value, { start = false, truncate = false, prefix = '', suffix = '', match = '', replaceFrom = '', replaceTo = '', regexOpts = 'i', case: textCase = '' } = {}) => {
|
||||
if (value === '' || value === null || typeof value === 'undefined') {
|
||||
return '';
|
||||
}
|
||||
|
@ -2266,6 +2273,17 @@ Zotero.Attachments = new function () {
|
|||
suffix = '';
|
||||
}
|
||||
|
||||
// match overrides all other options and returns immediately
|
||||
if (match) {
|
||||
try {
|
||||
let matchResult = value.match(new RegExp(match, regexOpts));
|
||||
return matchResult ? matchResult[0] : '';
|
||||
}
|
||||
catch (_e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
if (protectedLiterals.size > 0) {
|
||||
// escape protected literals in the format string with \
|
||||
value = value.replace(
|
||||
|
@ -2274,8 +2292,12 @@ Zotero.Attachments = new function () {
|
|||
);
|
||||
}
|
||||
|
||||
if (start) {
|
||||
value = value.substring(start);
|
||||
}
|
||||
|
||||
if (truncate) {
|
||||
value = value.substr(0, truncate);
|
||||
value = value.substring(0, truncate);
|
||||
}
|
||||
|
||||
value = value.trim();
|
||||
|
@ -2284,7 +2306,12 @@ Zotero.Attachments = new function () {
|
|||
let affixed = false;
|
||||
|
||||
if (replaceFrom) {
|
||||
value = value.replace(new RegExp(replaceFrom, regexOpts), replaceTo);
|
||||
try {
|
||||
value = value.replace(new RegExp(replaceFrom, regexOpts), replaceTo);
|
||||
}
|
||||
catch (_e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
if (prefix && !value.startsWith(prefix)) {
|
||||
value = prefix + value;
|
||||
|
@ -2313,9 +2340,11 @@ Zotero.Attachments = new function () {
|
|||
value = Zotero.Utilities.capitalizeTitle(value, true);
|
||||
break;
|
||||
case 'hyphen':
|
||||
value = value.replace(/\s+-/g, '-').replace(/-\s+/g, '-');
|
||||
value = value.toLowerCase().replace(/\s+/g, '-');
|
||||
break;
|
||||
case 'snake':
|
||||
value = value.replace(/\s+_/g, '_').replace(/_\s+/g, '_');
|
||||
value = value.toLowerCase().replace(/\s+/g, '_');
|
||||
break;
|
||||
case 'camel':
|
||||
|
@ -2392,8 +2421,9 @@ Zotero.Attachments = new function () {
|
|||
item.getField('firstCreator', true, true), args
|
||||
);
|
||||
|
||||
const vars = { ...fields, ...creatorFields, firstCreator, itemType, year };
|
||||
const attachmentTitleFn = args => common(attachmentTitle ?? '', args);
|
||||
|
||||
const vars = { ...fields, ...creatorFields, attachmentTitle: attachmentTitleFn, firstCreator, itemType, year };
|
||||
|
||||
// Final name is generated twice. In the first pass we collect all affixed values and determine protected literals.
|
||||
// This is done in order to remove repeated suffixes, except if these appear in the value or the format string itself.
|
||||
|
@ -2480,7 +2510,7 @@ Zotero.Attachments = new function () {
|
|||
if (!this.isRenameAllowedForType(contentType)) {
|
||||
return false;
|
||||
}
|
||||
return this.getFileBaseNameFromItem(parentItem);
|
||||
return this.getFileBaseNameFromItem(parentItem, { attachmentTitle: PathUtils.filename(file) });
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -294,7 +294,7 @@ Zotero.RecognizeDocument = new function () {
|
|||
// Rename attachment file to match new metadata
|
||||
if (Zotero.Attachments.shouldAutoRenameFile(attachment.attachmentLinkMode == Zotero.Attachments.LINK_MODE_LINKED_FILE)) {
|
||||
let ext = Zotero.File.getExtension(path);
|
||||
let fileBaseName = Zotero.Attachments.getFileBaseNameFromItem(parentItem);
|
||||
let fileBaseName = Zotero.Attachments.getFileBaseNameFromItem(parentItem, { attachmentTitle: originalTitle });
|
||||
let newName = fileBaseName + (ext ? '.' + ext : '');
|
||||
let result = await attachment.renameAttachmentFile(newName, false, true);
|
||||
if (result !== true) {
|
||||
|
|
|
@ -901,7 +901,7 @@ Zotero.Translate.ItemSaver.prototype = {
|
|||
let fileBaseName;
|
||||
if (parentItemID) {
|
||||
let parentItem = yield Zotero.Items.getAsync(parentItemID);
|
||||
fileBaseName = Zotero.Attachments.getFileBaseNameFromItem(parentItem);
|
||||
fileBaseName = Zotero.Attachments.getFileBaseNameFromItem(parentItem, { attachmentTitle: title });
|
||||
}
|
||||
|
||||
attachment.linkMode = "imported_url";
|
||||
|
|
|
@ -5665,7 +5665,7 @@ var ZoteroPane = new function()
|
|||
|
||||
let parentItemID = item.parentItemID;
|
||||
let parentItem = await Zotero.Items.getAsync(parentItemID);
|
||||
var newName = Zotero.Attachments.getFileBaseNameFromItem(parentItem);
|
||||
var newName = Zotero.Attachments.getFileBaseNameFromItem(parentItem, { attachmentTitle: item.getField('title') });
|
||||
|
||||
let extRE = /\.[^\.]+$/;
|
||||
let origFilename = PathUtils.split(file).pop();
|
||||
|
|
|
@ -1364,7 +1364,8 @@ describe("Zotero.Attachments", function() {
|
|||
});
|
||||
|
||||
describe("#getFileBaseNameFromItem()", function () {
|
||||
var item, itemManyAuthors, itemPatent, itemIncomplete, itemBookSection, itemSpaces, itemSuffixes, itemKeepDashes;
|
||||
var item, itemManyAuthors, itemPatent, itemIncomplete, itemBookSection, itemSpaces, itemSuffixes, itemKeepHyphens,
|
||||
itemNoRepeatedHyphens, itemNoRepeatedUnderscores;
|
||||
|
||||
before(() => {
|
||||
item = createUnsavedDataObject('item', { title: 'Lorem Ipsum', itemType: 'journalArticle' });
|
||||
|
@ -1378,7 +1379,9 @@ describe("Zotero.Attachments", function() {
|
|||
item.setField('issue', '42');
|
||||
item.setField('pages', '321');
|
||||
|
||||
|
||||
itemBookSection = createUnsavedDataObject('item', { title: 'Book Section', itemType: 'bookSection' });
|
||||
itemBookSection.setField('bookTitle', 'Book Title');
|
||||
|
||||
itemManyAuthors = createUnsavedDataObject('item', { title: 'Has Many Authors', itemType: 'book' });
|
||||
itemManyAuthors.setCreators([
|
||||
{ firstName: 'First', lastName: 'Author', creatorType: 'author' },
|
||||
|
@ -1403,222 +1406,247 @@ describe("Zotero.Attachments", function() {
|
|||
itemPatent.setField('number', 'HBK-8539b');
|
||||
itemPatent.setField('assignee', 'Fast FooBar');
|
||||
itemIncomplete = createUnsavedDataObject('item', { title: 'Incomplete', itemType: 'preprint' });
|
||||
itemBookSection = createUnsavedDataObject('item', { title: 'Book Section', itemType: 'bookSection' });
|
||||
itemBookSection.setField('bookTitle', 'Book Title');
|
||||
|
||||
itemSpaces = createUnsavedDataObject('item', { title: ' Spaces! ', itemType: 'book' });
|
||||
itemSuffixes = createUnsavedDataObject('item', { title: '-Suffixes-', itemType: 'book' });
|
||||
itemSuffixes.setField('date', "1999-07-15");
|
||||
itemKeepDashes = createUnsavedDataObject('item', { title: 'keep--dashes', itemType: 'journalArticle' });
|
||||
itemKeepDashes.setField('publicationTitle', "keep");
|
||||
itemKeepDashes.setField('issue', 'dashes');
|
||||
itemKeepDashes.setField('date', "1999-07-15");
|
||||
itemKeepHyphens = createUnsavedDataObject('item', { title: 'keep--hyphens', itemType: 'journalArticle' });
|
||||
itemKeepHyphens.setField('publicationTitle', "keep");
|
||||
itemKeepHyphens.setField('issue', 'hyphens');
|
||||
itemKeepHyphens.setField('date', "1999-07-15");
|
||||
itemNoRepeatedHyphens = createUnsavedDataObject('item', { title: 'no - repeated - hyphens', itemType: 'journalArticle' });
|
||||
itemNoRepeatedHyphens.setField('publicationTitle', "no- repeated- hyphens");
|
||||
itemNoRepeatedUnderscores = createUnsavedDataObject('item', { title: 'no _ repeated _ underscores', itemType: 'journalArticle' });
|
||||
itemNoRepeatedUnderscores.setField('publicationTitle', "no_ repeated_ underscores");
|
||||
});
|
||||
|
||||
|
||||
it('should strip HTML tags from title', function () {
|
||||
var htmlItem = createUnsavedDataObject('item', { title: 'Foo <i>Bar</i> Foo<br><br/><br />Bar' });
|
||||
var str = Zotero.Attachments.getFileBaseNameFromItem(htmlItem, '{{ title }}');
|
||||
var str = Zotero.Attachments.getFileBaseNameFromItem(htmlItem, { formatString: '{{ title }}' });
|
||||
assert.equal(str, 'Foo Bar Foo Bar');
|
||||
});
|
||||
|
||||
it('should accept basic formating options', function () {
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, 'FOO{{year}}BAR'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: 'FOO{{year}}BAR' }),
|
||||
'FOO1975BAR'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{firstCreator suffix=" - "}}{{year suffix=" - "}}{{title truncate="50" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{firstCreator suffix=" - "}}{{year suffix=" - "}}{{title truncate="50" }}' }),
|
||||
'Barius and Pixelus - 1975 - Lorem Ipsum'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{firstCreator suffix=" - " replaceFrom=" *and *" replaceTo="&"}}{{year suffix=" - " replaceFrom="(\\d{2})(\\d{2})" replaceTo="$2"}}{{title truncate="50" replaceFrom=".m" replaceTo="a"}} - {{title truncate="50" replaceFrom=".m" replaceTo="a" regexOpts="g"}}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{firstCreator suffix=" - " replaceFrom=" *and *" replaceTo="&"}}{{year suffix=" - " replaceFrom="(\\d{2})(\\d{2})" replaceTo="$2"}}{{title truncate="50" replaceFrom=".m" replaceTo="a"}} - {{title truncate="50" replaceFrom=".m" replaceTo="a" regexOpts="g"}}' }),
|
||||
'Barius&Pixelus - 75 - Lora Ipsum - Lora Ipsa'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{year suffix="-"}}{{firstCreator truncate="10" suffix="-"}}{{title truncate="5" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{year suffix="-"}}{{firstCreator truncate="10" suffix="-"}}{{title truncate="5" }}' }),
|
||||
'1975-Barius and-Lorem'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, 'foo {{year}} bar {{year prefix="++" truncate="2" suffix="++"}}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: 'foo {{year}} bar {{year prefix="++" truncate="2" suffix="++"}}' }),
|
||||
'foo 1975 bar ++19++'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, '{{firstCreator suffix=" - "}}{{year suffix=" - "}}{{title}}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, { formatString: '{{firstCreator suffix=" - "}}{{year suffix=" - "}}{{title}}' }),
|
||||
'Author et al. - 2000 - Has Many Authors'
|
||||
);
|
||||
});
|
||||
|
||||
it('should trim whitespaces from a value', function () {
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemSpaces, '{{ title }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemSpaces, { formatString: '{{ title }}' }),
|
||||
'Spaces!'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{title truncate="6"}}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{title truncate="6"}}' }),
|
||||
'Lorem'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{firstCreator truncate="7"}}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{firstCreator truncate="7"}}' }),
|
||||
'Barius'
|
||||
);
|
||||
// but preserve if it's configured as a prefix or suffix
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{title prefix=" " suffix=" "}}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{title prefix=" " suffix=" "}}' }),
|
||||
' Lorem Ipsum '
|
||||
);
|
||||
});
|
||||
|
||||
it('should offer a range of options for composing creators', function () {
|
||||
it('should offer a range of options for composing creators', async function () {
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{ authors max="1" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ authors max="1" }}' }),
|
||||
'Barius'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{ authors max="1" truncate="3" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ authors max="1" truncate="3" }}' }),
|
||||
'Bar'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{ authors max="5" join=" " }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ authors max="5" join=" " }}' }),
|
||||
'Barius Pixelus'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, '{{ authors max="3" join=" " }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, { formatString: '{{ authors max="3" join=" " }}' }),
|
||||
'Author Creator Person'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemPatent, '{{ authors }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemPatent, { formatString: '{{ authors }}' }),
|
||||
'AcmeCorp'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, '{{ authors max="2" name="family" initialize="family" join=" " initialize-with="" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, { formatString: '{{ authors max="2" name="family" initialize="family" join=" " initialize-with="" }}' }),
|
||||
'A C'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemPatent, '{{ authors max="2" name="family" initialize="family" initialize-with="" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemPatent, { formatString: '{{ authors max="2" name="family" initialize="family" initialize-with="" }}' }),
|
||||
'A'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{ authors max="1" name="full" initialize="full" name-part-separator="" initialize-with="" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ authors max="1" name="full" initialize="full" name-part-separator="" initialize-with="" }}' }),
|
||||
'FB'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, '{{ authors max="3" name="full" initialize="full" name-part-separator="" join=" " initialize-with="" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, { formatString: '{{ authors max="3" name="full" initialize="full" name-part-separator="" join=" " initialize-with="" }}' }),
|
||||
'FA SC TP'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{ authors max="1" name="family-given" initialize="given" name-part-separator="" initialize-with="" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ authors max="1" name="family-given" initialize="given" name-part-separator="" initialize-with="" }}' }),
|
||||
'BariusF'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, '{{ authors max="2" name="family-given" initialize="given" join=" " name-part-separator="" initialize-with="" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, { formatString: '{{ authors max="2" name="family-given" initialize="given" join=" " name-part-separator="" initialize-with="" }}' }),
|
||||
'AuthorF CreatorS'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{ editors }}test'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ editors }}test' }),
|
||||
'test'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, '{{ editors max="1" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, { formatString: '{{ editors max="1" }}' }),
|
||||
'Editor1'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, '{{ editors max="5" join=" " }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, { formatString: '{{ editors max="5" join=" " }}' }),
|
||||
'Editor1 ProEditor2 SuperbEditor3'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, '{{ editors max="2" name="family" initialize="family" join=" " initialize-with="" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, { formatString: '{{ editors max="2" name="family" initialize="family" join=" " initialize-with="" }}' }),
|
||||
'E P'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, '{{ editors max="1" name="full" initialize="full" name-part-separator="" initialize-with="" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, { formatString: '{{ editors max="1" name="full" initialize="full" name-part-separator="" initialize-with="" }}' }),
|
||||
'SE'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, '{{ editors max="1" name="family-given" initialize="given" name-part-separator="" initialize-with="" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, { formatString: '{{ editors max="1" name="family-given" initialize="given" name-part-separator="" initialize-with="" }}' }),
|
||||
'Editor1S'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{ authors max="3" name="full" initialize="given" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ authors max="3" name="full" initialize="given" }}' }),
|
||||
'F. Barius, B. Pixelus'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{ creators case="upper" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ creators case="upper" }}' }),
|
||||
'BARIUS, PIXELUS'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, '{{ authors max="2" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, { formatString: '{{ authors max="2" }}' }),
|
||||
'Author, Creator'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, '{{ creators max="3" join=" " name="given" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, { formatString: '{{ creators max="3" join=" " name="given" }}' }),
|
||||
'First Second Third'
|
||||
);
|
||||
});
|
||||
|
||||
it('should accept case parameter', async function () {
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{ publicationTitle case="upper" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ publicationTitle case="upper" }}' }),
|
||||
'BEST PUBLICATIONS PLACE'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{ publicationTitle case="lower" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ publicationTitle case="lower" }}' }),
|
||||
'best publications place'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{ publicationTitle case="title" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ publicationTitle case="title" }}' }),
|
||||
'Best Publications Place'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{ publicationTitle case="hyphen" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ publicationTitle case="hyphen" }}' }),
|
||||
'best-publications-place'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{ publicationTitle case="camel" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ publicationTitle case="camel" }}' }),
|
||||
'bestPublicationsPlace'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{ publicationTitle case="snake" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ publicationTitle case="snake" }}' }),
|
||||
'best_publications_place'
|
||||
);
|
||||
});
|
||||
|
||||
it('should accept itemType or any other field', function () {
|
||||
it('should not create repeated characters when converting case to hyphen or snake', async function () {
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{ itemType localize="true" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemNoRepeatedHyphens, { formatString: '{{ title case="hyphen" }}' }),
|
||||
'no-repeated-hyphens'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemNoRepeatedHyphens, { formatString: '{{ publicationTitle case="hyphen" }}' }),
|
||||
'no-repeated-hyphens'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemNoRepeatedUnderscores, { formatString: '{{ title case="snake" }}' }),
|
||||
'no_repeated_underscores'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemNoRepeatedUnderscores, { formatString: '{{ publicationTitle case="snake" }}' }),
|
||||
'no_repeated_underscores'
|
||||
);
|
||||
});
|
||||
|
||||
it('should accept itemType, attachmentTitle or any other field', function () {
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ itemType localize="true" }}' }),
|
||||
'Journal Article'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{ publicationTitle }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ publicationTitle }}' }),
|
||||
'Best Publications Place'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{ journalAbbreviation }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ journalAbbreviation }}' }),
|
||||
'BPP'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, '{{ publisher }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, { formatString: '{{ publisher }}' }),
|
||||
'Awesome House'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, '{{ volume }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemManyAuthors, { formatString: '{{ volume }}' }),
|
||||
'3'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{ issue }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ issue }}' }),
|
||||
'42'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{ pages }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ pages }}' }),
|
||||
'321'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemPatent, '{{ number }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemPatent, { formatString: '{{ number }}' }),
|
||||
'HBK-8539b'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemPatent, '{{ assignee }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemPatent, { formatString: '{{ assignee }}' }),
|
||||
'Fast FooBar'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ attachmentTitle }}', attachmentTitle: 'Full Text' }),
|
||||
'Full Text'
|
||||
);
|
||||
});
|
||||
|
||||
it("should support simple logic in template syntax", function () {
|
||||
|
@ -1634,68 +1662,107 @@ describe("Zotero.Attachments", function() {
|
|||
);
|
||||
});
|
||||
|
||||
it("should skip missing fields", function () {
|
||||
it("should skip missing fields", async function () {
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemIncomplete, '{{ authors prefix = "a" suffix="-" }}{{ publicationTitle case="hyphen" suffix="-" }}{{ title }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemIncomplete, { formatString: '{{ authors prefix = "a" suffix="-" }}{{ publicationTitle case="hyphen" suffix="-" }}{{ title }}' }),
|
||||
'Incomplete'
|
||||
);
|
||||
});
|
||||
|
||||
it("should recognized base-mapped fields", function () {
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemBookSection, '{{ bookTitle case="snake" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemBookSection, { formatString: '{{ bookTitle case="snake" }}' }),
|
||||
'book_title'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemBookSection, '{{ publicationTitle case="snake" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemBookSection, { formatString: '{{ publicationTitle case="snake" }}' }),
|
||||
'book_title'
|
||||
);
|
||||
});
|
||||
|
||||
it("should trim spaces from template string", function () {
|
||||
it("should trim spaces and remove new lines from the template string", function () {
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemBookSection, ' {{ bookTitle case="snake" }} '),
|
||||
'book_title'
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemBookSection, { formatString: ' {{ bookTitle case="snake" }}\n{{ bookTitle case="hyphen" prefix="-" }}' }),
|
||||
'book_title-book-title'
|
||||
);
|
||||
});
|
||||
|
||||
it("should suppress suffixes where they would create a repeat character", function () {
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, '{{ title suffix="-" }}{{ year prefix="-" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ title suffix="-" }}{{ year prefix="-" }}' }),
|
||||
'Lorem Ipsum-1975'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemSuffixes, '{{ title prefix="-" suffix="-" }}{{ year }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemSuffixes, { formatString: '{{ title prefix="-" suffix="-" }}{{ year }}' }),
|
||||
'-Suffixes-1999'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemSuffixes, '{{ title suffix="-" }}{{ year prefix="-" }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemSuffixes, { formatString: '{{ title suffix="-" }}{{ year prefix="-" }}' }),
|
||||
'-Suffixes-1999'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemKeepDashes, '{{ title suffix="-" }}{{ year prefix="-" }}'),
|
||||
'keep--dashes-1999'
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemKeepHyphens, { formatString: '{{ title suffix="-" }}{{ year prefix="-" }}' }),
|
||||
'keep--hyphens-1999'
|
||||
);
|
||||
// keep--dashes is a title and should be kept unchanged but "keep" and "dashes" are fields
|
||||
// keep--hyphens is a title and should be kept unchanged but "keep" and "hyphens" are fields
|
||||
// separated by prefixes and suffixes where repeated characters should be suppressed
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemKeepDashes, '{{ title suffix="-" }}{{ publicationTitle suffix="-" }}{{ issue prefix="-" }}'),
|
||||
'keep--dashes-keep-dashes'
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemKeepHyphens, { formatString: '{{ title suffix="-" }}{{ publicationTitle suffix="-" }}{{ issue prefix="-" }}' }),
|
||||
'keep--hyphens-keep-hyphens'
|
||||
);
|
||||
// keep--dashes is provided as literal part of the template and should be kept unchanged
|
||||
// but "keep" and "dashes" are fields separated by prefixes and suffixes where repeated
|
||||
// characters should be suppressed. Finally "keep--dashes" title is appended at the end
|
||||
// keep--hyphens is provided as literal part of the template and should be kept unchanged
|
||||
// but "keep" and "hyphens" are fields separated by prefixes and suffixes where repeated
|
||||
// characters should be suppressed. Finally "keep--hyphens" title is appended at the end
|
||||
// which should also be kept as is.
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemKeepDashes, 'keep--dashes-{{ publicationTitle prefix="-" suffix="-" }}{{ issue prefix="-" suffix="-" }}-keep--dashes-{{ publicationTitle suffix="-" }}test{{ title prefix="-" }}'),
|
||||
'keep--dashes-keep-dashes-keep--dashes-keep-test-keep--dashes'
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemKeepHyphens, { formatString: 'keep--hyphens-{{ publicationTitle prefix="-" suffix="-" }}{{ issue prefix="-" suffix="-" }}-keep--hyphens-{{ publicationTitle suffix="-" }}test{{ title prefix="-" }}' }),
|
||||
'keep--hyphens-keep-hyphens-keep--hyphens-keep-test-keep--hyphens'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemSuffixes, '{{ title prefix="/" suffix="\\" }}{{ year }}'),
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemSuffixes, { formatString: '{{ title prefix="/" suffix="\\" }}{{ year }}' }),
|
||||
'-Suffixes-1999'
|
||||
);
|
||||
});
|
||||
|
||||
it("should be possible to test attachmentTitle", function () {
|
||||
const template = `{{ if {{ attachmentTitle match="^(full.*|submitted.*|accepted.*)$" }} }}
|
||||
{{ firstCreator suffix=" - " }}{{ year suffix=" - " }}{{ title truncate="100" }}
|
||||
{{ else }}
|
||||
{{ attachmentTitle replaceFrom="\\.pdf|\\.epub|\\.png" }}
|
||||
{{ endif }}`;
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: template, attachmentTitle: 'Full Text' }),
|
||||
'Barius and Pixelus - 1975 - Lorem Ipsum'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemBookSection, { formatString: template, attachmentTitle: 'Other Attachment.png' }),
|
||||
'Other Attachment'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(itemBookSection, { formatString: `{{ attachmentTitle start = "6" truncate = "4" }}`, attachmentTitle: 'Other Attachment.png' }),
|
||||
'Atta'
|
||||
);
|
||||
});
|
||||
|
||||
it("should perform regex in a case-insensitive way, unless configured otherwise", function () {
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ title match="lorem" }}' }),
|
||||
'Lorem'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ title match="lorem" regexOpts="" }}' }),
|
||||
'_' // template formatting results in an empty string, "_" is returned to make it a valid file name
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ title replaceFrom="lorem" replaceTo="Foobar" }}' }),
|
||||
'Foobar Ipsum'
|
||||
);
|
||||
assert.equal(
|
||||
Zotero.Attachments.getFileBaseNameFromItem(item, { formatString: '{{ title replaceFrom="lorem" replaceTo="foobar" regexOpts="" }}' }),
|
||||
'Lorem Ipsum'
|
||||
);
|
||||
});
|
||||
|
||||
it("should convert old attachmentRenameFormatString to use new attachmentRenameTemplate syntax", function () {
|
||||
assert.equal(
|
||||
Zotero.Prefs.convertLegacyAttachmentRenameFormatString('{%c - }{%y - }{%t{50}}'),
|
||||
|
|
Loading…
Add table
Reference in a new issue