From c9290555711d0f2f1c7dd8f633113e5a802cf8f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adomas=20Ven=C4=8Dkauskas?= Date: Fri, 2 Apr 2021 11:50:32 +0300 Subject: [PATCH] Refactor utilities code in preparation to move to external repo --- chrome/content/zotero/xpcom/attachments.js | 2 +- .../content/zotero/xpcom/data/collection.js | 2 +- chrome/content/zotero/xpcom/data/feed.js | 2 +- chrome/content/zotero/xpcom/data/feedItem.js | 2 +- chrome/content/zotero/xpcom/data/group.js | 2 +- chrome/content/zotero/xpcom/data/library.js | 2 +- chrome/content/zotero/xpcom/data/search.js | 2 +- chrome/content/zotero/xpcom/feedReader.js | 2 +- chrome/content/zotero/xpcom/progressWindow.js | 4 +- chrome/content/zotero/xpcom/utilities.js | 503 +++++++++--------- .../zotero/xpcom/utilities_internal.js | 212 +++----- chrome/content/zotero/zoteroPane.js | 2 +- test/tests/dataObjectTest.js | 2 +- test/tests/utilitiesTest.js | 45 -- test/tests/utilities_internalTest.js | 45 ++ 15 files changed, 368 insertions(+), 461 deletions(-) diff --git a/chrome/content/zotero/xpcom/attachments.js b/chrome/content/zotero/xpcom/attachments.js index 9b4e2f2a55..4990674489 100644 --- a/chrome/content/zotero/xpcom/attachments.js +++ b/chrome/content/zotero/xpcom/attachments.js @@ -2672,7 +2672,7 @@ Zotero.Attachments = new function(){ this._getFileNameFromURL = function(url, contentType) { - url = Zotero.Utilities.parseURL(url); + url = Zotero.Utilities.Internal.parseURL(url); var fileBaseName = url.fileBaseName; var fileExt = Zotero.MIME.getPrimaryExtension(contentType, url.fileExtension); diff --git a/chrome/content/zotero/xpcom/data/collection.js b/chrome/content/zotero/xpcom/data/collection.js index 438713baff..762130336f 100644 --- a/chrome/content/zotero/xpcom/data/collection.js +++ b/chrome/content/zotero/xpcom/data/collection.js @@ -31,7 +31,7 @@ Zotero.Collection = function(params = {}) { this._childCollections = new Set(); this._childItems = new Set(); - Zotero.Utilities.assignProps(this, params, ['name', 'libraryID', 'parentID', 'parentKey']); + Zotero.Utilities.Internal.assignProps(this, params, ['name', 'libraryID', 'parentID', 'parentKey']); } Zotero.extendClass(Zotero.DataObject, Zotero.Collection); diff --git a/chrome/content/zotero/xpcom/data/feed.js b/chrome/content/zotero/xpcom/data/feed.js index d8ee28c16f..ce01d7b8df 100644 --- a/chrome/content/zotero/xpcom/data/feed.js +++ b/chrome/content/zotero/xpcom/data/feed.js @@ -60,7 +60,7 @@ Zotero.Feed = function(params = {}) { get: function() { return this._get('_libraryFilesEditable'); } }); - Zotero.Utilities.assignProps(this, params, + Zotero.Utilities.Internal.assignProps(this, params, ['name', 'url', 'refreshInterval', 'cleanupReadAfter', 'cleanupUnreadAfter']); // Return a proxy so that we can disable the object once it's deleted diff --git a/chrome/content/zotero/xpcom/data/feedItem.js b/chrome/content/zotero/xpcom/data/feedItem.js index 4400586884..affff08a8e 100644 --- a/chrome/content/zotero/xpcom/data/feedItem.js +++ b/chrome/content/zotero/xpcom/data/feedItem.js @@ -33,7 +33,7 @@ Zotero.FeedItem = function(itemTypeOrID, params = {}) { this._feedItemReadTime = null; this._feedItemTranslatedTime = null; - Zotero.Utilities.assignProps(this, params, ['guid']); + Zotero.Utilities.Internal.assignProps(this, params, ['guid']); }; Zotero.extendClass(Zotero.Item, Zotero.FeedItem); diff --git a/chrome/content/zotero/xpcom/data/group.js b/chrome/content/zotero/xpcom/data/group.js index 3b9d8d44d7..98b250fad0 100644 --- a/chrome/content/zotero/xpcom/data/group.js +++ b/chrome/content/zotero/xpcom/data/group.js @@ -29,7 +29,7 @@ Zotero.Group = function (params = {}) { params.libraryType = 'group'; Zotero.Group._super.call(this, params); - Zotero.Utilities.assignProps(this, params, ['groupID', 'name', 'description', + Zotero.Utilities.Internal.assignProps(this, params, ['groupID', 'name', 'description', 'version']); // Return a proxy so that we can disable the object once it's deleted diff --git a/chrome/content/zotero/xpcom/data/library.js b/chrome/content/zotero/xpcom/data/library.js index 70c67242af..8d210b4055 100644 --- a/chrome/content/zotero/xpcom/data/library.js +++ b/chrome/content/zotero/xpcom/data/library.js @@ -38,7 +38,7 @@ Zotero.Library = function(params = {}) { this._hasSearches = null; this._storageDownloadNeeded = false; - Zotero.Utilities.assignProps( + Zotero.Utilities.Internal.assignProps( this, params, [ diff --git a/chrome/content/zotero/xpcom/data/search.js b/chrome/content/zotero/xpcom/data/search.js index 6414148c03..73d139af8f 100644 --- a/chrome/content/zotero/xpcom/data/search.js +++ b/chrome/content/zotero/xpcom/data/search.js @@ -36,7 +36,7 @@ Zotero.Search = function(params = {}) { this._conditions = {}; this._hasPrimaryConditions = false; - Zotero.Utilities.assignProps(this, params, ['name', 'libraryID']); + Zotero.Utilities.Internal.assignProps(this, params, ['name', 'libraryID']); } Zotero.extendClass(Zotero.DataObject, Zotero.Search); diff --git a/chrome/content/zotero/xpcom/feedReader.js b/chrome/content/zotero/xpcom/feedReader.js index 2326d7e385..ff877d804b 100644 --- a/chrome/content/zotero/xpcom/feedReader.js +++ b/chrome/content/zotero/xpcom/feedReader.js @@ -521,7 +521,7 @@ Zotero.FeedReader._getFeedItem = function (feedEntry, feedInfo) { Zotero.FeedReader._getRichText = function (feedText, field) { let domDiv = Zotero.Utilities.Internal.getDOMDocument().createElement("div"); let domFragment = feedText.createDocumentFragment(domDiv); - return Zotero.Utilities.dom2text(domFragment, field); + return Zotero.Utilities.trimInternal(domFragment.textContent); }; /* diff --git a/chrome/content/zotero/xpcom/progressWindow.js b/chrome/content/zotero/xpcom/progressWindow.js index 8805295ff8..5797725948 100644 --- a/chrome/content/zotero/xpcom/progressWindow.js +++ b/chrome/content/zotero/xpcom/progressWindow.js @@ -434,7 +434,7 @@ Zotero.ProgressWindow = function(options = {}) { var attachment = item.attachments[i]; _attachmentsMap.set(attachment, new self.ItemProgress( - Zotero.Utilities.determineAttachmentIcon(attachment), + Zotero.Utilities.Internal.determineAttachmentIcon(attachment), attachment.title, itemProgress)); } } @@ -449,7 +449,7 @@ Zotero.ProgressWindow = function(options = {}) { } else { itemProgress.setProgress(progress); if(progress === 100) { - itemProgress.setIcon(Zotero.Utilities.determineAttachmentIcon(attachment)); + itemProgress.setIcon(Zotero.Utilities.Internal.determineAttachmentIcon(attachment)); } } } diff --git a/chrome/content/zotero/xpcom/utilities.js b/chrome/content/zotero/xpcom/utilities.js index b7eb1e6b50..fca0502b9d 100644 --- a/chrome/content/zotero/xpcom/utilities.js +++ b/chrome/content/zotero/xpcom/utilities.js @@ -26,10 +26,26 @@ ***** END LICENSE BLOCK ***** */ +(function() { +if (typeof module != 'undefined') { + require('./xregexp-all'); +} + +function movedToUtilitiesInternal(fnName) { + return function () { + if (Zotero.Utilities && Zotero.Utilitie.Internal) { + Zotero.debug(`Zotero.Utilities.${fnName}() is deprecated -- use Zotero.Utilities.Internal.${fnName}() instead`); + return Zotero.Utilities.Internal[fnName].apply(Zotero.Utilities.Internal, arguments); + } else { + throw new Error(`Zotero.Utilities.${fnName}() is only available in the zotero-client codebase`) + } + } +} + /** * @class Functions for text manipulation and other miscellaneous purposes */ -Zotero.Utilities = { +var Utilities = { /** * Returns a function which will execute `fn` with provided arguments after `delay` milliseconds and not more * than once, if called multiple times. See @@ -116,11 +132,11 @@ Zotero.Utilities = { * @param {String} string Uppercase author name * @return {String} Title-cased author name */ - "capitalizeName": function (string) { + capitalizeName: function (string) { if (typeof string === "string" && string.toUpperCase() === string) { - string = Zotero.Utilities.XRegExp.replace( + string = Utilities.XRegExp.replace( string.toLowerCase(), - Zotero.Utilities.XRegExp('(^|[^\\pL])\\pL', 'g'), + Utilities.XRegExp('(^|[^\\pL])\\pL', 'g'), m => m.toUpperCase() ); } @@ -135,7 +151,7 @@ Zotero.Utilities = { * @param {Boolean} useComma Whether the creator string is in inverted (Last, First) format * @return {Object} firstName, lastName, and creatorType */ - "cleanAuthor":function(author, type, useComma) { + cleanAuthor: function(author, type, useComma) { var allCaps = 'A-Z' + '\u0400-\u042f'; //cyrilic @@ -168,7 +184,7 @@ Zotero.Utilities = { spaceIndex = author.lastIndexOf(" ", spaceIndex-1); var lastName = author.substring(spaceIndex + 1); var firstName = author.substring(0, spaceIndex); - } while (!Zotero.Utilities.XRegExp('\\pL').test(lastName[0]) && spaceIndex > 0) + } while (!Utilities.XRegExp('\\pL').test(lastName[0]) && spaceIndex > 0) } if(firstName && allCapsRe.test(firstName) && @@ -205,7 +221,7 @@ Zotero.Utilities = { * Removes leading and trailing whitespace from a string * @type String */ - "trim":function(/**String*/ s) { + trim: function(/**String*/ s) { if (typeof(s) != "string") { throw new Error("trim: argument must be a string"); } @@ -218,7 +234,7 @@ Zotero.Utilities = { * Cleans whitespace off a string and replaces multiple spaces with one * @type String */ - "trimInternal":function(/**String*/ s) { + trimInternal: function(/**String*/ s) { if (typeof(s) != "string") { throw new Error("trimInternal: argument must be a string"); } @@ -231,7 +247,7 @@ Zotero.Utilities = { * Cleans any non-word non-parenthesis characters off the ends of a string * @type String */ - "superCleanString":function(/**String*/ x) { + superCleanString: function(/**String*/ x) { if(typeof(x) != "string") { throw new Error("superCleanString: argument must be a string"); } @@ -281,7 +297,7 @@ Zotero.Utilities = { * Eliminates HTML tags, replacing <br>s with newlines * @type String */ - "cleanTags":function(/**String*/ x) { + cleanTags: function(/**String*/ x) { if(typeof(x) != "string") { throw new Error("cleanTags: argument must be a string"); } @@ -295,7 +311,7 @@ Zotero.Utilities = { * Strip info:doi prefix and any suffixes from a DOI * @type String */ - "cleanDOI":function(/**String**/ x) { + cleanDOI: function(/**String**/ x) { if(typeof(x) != "string") { throw new Error("cleanDOI: argument must be a string"); } @@ -311,7 +327,7 @@ Zotero.Utilities = { * @param {Boolean} [dontValidate=false] Do not validate check digit * @return {String|Boolean} Valid ISBN or false */ - "cleanISBN":function(isbnStr, dontValidate) { + cleanISBN: function(isbnStr, dontValidate) { isbnStr = isbnStr.toUpperCase() .replace(/[\x2D\xAD\u2010-\u2015\u2043\u2212]+/g, ''); // Ignore dashes var isbnRE = /\b(?:97[89]\s*(?:\d\s*){9}\d|(?:\d\s*){9}[\dX])\b/g, @@ -355,9 +371,9 @@ Zotero.Utilities = { * cleanISBN * @return {String} ISBN-13 */ - "toISBN13": function(isbnStr) { + toISBN13: function(isbnStr) { var isbn; - if (!(isbn = Zotero.Utilities.cleanISBN(isbnStr, true))) { + if (!(isbn = Utilities.cleanISBN(isbnStr, true))) { throw new Error('ISBN not found in "' + isbnStr + '"'); } @@ -382,7 +398,7 @@ Zotero.Utilities = { * Clean and validate ISSN. * Return issn if valid, otherwise return false */ - "cleanISSN":function(/**String*/ issnStr) { + cleanISSN: function(/**String*/ issnStr) { issnStr = issnStr.toUpperCase() .replace(/[\x2D\xAD\u2010-\u2015\u2043\u2212]+/g, ''); // Ignore dashes var issnRE = /\b(?:\d\s*){7}[\dX]\b/g, @@ -417,8 +433,8 @@ Zotero.Utilities = { * are replaced with P tags, while single newlines are replaced with BR tags. * @type String */ - "text2html":function (/**String**/ str, /**Boolean**/ singleNewlineIsParagraph) { - str = Zotero.Utilities.htmlSpecialChars(str); + text2html: function (/**String**/ str, /**Boolean**/ singleNewlineIsParagraph) { + str = Utilities.htmlSpecialChars(str); // \n =>

if (singleNewlineIsParagraph) { @@ -447,7 +463,7 @@ Zotero.Utilities = { * @param {String} str * @return {String} */ - "htmlSpecialChars":function(str) { + htmlSpecialChars: function(str) { if (str && typeof str != 'string') { Zotero.debug('#htmlSpecialChars: non-string arguments are deprecated. Update your code', 1, undefined, true); @@ -489,7 +505,7 @@ Zotero.Utilities = { // Create a node and use the textContent property to do unescaping where // possible, because this approach preserves line endings in the HTML if(node === undefined) { - node = Zotero.Utilities.Internal.getDOMDocument().createElement("div"); + node = Utilities.Internal.getDOMDocument().createElement("div"); } node.innerHTML = str; @@ -506,27 +522,13 @@ Zotero.Utilities = { }; }, - /** - * Converts text inside a DOM object to plain text preserving text formatting - * appropriate for given field - * - * @param {DOMNode} rootNode Node containing all the text that needs to be extracted - * @param {String} targetField Zotero item field that the text is meant for - * - * @return {String} Zotero formatted string - */ - "dom2text": function(rootNode, targetField) { - // TODO: actually do this - return Zotero.Utilities.trimInternal(rootNode.textContent); - }, - /** * Wrap URLs and DOIs in links in plain text * * Ignore URLs preceded by '>', just in case there are already links * @type String */ - "autoLink":function (/**String**/ str) { + autoLink: function (/**String**/ str) { // "http://www.google.com." // "http://www.google.com. " // "" (and other characters, with or without a space after) @@ -551,7 +553,7 @@ Zotero.Utilities = { * [ attributes: { key1: val [ , key2: val, ...] } * } */ - "parseMarkup":function(/**String*/ str) { + parseMarkup: function(/**String*/ str) { var parts = []; var splits = str.split(/(]+>[^<]*<\/a>)/); @@ -590,7 +592,7 @@ Zotero.Utilities = { * Calculates the Levenshtein distance between two strings * @type Number */ - "levenshtein":function (/**String*/ a, /**String**/ b) { + levenshtein: function (/**String*/ a, /**String**/ b) { var aLen = a.length; var bLen = b.length; @@ -622,7 +624,7 @@ Zotero.Utilities = { * @param {Object} obj * @type Boolean */ - "isEmpty":function (obj) { + isEmpty: function (obj) { for (var i in obj) { return false; } @@ -639,7 +641,7 @@ Zotero.Utilities = { * the index of array2's elements; * otherwise return the values */ - "arrayDiff":function(array1, array2, useIndex) { + arrayDiff: function(array1, array2, useIndex) { if (!Array.isArray(array1)) { throw new Error("array1 is not an array (" + array1 + ")"); } @@ -666,7 +668,7 @@ Zotero.Utilities = { * * @return {Boolean} */ - "arrayEquals": function (array1, array2) { + arrayEquals: function (array1, array2) { // If either array is a falsy value, return if (!array1 || !array2) return false; @@ -700,7 +702,7 @@ Zotero.Utilities = { * @param {Array} arr * @return {Array} */ - "arrayShuffle": function (array) { + arrayShuffle: function (array) { var counter = array.length, temp, index; // While there are elements in the array @@ -728,46 +730,6 @@ Zotero.Utilities = { return [...new Set(arr)]; }, - /** - * Run a function on chunks of a given size of an array's elements. - * - * @param {Array} arr - * @param {Integer} chunkSize - * @param {Function} func - * @return {Array} The return values from the successive runs - */ - "forEachChunk":function(arr, chunkSize, func) { - var retValues = []; - var tmpArray = arr.concat(); - var num = arr.length; - var done = 0; - - do { - var chunk = tmpArray.splice(0, chunkSize); - done += chunk.length; - retValues.push(func(chunk)); - } - while (done < num); - - return retValues; - }, - - /** - * Assign properties to an object - * - * @param {Object} target - * @param {Object} source - * @param {String[]} [props] Properties to assign. Assign all otherwise - */ - "assignProps": function(target, source, props) { - if (!props) props = Object.keys(source); - - for (var i=0; i>"; } @@ -1507,20 +1434,157 @@ Zotero.Utilities = { return dumpedText; }, + /** + * Converts Zotero.Item to a format expected by translators + * This is mostly the Zotero web API item JSON format, but with an attachments + * and notes arrays and optional compatibility mappings for older translators. + * + * @param {Zotero.Item} zoteroItem + * @param {Boolean} legacy Add mappings for legacy (pre-4.0.27) translators + * @return {Object} + */ + itemToExportFormat: function (zoteroItem, legacy, skipChildItems) { + function addCompatibilityMappings(item, zoteroItem) { + item.uniqueFields = {}; + + // Meaningless local item ID, but some older export translators depend on it + item.itemID = zoteroItem.id; + item.key = zoteroItem.key; // CSV translator exports this + + // "version" is expected to be a field for "computerProgram", which is now + // called "versionNumber" + delete item.version; + if (item.versionNumber) { + item.version = item.uniqueFields.version = item.versionNumber; + delete item.versionNumber; + } + + // SQL instead of ISO-8601 + item.dateAdded = zoteroItem.dateAdded; + item.dateModified = zoteroItem.dateModified; + if (item.accessDate) { + item.accessDate = zoteroItem.getField('accessDate'); + } + + // Map base fields + for (let field in item) { + let id = Zotero.ItemFields.getID(field); + if (!id || !Zotero.ItemFields.isValidForType(id, zoteroItem.itemTypeID)) { + continue; + } + + let baseField = Zotero.ItemFields.getName( + Zotero.ItemFields.getBaseIDFromTypeAndField(item.itemType, field) + ); + + if (!baseField || baseField == field) { + item.uniqueFields[field] = item[field]; + } else { + item[baseField] = item[field]; + item.uniqueFields[baseField] = item[field]; + } + } + + // Add various fields for compatibility with translators pre-4.0.27 + item.itemID = zoteroItem.id; + item.libraryID = zoteroItem.libraryID == 1 ? null : zoteroItem.libraryID; + + // Creators + if (item.creators) { + for (let i=0; i} A CSL item, or a promise for a CSL item if a Zotero.Item * is passed */ - "itemToCSLJSON":function(zoteroItem) { + itemToCSLJSON: function(zoteroItem) { // If a Zotero.Item was passed, convert it to the proper format (skipping child items) and // call this function again with that object // // (Zotero.Item won't be defined in translation-server) if (typeof Zotero.Item !== 'undefined' && zoteroItem instanceof Zotero.Item) { return this.itemToCSLJSON( - Zotero.Utilities.Internal.itemToExportFormat(zoteroItem, false, true) + Utilities.Internal.itemToExportFormat(zoteroItem, false, true) ); } @@ -1687,7 +1751,7 @@ Zotero.Utilities = { * @param {Zotero.Item} item * @param {Object} cslItem */ - "itemFromCSLJSON":function(item, cslItem) { + itemFromCSLJSON: function(item, cslItem) { var isZoteroItem = !!item.setType, zoteroType; @@ -1824,7 +1888,7 @@ Zotero.Utilities = { date = Zotero.Date.strToISO(date); } } else { - var newDate = Zotero.Utilities.deepCopy(cslDate); + var newDate = Utilities.deepCopy(cslDate); if(cslDate["date-parts"] && typeof cslDate["date-parts"] === "object" && cslDate["date-parts"] !== null && typeof cslDate["date-parts"][0] === "object" @@ -1837,11 +1901,11 @@ Zotero.Utilities = { if(newDate.year) { if(variable === "accessed") { // Need to convert to SQL - var date = Zotero.Utilities.lpad(newDate.year, "0", 4); + var date = Utilities.lpad(newDate.year, "0", 4); if(newDate.month) { - date += "-"+Zotero.Utilities.lpad(newDate.month, "0", 2); + date += "-"+Utilities.lpad(newDate.month, "0", 2); if(newDate.day) { - date += "-"+Zotero.Utilities.lpad(newDate.day, "0", 2); + date += "-"+Utilities.lpad(newDate.day, "0", 2); } } } else { @@ -1863,135 +1927,42 @@ Zotero.Utilities = { } } }, - - - parseURL: function (url) { - var parts = require('url').parse(url); - // fileName - parts.fileName = parts.pathname.split('/').pop(); - // fileExtension - var pos = parts.fileName.lastIndexOf('.'); - parts.fileExtension = pos == -1 ? '' : parts.fileName.substr(pos + 1); - // fileBaseName - parts.fileBaseName = parts.fileName - // filename up to the period before the file extension, if there is one - .substr(0, parts.fileName.length - (parts.fileExtension ? parts.fileExtension.length + 1 : 0)); - return parts; - }, - - /** - * Get the real target URL from an intermediate URL - */ - "resolveIntermediateURL":function(url) { - var patterns = [ - // Google search results - { - regexp: /^https?:\/\/(www.)?google\.(com|(com?\.)?[a-z]{2})\/url\?/, - variable: "url" - } - ]; - - for (var i=0, len=patterns.length; i= 128) { - if(val >= 2048) { - array[offset] = (val >>> 12) | 224; - array[offset+1] = ((val >>> 6) & 63) | 128; - array[offset+2] = (val & 63) | 128; - offset += 3; - } else { - array[offset] = ((val >>> 6) | 192); - array[offset+1] = (val & 63) | 128; - offset += 2; - } - } else { - array[offset++] = val; - } - } - }, - - /** - * Gets the byte length of the UTF-8 representation of a given string - * @param {String} string - * @return {Integer} - */ - "getStringByteLength":function(string) { - var length = 0, n = string.length; - for(var i=0; i= 128) { - if(val >= 2048) { - length += 3; - } else { - length += 2; - } - } else { - length += 1; - } - } - return length; - }, - - /** - * Gets the icon for a JSON-style attachment - */ - "determineAttachmentIcon":function(attachment) { - if(attachment.linkMode === "linked_url") { - return Zotero.ItemTypes.getImageSrc("attachment-web-link"); - } - return Zotero.ItemTypes.getImageSrc(attachment.mimeType === "application/pdf" - ? "attachment-pdf" : "attachment-snapshot"); - }, - + "allowedKeyChars": "23456789ABCDEFGHIJKLMNPQRSTUVWXYZ", - + /** * Generates a valid object key for the server API */ - "generateObjectKey":function generateObjectKey() { + generateObjectKey: function generateObjectKey() { return Zotero.Utilities.randomString(8, Zotero.Utilities.allowedKeyChars); }, - + /** * Check if an object key is in a valid format */ - "isValidObjectKey":function(key) { + isValidObjectKey: function(key) { if (!Zotero.Utilities.objectKeyRegExp) { - Zotero.Utilities.objectKeyRegExp = new RegExp('^[' + Zotero.Utilities.allowedKeyChars + ']{8}$'); + Zotero.Utilities.objectKeyRegExp = new RegExp('^[' + Zotero.Utilities.Internal.allowedKeyChars + ']{8}$'); } return Zotero.Utilities.objectKeyRegExp.test(key); }, + + assignProps: movedToUtilitiesInternal("assignProps"), + parseURL: movedToUtilitiesInternal("parseURL"), + resolveIntermediateURL: movedToUtilitiesInternal("resolveIntermediateURL"), + determineAttachmentIcon: movedToUtilitiesInternal('determineAttachmentIcon'), - /** - * Provides unicode support and other additional features for regular expressions - * See https://github.com/slevithan/xregexp for usage - */ - "XRegExp": typeof XRegExp !== "undefined" ? XRegExp : null + // /** + // * Provides unicode support and other additional features for regular expressions + // * See https://github.com/slevithan/xregexp for usage + // */ + XRegExp: typeof XRegExp !== "undefined" ? XRegExp : null } -if (typeof process === 'object' && process + '' === '[object process]'){ - module.exports = Zotero.Utilities; +if (typeof module != 'undefined') { + module.exports = Utilities; +} else if (typeof Zotero != 'undefined') { + Zotero.Utilities = Utilities; } + +})(); diff --git a/chrome/content/zotero/xpcom/utilities_internal.js b/chrome/content/zotero/xpcom/utilities_internal.js index 11c406e951..9447a33a7e 100644 --- a/chrome/content/zotero/xpcom/utilities_internal.js +++ b/chrome/content/zotero/xpcom/utilities_internal.js @@ -984,143 +984,11 @@ Zotero.Utilities.Internal = { var doc = parser.parseFromString(responseText, 'text/html'); return Zotero.HTTP.wrapDocument(doc, url); }, - - - /** - * Converts Zotero.Item to a format expected by translators - * This is mostly the Zotero web API item JSON format, but with an attachments - * and notes arrays and optional compatibility mappings for older translators. - * - * @param {Zotero.Item} zoteroItem - * @param {Boolean} legacy Add mappings for legacy (pre-4.0.27) translators - * @return {Object} - */ - itemToExportFormat: function (zoteroItem, legacy, skipChildItems) { - function addCompatibilityMappings(item, zoteroItem) { - item.uniqueFields = {}; - - // Meaningless local item ID, but some older export translators depend on it - item.itemID = zoteroItem.id; - item.key = zoteroItem.key; // CSV translator exports this - - // "version" is expected to be a field for "computerProgram", which is now - // called "versionNumber" - delete item.version; - if (item.versionNumber) { - item.version = item.uniqueFields.version = item.versionNumber; - delete item.versionNumber; - } - - // SQL instead of ISO-8601 - item.dateAdded = zoteroItem.dateAdded; - item.dateModified = zoteroItem.dateModified; - if (item.accessDate) { - item.accessDate = zoteroItem.getField('accessDate'); - } - - // Map base fields - for (let field in item) { - let id = Zotero.ItemFields.getID(field); - if (!id || !Zotero.ItemFields.isValidForType(id, zoteroItem.itemTypeID)) { - continue; - } - - let baseField = Zotero.ItemFields.getName( - Zotero.ItemFields.getBaseIDFromTypeAndField(item.itemType, field) - ); - - if (!baseField || baseField == field) { - item.uniqueFields[field] = item[field]; - } else { - item[baseField] = item[field]; - item.uniqueFields[baseField] = item[field]; - } - } - - // Add various fields for compatibility with translators pre-4.0.27 - item.itemID = zoteroItem.id; - item.libraryID = zoteroItem.libraryID == 1 ? null : zoteroItem.libraryID; - - // Creators - if (item.creators) { - for (let i=0; i { - f = Zotero.Utilities.parseURL; - }); - - describe("#fileName", function () { - it("should contain filename", function () { - assert.propertyVal(f('http://example.com/abc/def.html?foo=bar'), 'fileName', 'def.html'); - }); - - it("should be empty if no filename", function () { - assert.propertyVal(f('http://example.com/abc/'), 'fileName', ''); - }); - }); - - describe("#fileExtension", function () { - it("should contain extension", function () { - assert.propertyVal(f('http://example.com/abc/def.html?foo=bar'), 'fileExtension', 'html'); - }); - - it("should be empty if no extension", function () { - assert.propertyVal(f('http://example.com/abc/def'), 'fileExtension', ''); - }); - - it("should be empty if no filename", function () { - assert.propertyVal(f('http://example.com/abc/'), 'fileExtension', ''); - }); - }); - - describe("#fileBaseName", function () { - it("should contain base name", function () { - assert.propertyVal(f('http://example.com/abc/def.html?foo=bar'), 'fileBaseName', 'def'); - }); - - it("should equal filename if no extension", function () { - assert.propertyVal(f('http://example.com/abc/def'), 'fileBaseName', 'def'); - }); - - it("should be empty if no filename", function () { - assert.propertyVal(f('http://example.com/abc/'), 'fileBaseName', ''); - }); - }); - }); - describe("#ellipsize()", function () { describe("with wordBoundary", function () { diff --git a/test/tests/utilities_internalTest.js b/test/tests/utilities_internalTest.js index 05a5c4ab0b..22a3d433f4 100644 --- a/test/tests/utilities_internalTest.js +++ b/test/tests/utilities_internalTest.js @@ -468,4 +468,49 @@ describe("Zotero.Utilities.Internal", function () { assert.equal(Zotero.Utilities.Internal.getNextName('Name 2', existing, true), 'Name 4'); }); }); + + describe("#parseURL()", function () { + var f; + before(() => { + f = Zotero.Utilities.Internal.parseURL; + }); + + describe("#fileName", function () { + it("should contain filename", function () { + assert.propertyVal(f('http://example.com/abc/def.html?foo=bar'), 'fileName', 'def.html'); + }); + + it("should be empty if no filename", function () { + assert.propertyVal(f('http://example.com/abc/'), 'fileName', ''); + }); + }); + + describe("#fileExtension", function () { + it("should contain extension", function () { + assert.propertyVal(f('http://example.com/abc/def.html?foo=bar'), 'fileExtension', 'html'); + }); + + it("should be empty if no extension", function () { + assert.propertyVal(f('http://example.com/abc/def'), 'fileExtension', ''); + }); + + it("should be empty if no filename", function () { + assert.propertyVal(f('http://example.com/abc/'), 'fileExtension', ''); + }); + }); + + describe("#fileBaseName", function () { + it("should contain base name", function () { + assert.propertyVal(f('http://example.com/abc/def.html?foo=bar'), 'fileBaseName', 'def'); + }); + + it("should equal filename if no extension", function () { + assert.propertyVal(f('http://example.com/abc/def'), 'fileBaseName', 'def'); + }); + + it("should be empty if no filename", function () { + assert.propertyVal(f('http://example.com/abc/'), 'fileBaseName', ''); + }); + }); + }); })