mirror of
https://github.com/ONLYOFFICE/onlyoffice.github.io.git
synced 2026-02-10 18:05:06 +08:00
variable typing
This commit is contained in:
@ -31,7 +31,7 @@
|
||||
<script src="scripts/citeproc/citeproc_commonjs.js"></script>
|
||||
|
||||
<script src="scripts/csl/citation/citation-item-data.js"></script>
|
||||
<script src="scripts/csl/citation/citation-tem.js"></script>
|
||||
<script src="scripts/csl/citation/citation-item.js"></script>
|
||||
<script src="scripts/csl/citation/citation.js"></script>
|
||||
<script src="scripts/csl/citation/storage.js"></script>
|
||||
|
||||
@ -74,7 +74,7 @@
|
||||
<div class="selectHolder">
|
||||
<input id="library" readonly class="control select" type="text">
|
||||
<div id="searchLibrary" class="selectList display-none">
|
||||
<span data-value="all" class="i18n">All groups</span>
|
||||
<span data-value="all" class="i18n" selected>All groups</span>
|
||||
</div>
|
||||
</div>
|
||||
<label id="searchLabel">
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
// @ts-check
|
||||
|
||||
/// <reference path="./types-global.js" />
|
||||
/// <reference path="./csl/citation/citation.js" />
|
||||
/// <reference path="./csl/styles/style-parser.js" />
|
||||
|
||||
/**
|
||||
* @typedef {Object} CustomField
|
||||
* @property {string} Value
|
||||
@ -7,15 +11,6 @@
|
||||
* @property {string} [FieldId]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} SupSubPositions
|
||||
* @property {'sup'|'sub'} type
|
||||
* @property {number} start
|
||||
* @property {number} end
|
||||
* @property {string} content
|
||||
* @property {string} originalMatch
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {string} citPrefix
|
||||
* @param {string} citSuffix
|
||||
|
||||
@ -15,6 +15,10 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
/// <reference path="./zotero.js" />
|
||||
/// <reference path="./csl/citation/citation.js" />
|
||||
/// <reference path="./csl/styles/styles-manager.js" />
|
||||
|
||||
(function () {
|
||||
var counter = 0; // счетчик отправленных запросов (используется чтобы знать показывать "not found" или нет)
|
||||
var displayNoneClass = "display-none";
|
||||
@ -64,6 +68,7 @@
|
||||
var selectedLocale;
|
||||
var selectedStyle;
|
||||
|
||||
/** @type {ZoteroSdk} */
|
||||
var sdk = null;
|
||||
var cslStylesManager = null;
|
||||
var citationDocService = null;
|
||||
@ -126,7 +131,7 @@
|
||||
showLoader(true);
|
||||
setTimeout(function () { searchField.focus(); },100);
|
||||
|
||||
sdk = ZoteroSdk();
|
||||
sdk = new ZoteroSdk();
|
||||
cslStylesManager = new CslStylesManager();
|
||||
addEventListeners();
|
||||
|
||||
@ -826,6 +831,15 @@
|
||||
docsScroller.onscroll();
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Promise} promise
|
||||
* @param {boolean} append
|
||||
* @param {boolean} showLoader
|
||||
* @param {boolean} hideLoader
|
||||
* @param {boolean} isGroup
|
||||
* @param {boolean} bCount
|
||||
* @returns {Promise}
|
||||
*/
|
||||
function loadLibrary(promise, append, showLoader, hideLoader, isGroup, bCount) {
|
||||
if (showLoader) showLibLoader(true);
|
||||
if (bCount) counter++;
|
||||
|
||||
@ -127,11 +127,18 @@ CitationItemData.prototype._addCustomProperty = function (key, value) {
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @returns
|
||||
*/
|
||||
CitationItemData.prototype.getCustomProperty = function (key) {
|
||||
if (Object.hasOwnProperty.call(this._custom, key)) return this._custom[key];
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {any} itemDataObject
|
||||
*/
|
||||
CitationItemData.prototype.fillFromObject = function (itemDataObject) {
|
||||
if (Object.hasOwnProperty.call(itemDataObject, "type")) {
|
||||
this._type = itemDataObject.type;
|
||||
@ -448,7 +455,10 @@ CitationItemData.prototype.fillFromObject = function (itemDataObject) {
|
||||
}
|
||||
|
||||
if (Object.hasOwnProperty.call(itemDataObject, "creators")) {
|
||||
itemDataObject.creators.forEach(function (creator) {
|
||||
const self = this;
|
||||
itemDataObject.creators.forEach(function (
|
||||
/** @type {{firstName: string, lastName: string}}} */ creator
|
||||
) {
|
||||
let author = {};
|
||||
if (creator.firstName) {
|
||||
author.given = creator.firstName;
|
||||
@ -456,8 +466,9 @@ CitationItemData.prototype.fillFromObject = function (itemDataObject) {
|
||||
if (creator.lastName) {
|
||||
author.family = creator.lastName;
|
||||
}
|
||||
this._author.push(author);
|
||||
}, this);
|
||||
self._author.push(author);
|
||||
},
|
||||
this);
|
||||
}
|
||||
|
||||
if (Object.hasOwnProperty.call(itemDataObject, "libraryCatalog")) {
|
||||
|
||||
@ -1,3 +1,16 @@
|
||||
// @ts-check
|
||||
/// <reference path="./citation-item-data.js" />
|
||||
/**
|
||||
* @typedef {Object} OldCitationItem - before version 1.0.5
|
||||
* @property {string|number} id
|
||||
* @property {string} [type]
|
||||
* @property {string} [title]
|
||||
* @property {string} [userID]
|
||||
* @property {string} [groupID]
|
||||
* @property {number} index
|
||||
* @property {boolean} [`suppress-author`]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {string|number} id
|
||||
*/
|
||||
@ -17,7 +30,11 @@ function CitationItem(id) {
|
||||
this._uris = new Array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} itemObject
|
||||
*/
|
||||
CitationItem.prototype.fillFromObject = function (itemObject) {
|
||||
const self = this;
|
||||
if (
|
||||
Object.hasOwnProperty.call(itemObject, "version") &&
|
||||
Object.hasOwnProperty.call(itemObject, "library")
|
||||
@ -50,12 +67,15 @@ CitationItem.prototype.fillFromObject = function (itemObject) {
|
||||
if (Object.hasOwnProperty.call(itemObject, "author-only"))
|
||||
this._authorOnly = itemObject["author-only"];
|
||||
if (Object.hasOwnProperty.call(itemObject, "uris")) {
|
||||
itemObject.uris.forEach(function (uri) {
|
||||
this.addUri(uri);
|
||||
itemObject.uris.forEach(function (/** @type {string} */ uri) {
|
||||
self.addUri(uri);
|
||||
}, this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @returns {SuppressAuthor}
|
||||
*/
|
||||
CitationItem.prototype.getSuppressAuthor = function () {
|
||||
return {
|
||||
id: this.id,
|
||||
@ -209,7 +229,12 @@ CitationItem.prototype.toJSON = function () {
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} index
|
||||
* @returns
|
||||
*/
|
||||
CitationItem.prototype.toFlatJSON = function (index) {
|
||||
/** @type {OldCitationItem} */
|
||||
var oldItem = {
|
||||
id: this.id,
|
||||
index: index,
|
||||
@ -221,11 +246,17 @@ CitationItem.prototype.toFlatJSON = function (index) {
|
||||
let itemDataObject = this._itemData.toJSON();
|
||||
Object.assign(oldItem, itemDataObject);
|
||||
|
||||
if (this._itemData.getCustomProperty("userID") !== null) {
|
||||
oldItem.userID = this._itemData.getCustomProperty("userID");
|
||||
if (
|
||||
typeof this._itemData.getCustomProperty("userID") !== "undefined" &&
|
||||
this._itemData.getCustomProperty("userID") !== null
|
||||
) {
|
||||
oldItem.userID = String(this._itemData.getCustomProperty("userID"));
|
||||
}
|
||||
if (this._itemData.getCustomProperty("groupID") !== null) {
|
||||
oldItem.groupID = this._itemData.getCustomProperty("groupID");
|
||||
if (
|
||||
typeof this._itemData.getCustomProperty("groupID") !== "undefined" &&
|
||||
this._itemData.getCustomProperty("groupID") !== null
|
||||
) {
|
||||
oldItem.groupID = String(this._itemData.getCustomProperty("groupID"));
|
||||
}
|
||||
|
||||
return oldItem;
|
||||
@ -1,7 +1,10 @@
|
||||
// @ts-check
|
||||
/// <reference path="./citation-item.js" />
|
||||
|
||||
/**
|
||||
* @typedef {Object} SuppressAuthor
|
||||
* @property {string} id
|
||||
* @property {boolean} "suppress-author"
|
||||
* @property {string|number} id
|
||||
* @property {boolean} `suppress-author`
|
||||
*/
|
||||
|
||||
/**
|
||||
@ -40,6 +43,7 @@ function CSLCitation(itemsStartIndex, citationID) {
|
||||
/** @type {string} */
|
||||
this.citationID = citationID;
|
||||
this._itemsStartIndex = itemsStartIndex;
|
||||
/** @type {Array<CitationItem>} */
|
||||
this._citationItems = new Array();
|
||||
this._properties = new Object();
|
||||
|
||||
@ -48,7 +52,7 @@ function CSLCitation(itemsStartIndex, citationID) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} citationObject
|
||||
* @param {any} citationObject
|
||||
* @returns
|
||||
*/
|
||||
CSLCitation.prototype.fillFromObject = function (citationObject) {
|
||||
@ -69,7 +73,12 @@ CSLCitation.prototype.fillFromObject = function (citationObject) {
|
||||
return this._fillFromCslJson(citationObject);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {any} citationObject
|
||||
* @returns
|
||||
*/
|
||||
CSLCitation.prototype._fillFromCitationObject = function (citationObject) {
|
||||
const self = this;
|
||||
if (Object.hasOwnProperty.call(citationObject, "schema")) {
|
||||
// this._setSchema(citationObject.schema);
|
||||
}
|
||||
@ -86,11 +95,13 @@ CSLCitation.prototype._fillFromCitationObject = function (citationObject) {
|
||||
return item.id;
|
||||
});
|
||||
|
||||
citationObject.citationItems.forEach(function (item) {
|
||||
citationObject.citationItems.forEach(function (
|
||||
/** @type {CitationItem} */ item
|
||||
) {
|
||||
let id = item.id;
|
||||
let citationItem;
|
||||
if (existingIds.indexOf(id) >= 0) {
|
||||
citationItem = this._citationItems[existingIds.indexOf(id)];
|
||||
citationItem = self._citationItems[existingIds.indexOf(id)];
|
||||
} else {
|
||||
citationItem = new CitationItem(id);
|
||||
existingIds.push(id);
|
||||
@ -98,21 +109,23 @@ CSLCitation.prototype._fillFromCitationObject = function (citationObject) {
|
||||
|
||||
if (typeof id === "number") {
|
||||
// Word 365 or wps
|
||||
id = this._extractIdFromWord365Citation(item);
|
||||
id = self._extractIdFromWord365Citation(item);
|
||||
}
|
||||
|
||||
citationItem.fillFromObject(item);
|
||||
|
||||
this._addCitationItem(citationItem);
|
||||
}, this);
|
||||
self._addCitationItem(citationItem);
|
||||
},
|
||||
this);
|
||||
return existingIds.length;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {{citationObject: Array<{id: string, index: number, "suppress-author": boolean, title: string, type: string, userID: string, groupID: string}>}} citationObject
|
||||
* @param {{citationItems: OldCitationItem[]}} citationObject
|
||||
* @returns
|
||||
*/
|
||||
CSLCitation.prototype._fillFromFlatCitationObject = function (citationObject) {
|
||||
const self = this;
|
||||
if (citationObject.citationItems.length === 0) {
|
||||
console.error("CSLCitation.citationItems: citationItems is empty");
|
||||
return 0;
|
||||
@ -123,14 +136,14 @@ CSLCitation.prototype._fillFromFlatCitationObject = function (citationObject) {
|
||||
}
|
||||
|
||||
citationObject.citationItems.forEach(function (itemObject) {
|
||||
this._fillFromCslJson(itemObject);
|
||||
self._fillFromCslJson(itemObject);
|
||||
}, this);
|
||||
|
||||
return 1;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {Object} citationObject
|
||||
* @param {any} itemObject
|
||||
* @returns
|
||||
*/
|
||||
CSLCitation.prototype._fillFromCslJson = function (itemObject) {
|
||||
@ -155,7 +168,7 @@ CSLCitation.prototype._fillFromCslJson = function (itemObject) {
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {{key: string, version: number, library: Object, links: Object, meta: Object, data: CitationJsonData}} citationObject
|
||||
* @param {{key: string, version: number, library: Object, links: Object, meta: Object, data: CitationJsonData}} itemObject
|
||||
* @returns
|
||||
*/
|
||||
CSLCitation.prototype._fillFromJson = function (itemObject) {
|
||||
@ -195,6 +208,10 @@ CSLCitation.prototype.getSuppressAuthors = function () {
|
||||
}, this);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
* @returns
|
||||
*/
|
||||
CSLCitation.prototype.getProperty = function (key) {
|
||||
let items = this._citationItems;
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
@ -207,6 +224,10 @@ CSLCitation.prototype.getProperty = function (key) {
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {CitationItem} item
|
||||
* @returns
|
||||
*/
|
||||
CSLCitation.prototype._addCitationItem = function (item) {
|
||||
const existingIds = this._citationItems.map(function (item) {
|
||||
return item.id;
|
||||
@ -219,17 +240,26 @@ CSLCitation.prototype._addCitationItem = function (item) {
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {object} properties
|
||||
* @returns
|
||||
*/
|
||||
CSLCitation.prototype._setProperties = function (properties) {
|
||||
this._properties = properties;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} schema
|
||||
* @returns
|
||||
*/
|
||||
CSLCitation.prototype._setSchema = function (schema) {
|
||||
this._schema = schema;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {any} item
|
||||
* @returns {string}
|
||||
*/
|
||||
CSLCitation.prototype._extractIdFromWord365Citation = function (item) {
|
||||
@ -265,9 +295,10 @@ CSLCitation.prototype.validate = function () {
|
||||
};
|
||||
|
||||
CSLCitation.prototype.toJSON = function () {
|
||||
var result = {
|
||||
var result = /** @type {any} */ ({
|
||||
citationID: this.citationID,
|
||||
};
|
||||
schema: this._schema,
|
||||
});
|
||||
|
||||
if (this._properties && Object.keys(this._properties).length > 0) {
|
||||
result.properties = this._properties;
|
||||
@ -275,11 +306,9 @@ CSLCitation.prototype.toJSON = function () {
|
||||
|
||||
if (this._citationItems && this._citationItems.length > 0) {
|
||||
result.citationItems = this._citationItems.map(function (item) {
|
||||
return item.toJSON ? item.toJSON() : item;
|
||||
return item.toJSON();
|
||||
});
|
||||
}
|
||||
|
||||
result.schema = this._schema;
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
// @ts-check
|
||||
/// <reference path="./storage.js" />
|
||||
/// <reference path="./style-parser.js" />
|
||||
|
||||
function CslStylesManager() {
|
||||
this._isOnlineAvailable = false;
|
||||
|
||||
127
sdkjs-plugins/content/zotero/scripts/types-global.js
Normal file
127
sdkjs-plugins/content/zotero/scripts/types-global.js
Normal file
@ -0,0 +1,127 @@
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* @typedef {Object} AscSimpleRequestParams
|
||||
* @property {string} url
|
||||
* @property {"GET"|"POST"} method
|
||||
* @property {object} headers
|
||||
* @property {string} [body]
|
||||
* @property {function(AscSimpleResponse, string): void} complete
|
||||
* @property {function(AscSimpleResponse, string, Error): void} error
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} AscSimpleRequest
|
||||
* @property {function(AscSimpleRequestParams): void} createRequest
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} AscSimpleResponse
|
||||
* @property {number} responseStatus
|
||||
* @property {string} responseText
|
||||
* @property {string} [message]
|
||||
* @property {string} status
|
||||
* @property {number} statusCode
|
||||
*/
|
||||
|
||||
/** @type {AscSimpleRequest} */
|
||||
var AscSimpleRequest = window.AscSimpleRequest;
|
||||
|
||||
/** ------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* @typedef {Object} SupSubPositions
|
||||
* @property {'sup'|'sub'} type
|
||||
* @property {number} start
|
||||
* @property {number} end
|
||||
* @property {string} content
|
||||
* @property {string} originalMatch
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} AscPluginTheme
|
||||
* @property {string} `text-normal`
|
||||
* @property {string} `background-normal`
|
||||
* @property {string} `highlight-button-hover`
|
||||
* @property {string} `highlight-button-pressed`
|
||||
* @property {string} `border-regular-control`
|
||||
* @property {string} `border-toolbar`
|
||||
* @property {string} `border-divider`
|
||||
* @property {string} `background-toolbar`
|
||||
* @property {string} RulerLight
|
||||
* @property {string} Color - text color
|
||||
* @property {string} type - light/dark
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback ExecuteCommandCallback
|
||||
* @param {string} command
|
||||
* @param {any} [value]
|
||||
* @param {function} [callback]
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback CallCommandCallback
|
||||
* @param {function} command
|
||||
* @param {boolean} [isClose]
|
||||
* @param {boolean} [isCalc]
|
||||
* @param {function} [callback]
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} AscPlugin
|
||||
* @property {function(string, Array<any>|null, function(any): void): void} executeMethod
|
||||
* @property {ExecuteCommandCallback} executeCommand
|
||||
* @property {CallCommandCallback} callCommand
|
||||
* @property {function(): void} init
|
||||
* @property {object} info
|
||||
* @property {function(string): void} sendToPlugin
|
||||
* @property {function} onTranslate
|
||||
* @property {function(string, function): void} attachEvent
|
||||
* @property {string} onThemeChanged
|
||||
* @property {function(string): void} onThemeChangedBase
|
||||
* @property {AscPluginTheme} theme
|
||||
* @property {function(string): string} tr
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} Asc
|
||||
* @property {AscPlugin} plugin
|
||||
* @property {{positions: Array<SupSubPositions>}} scope
|
||||
*/
|
||||
|
||||
/** @type {Asc} */
|
||||
var Asc = window.Asc;
|
||||
|
||||
/** ------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* @typedef {Object} Api
|
||||
* @property {function(): any} GetDocument
|
||||
*/
|
||||
|
||||
/** @type {Api} */
|
||||
var Api = window.Api;
|
||||
|
||||
/** ------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* @typedef {Object} FetchResponse
|
||||
* @property {function(): Promise<ArrayBuffer>} arrayBuffer
|
||||
* @property {function(): Promise<Blob>} blob
|
||||
* @property {function(): Promise<Object>} json
|
||||
* @property {function(): Promise<string>} text
|
||||
* @property {boolean} ok
|
||||
* @property {number} status
|
||||
* @property {string} statusText
|
||||
* @property {Headers} headers
|
||||
* @property {string} type
|
||||
* @property {string} url
|
||||
* @property {boolean} redirected
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Promise<FetchResponse>} FetchPromise
|
||||
*/
|
||||
@ -1,3 +1,8 @@
|
||||
// @ts-check
|
||||
/// <reference path="./types-global.js" />
|
||||
/// <reference path="./zotero.js" />
|
||||
/// <reference path="./zotero-environment.js" />
|
||||
|
||||
/**
|
||||
* @typedef {Object} AvailableApis
|
||||
* @property {boolean} desktop
|
||||
@ -14,7 +19,8 @@ var ZoteroApiChecker = {
|
||||
_online: false,
|
||||
_hasKey: false,
|
||||
_timeout: 1000, // 1 second
|
||||
_callback: function () {},
|
||||
/** @type {function(AvailableApis): void} */
|
||||
_callback: function (e) {},
|
||||
_desktopVersion: (function () {
|
||||
if (
|
||||
window.navigator &&
|
||||
@ -24,15 +30,17 @@ var ZoteroApiChecker = {
|
||||
)
|
||||
return false;
|
||||
if (window.location && window.location.protocol == "file:") return true;
|
||||
if (
|
||||
window.document &&
|
||||
window.document.currentScript &&
|
||||
0 == window.document.currentScript.src.indexOf("file:///")
|
||||
)
|
||||
return true;
|
||||
const src = window.document.currentScript
|
||||
? window.document.currentScript.getAttribute("src")
|
||||
: "";
|
||||
if (src && 0 == src.indexOf("file:///")) return true;
|
||||
return false;
|
||||
})(),
|
||||
|
||||
/**
|
||||
* @param {ZoteroSdk} sdk
|
||||
* @returns
|
||||
*/
|
||||
runApisChecker: function (sdk) {
|
||||
const self = this;
|
||||
|
||||
@ -55,15 +63,21 @@ var ZoteroApiChecker = {
|
||||
attemptCheck();
|
||||
|
||||
return {
|
||||
subscribe: function (callbackFn) {
|
||||
subscribe: function (
|
||||
/** @type {function(AvailableApis): void} */ callbackFn
|
||||
) {
|
||||
self._callback = callbackFn;
|
||||
},
|
||||
unsubscribe: function () {
|
||||
done = true;
|
||||
callback = function () {};
|
||||
self._done = true;
|
||||
self._callback = function () {};
|
||||
},
|
||||
};
|
||||
},
|
||||
/**
|
||||
* @param {ZoteroSdk} sdk
|
||||
* @returns
|
||||
*/
|
||||
checkStatus: function (sdk) {
|
||||
return this._checkApiAvailable(sdk);
|
||||
},
|
||||
@ -77,7 +91,10 @@ var ZoteroApiChecker = {
|
||||
desktopVersion: this._desktopVersion,
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {ZoteroSdk} sdk
|
||||
* @returns
|
||||
*/
|
||||
_checkApiAvailable: function (sdk) {
|
||||
const self = this;
|
||||
return new Promise(function (resolve) {
|
||||
@ -115,6 +132,10 @@ var ZoteroApiChecker = {
|
||||
});
|
||||
});
|
||||
},
|
||||
/**
|
||||
* @param {string} url
|
||||
* @returns
|
||||
*/
|
||||
_sendDesktopRequest: function (url) {
|
||||
const self = this;
|
||||
return new Promise(function (resolve, reject) {
|
||||
@ -132,7 +153,8 @@ var ZoteroApiChecker = {
|
||||
"Zotero-API-Version": "3",
|
||||
"User-Agent": "AscDesktopEditor",
|
||||
},
|
||||
complete: function (e) {
|
||||
complete: function (/** @type {AscSimpleResponse} */ e) {
|
||||
console.warn(e);
|
||||
let hasPermission = false;
|
||||
let isZoteroRunning = false;
|
||||
if (e.responseStatus == 403) {
|
||||
@ -147,7 +169,7 @@ var ZoteroApiChecker = {
|
||||
isZoteroRunning: isZoteroRunning,
|
||||
});
|
||||
},
|
||||
error: function (e) {
|
||||
error: function (/** @type {AscSimpleResponse} */ e) {
|
||||
if (e.statusCode == -102) e.statusCode = 404;
|
||||
reject(e);
|
||||
},
|
||||
|
||||
@ -16,315 +16,509 @@
|
||||
*
|
||||
*/
|
||||
|
||||
// @ts-check
|
||||
/// <reference path="./types-global.js" />
|
||||
/// <reference path="./zotero-environment.js" />
|
||||
|
||||
/**
|
||||
* @typedef {Object} ZoteroGroupInfo
|
||||
* @property {number} id
|
||||
* @property {number} version
|
||||
* @property {{alternate: {href: string, type: string}, self: {href: string, type: string}}} meta
|
||||
* @property {{created: string, lastModified: string, numItems: number}} links
|
||||
* @property {{name: string, description: string, id: number, owner: number, type: string}} data
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} UserGroupInfo
|
||||
* @property {number} id
|
||||
* @property {string} name
|
||||
*/
|
||||
|
||||
const ZoteroSdk = function () {
|
||||
var apiKey;
|
||||
var userId = 0;
|
||||
var userGroups = [];
|
||||
var isOnlineAvailable = true;
|
||||
this._apiKey = null;
|
||||
this._userId = 0;
|
||||
/** @type {Array<UserGroupInfo>}} */
|
||||
this._userGroups = [];
|
||||
this._isOnlineAvailable = true;
|
||||
};
|
||||
|
||||
function getRequestWithOfflineSupport(url) {
|
||||
if (isOnlineAvailable) {
|
||||
return getRequest(url);
|
||||
} else {
|
||||
return getDesktopRequest(url.href);
|
||||
}
|
||||
}
|
||||
// Constants
|
||||
ZoteroSdk.prototype.ZOTERO_API_VERSION = "3";
|
||||
ZoteroSdk.prototype.USER_AGENT = "AscDesktopEditor";
|
||||
ZoteroSdk.prototype.DEFAULT_FORMAT = "csljson";
|
||||
ZoteroSdk.prototype.STORAGE_KEYS = {
|
||||
USER_ID: "zoteroUserId",
|
||||
API_KEY: "zoteroApiKey",
|
||||
};
|
||||
ZoteroSdk.prototype.API_PATHS = {
|
||||
USERS: "users",
|
||||
GROUPS: "groups",
|
||||
ITEMS: "items",
|
||||
KEYS: "keys",
|
||||
};
|
||||
|
||||
/**
|
||||
* Make a GET request to the local Zotero API.
|
||||
* @param {string} url - URL of the request.
|
||||
* @returns {Promise<{responseStatus: number, responseText: string, status: string, statusCode: number}>}
|
||||
*/
|
||||
function getDesktopRequest(url) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
window.AscSimpleRequest.createRequest({
|
||||
url: url,
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Zotero-API-Version": "3",
|
||||
"User-Agent": "AscDesktopEditor",
|
||||
},
|
||||
complete: function(e) {
|
||||
resolve(e);
|
||||
},
|
||||
error: function(e) {
|
||||
if ( e.statusCode == -102 ) {
|
||||
e.statusCode = 404;
|
||||
e.message = "Connection to Zotero failed. Make sure Zotero is running";
|
||||
}
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Get appropriate base URL based on online/offline mode
|
||||
*/
|
||||
ZoteroSdk.prototype._getBaseUrl = function () {
|
||||
return this._isOnlineAvailable
|
||||
? zoteroEnvironment.restApiUrl
|
||||
: zoteroEnvironment.desktopApiUrl;
|
||||
};
|
||||
|
||||
/**
|
||||
* Make a GET request to the online Zotero API.
|
||||
* @param {string} url - URL of the request.
|
||||
* @returns {Promise<{body: ReadableStream, bodyUsed: boolean, headers: Headers, ok: boolean, redirected: boolean, status: string, statusText: string, type: string, url: string}>}
|
||||
*/
|
||||
function getRequest(url) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var headers = {
|
||||
"Zotero-API-Version": "3"
|
||||
};
|
||||
if (apiKey) headers["Zotero-API-Key"] = apiKey;
|
||||
fetch(url, {
|
||||
headers: headers
|
||||
}).then(function (res) {
|
||||
if (!res.ok) {
|
||||
reject(new Error(res.status + " " + res.statusText));
|
||||
return;
|
||||
};
|
||||
resolve(res);
|
||||
}).catch(function (err) {
|
||||
if (typeof err === "object") {
|
||||
console.error(err.message);
|
||||
err.message = "Connection to Zotero failed";
|
||||
}
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Get locales URL based on online/offline mode
|
||||
*/
|
||||
ZoteroSdk.prototype._getLocalesUrl = function () {
|
||||
return this._isOnlineAvailable
|
||||
? zoteroEnvironment.localesUrl
|
||||
: zoteroEnvironment.localesPath;
|
||||
};
|
||||
|
||||
function buildGetRequest(path, query) {
|
||||
var url = new URL(path, zoteroEnvironment.restApiUrl);
|
||||
if (!isOnlineAvailable) {
|
||||
url = new URL(path, zoteroEnvironment.desktopApiUrl);
|
||||
}
|
||||
for (var key in query) url.searchParams.append(key, query[key]);
|
||||
return getRequestWithOfflineSupport(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves items from the Zotero API.
|
||||
* @param {string} [search] - Search query.
|
||||
* @param {string[]} [itemsID] - IDs of items to retrieve.
|
||||
* @param {string} [format]
|
||||
* @returns {Promise<{body: ReadableStream, bodyUsed: boolean, headers: Headers, ok: boolean, redirected: boolean, status: string, statusText: string, type: string, url: string}>}
|
||||
*/
|
||||
function getItems(search, itemsID, format) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
format = format || "csljson";
|
||||
var props = {
|
||||
format: format
|
||||
};
|
||||
if (search) {
|
||||
props.q = search;
|
||||
} else if (itemsID) {
|
||||
props.itemKey = itemsID.join(',');
|
||||
}
|
||||
if (isOnlineAvailable) {
|
||||
parseItemsResponse(buildGetRequest("users/" + userId + "/items", props), resolve, reject, userId);
|
||||
} else {
|
||||
parseDesktopItemsResponse(buildGetRequest("users/" + userId + "/items", props), resolve, reject, userId);
|
||||
/**
|
||||
* Make a GET request to the local Zotero API (offline mode)
|
||||
* @param {string} url
|
||||
* @returns {Promise<AscSimpleResponse>}
|
||||
*/
|
||||
ZoteroSdk.prototype._getDesktopRequest = function (url) {
|
||||
var self = this;
|
||||
return new Promise(function (resolve, reject) {
|
||||
window.AscSimpleRequest.createRequest({
|
||||
url: url,
|
||||
method: "GET",
|
||||
headers: {
|
||||
"Zotero-API-Version": self.ZOTERO_API_VERSION,
|
||||
"User-Agent": self.USER_AGENT,
|
||||
},
|
||||
complete: resolve,
|
||||
error: function (/** @type {AscSimpleResponse} */ error) {
|
||||
if (error.statusCode === -102) {
|
||||
error.statusCode = 404;
|
||||
error.message =
|
||||
"Connection to Zotero failed. Make sure Zotero is running";
|
||||
}
|
||||
});
|
||||
}
|
||||
reject(error);
|
||||
},
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function getGroupItems(search, groupId, itemsID, format) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
format = format || "csljson";
|
||||
var props = {
|
||||
format: format
|
||||
};
|
||||
if (search) {
|
||||
props.q = search;
|
||||
} else if (itemsID) {
|
||||
props.itemKey = itemsID.join(',');
|
||||
}
|
||||
if (isOnlineAvailable) {
|
||||
parseItemsResponse(buildGetRequest("groups/" + groupId + "/items", props), resolve, reject, groupId);
|
||||
} else {
|
||||
parseDesktopItemsResponse(buildGetRequest("groups/" + groupId + "/items", props), resolve, reject, groupId);
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Make a GET request to the online Zotero API
|
||||
* @param {URL} url
|
||||
* @returns {Promise<FetchResponse>}
|
||||
*/
|
||||
ZoteroSdk.prototype._getOnlineRequest = function (url) {
|
||||
var self = this;
|
||||
var headers = {
|
||||
"Zotero-API-Version": self.ZOTERO_API_VERSION,
|
||||
"Zotero-API-Key": self._apiKey || "",
|
||||
};
|
||||
|
||||
function getLocale(langTag) {
|
||||
let url = zoteroEnvironment.localesPath;
|
||||
if (isOnlineAvailable) {
|
||||
url = zoteroEnvironment.localesUrl;
|
||||
return fetch(url, { headers: headers })
|
||||
.then(function (response) {
|
||||
if (!response.ok) {
|
||||
throw new Error(response.status + " " + response.statusText);
|
||||
}
|
||||
return fetch(url + "locales-" + langTag + ".xml")
|
||||
.then(function (resp) { return resp.text(); });
|
||||
}
|
||||
return response;
|
||||
})
|
||||
.catch(function (error) {
|
||||
console.error("Zotero API request failed:", error.message);
|
||||
if (typeof error === "object") {
|
||||
error.message = "Connection to Zotero failed";
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
|
||||
function getUserGroups() {
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (userGroups.length > 0) {
|
||||
resolve(userGroups);
|
||||
} else {
|
||||
buildGetRequest("users/" + userId + "/groups").then(function (res) {
|
||||
if (isOnlineAvailable) {
|
||||
if (!res.ok)
|
||||
throw new Error(res.status + " " + res.statusText);
|
||||
return res.json();
|
||||
}
|
||||
return JSON.parse(res.responseText);
|
||||
}).then(function (res) {
|
||||
res.forEach(function(el) {
|
||||
userGroups.push({
|
||||
id: el.id,
|
||||
name: el.data.name
|
||||
});
|
||||
});
|
||||
resolve(userGroups);
|
||||
}).catch(function (err) {
|
||||
reject(err);
|
||||
/**
|
||||
* Universal request handler with offline support
|
||||
* @param {URL} url
|
||||
* @returns {Promise<AscSimpleResponse | FetchResponse>}
|
||||
*/
|
||||
ZoteroSdk.prototype._getRequestWithOfflineSupport = function (url) {
|
||||
return this._isOnlineAvailable
|
||||
? this._getOnlineRequest(url)
|
||||
: this._getDesktopRequest(url.href);
|
||||
};
|
||||
|
||||
/**
|
||||
* Build URL and make GET request
|
||||
* @param {string} path
|
||||
* @param {*} [queryParams]
|
||||
* @returns {Promise<AscSimpleResponse | FetchResponse>}
|
||||
*/
|
||||
ZoteroSdk.prototype._buildGetRequest = function (path, queryParams) {
|
||||
queryParams = queryParams || {};
|
||||
var url = new URL(path, this._getBaseUrl());
|
||||
|
||||
Object.keys(queryParams).forEach(function (key) {
|
||||
if (queryParams[key] !== undefined && queryParams[key] !== null) {
|
||||
url.searchParams.append(key, queryParams[key]);
|
||||
}
|
||||
});
|
||||
|
||||
return this._getRequestWithOfflineSupport(url);
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse link header for pagination
|
||||
* @param {string} headerValue
|
||||
* @returns {{[key: string]: string}}
|
||||
*/
|
||||
ZoteroSdk.prototype._parseLinkHeader = function (headerValue) {
|
||||
/** @type {{[key: string]: string}} */
|
||||
var links = {};
|
||||
var linkHeaderRegex = /<(.*?)>; rel="(.*?)"/g;
|
||||
|
||||
if (!headerValue) return links;
|
||||
|
||||
var match;
|
||||
while ((match = linkHeaderRegex.exec(headerValue.trim())) !== null) {
|
||||
links[match[2]] = match[1];
|
||||
}
|
||||
|
||||
return links;
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse response for desktop (offline) mode
|
||||
* @param {Promise<AscSimpleResponse>} promise
|
||||
* @param {function(any): void} resolve
|
||||
* @param {function(any): void} reject
|
||||
* @param {number} id
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
ZoteroSdk.prototype._parseDesktopItemsResponse = function (
|
||||
promise,
|
||||
resolve,
|
||||
reject,
|
||||
id
|
||||
) {
|
||||
var self = this;
|
||||
return promise
|
||||
.then(function (response) {
|
||||
return {
|
||||
items: { items: JSON.parse(response.responseText) },
|
||||
id: id,
|
||||
};
|
||||
})
|
||||
.then(resolve)
|
||||
.catch(reject);
|
||||
};
|
||||
|
||||
/**
|
||||
* Parse response for online mode with pagination support
|
||||
* @param {Promise<FetchResponse>} promise
|
||||
* @param {function(any): void} resolve
|
||||
* @param {function(any): void} reject
|
||||
* @param {number} id
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
ZoteroSdk.prototype._parseItemsResponse = function (
|
||||
promise,
|
||||
resolve,
|
||||
reject,
|
||||
id
|
||||
) {
|
||||
var self = this;
|
||||
return promise
|
||||
.then(function (response) {
|
||||
return Promise.all([response.json(), response]);
|
||||
})
|
||||
.then(function (results) {
|
||||
var json = results[0];
|
||||
var response = results[1];
|
||||
var links = self._parseLinkHeader(
|
||||
response.headers.get("Link") || ""
|
||||
);
|
||||
/** @type {{items: any, id: number, next?: function(): Promise<void>}} */
|
||||
var result = {
|
||||
items: json,
|
||||
id: id,
|
||||
};
|
||||
|
||||
if (links.next) {
|
||||
result.next = function () {
|
||||
return new Promise(function (rs, rj) {
|
||||
self._parseItemsResponse(
|
||||
self._getOnlineRequest(new URL(links.next)),
|
||||
rs,
|
||||
rj,
|
||||
id
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
function format(ids, key, style, locale) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var request;
|
||||
if (key) {
|
||||
request = buildGetRequest("groups/" + key + "/items", {
|
||||
format: "bib",
|
||||
style: style,
|
||||
locale: locale,
|
||||
itemKey: ids.join(",")
|
||||
})
|
||||
} else {
|
||||
request = buildGetRequest("users/" + userId + "/items", {
|
||||
format: "bib",
|
||||
style: style,
|
||||
locale: locale,
|
||||
itemKey: ids.join(",")
|
||||
})
|
||||
}
|
||||
request.then(function (res) {
|
||||
resolve(res.text());
|
||||
}).catch(function (err) {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function setApiKey(key) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
buildGetRequest("keys/" + key)
|
||||
.then(function (res) {
|
||||
if (!res.ok) throw new Error(res.status + " " + res.statusText);
|
||||
return res.json();
|
||||
}).then(function (res) {
|
||||
saveSettings(res.userID, key);
|
||||
resolve(true);
|
||||
}).catch(function (err) {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function applySettings(id, key) {
|
||||
userId = id;
|
||||
apiKey = key;
|
||||
}
|
||||
|
||||
function saveSettings(id, key) {
|
||||
applySettings(id, key);
|
||||
localStorage.setItem("zoteroUserId", id);
|
||||
localStorage.setItem("zoteroApiKey", key);
|
||||
}
|
||||
|
||||
function getSettings() {
|
||||
var uid = localStorage.getItem("zoteroUserId");
|
||||
var key = localStorage.getItem("zoteroApiKey");
|
||||
|
||||
var configured = !(!uid || !key);
|
||||
if (configured) applySettings(uid, key);
|
||||
return configured;
|
||||
}
|
||||
|
||||
function clearSettings() {
|
||||
localStorage.removeItem("zoteroUserId");
|
||||
localStorage.removeItem("zoteroApiKey");
|
||||
userGroups = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Promise} promise - promise from items request
|
||||
* @param {function} resolve - resolve function for returned promise
|
||||
* @param {function} reject - reject function for returned promise
|
||||
* @param {string} id - id of request
|
||||
* @returns {Promise<{items: {items: Array<Object>}, id: string}}>} promise with items and optional next function
|
||||
*/
|
||||
function parseDesktopItemsResponse(promise, resolve, reject, id) {
|
||||
promise.then(function (res) {
|
||||
var obj = {
|
||||
items: {items: JSON.parse(res.responseText)},
|
||||
id: id
|
||||
};
|
||||
resolve(obj);
|
||||
}).catch(function (err) {
|
||||
reject(err);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Promise} promise - promise from items request
|
||||
* @param {function} resolve - resolve function for returned promise
|
||||
* @param {function} reject - reject function for returned promise
|
||||
* @param {string} id - id of request
|
||||
* @returns {Promise<{items: {items: Array<Object>}, id: string}}>} promise with items and optional next function
|
||||
*/
|
||||
function parseItemsResponse(promise, resolve, reject, id) {
|
||||
promise.then(function (res) {
|
||||
return res.json().then(function (json) {
|
||||
var links = parseLinkHeader(res.headers.get("Link"));
|
||||
var obj = {
|
||||
items: json,
|
||||
id: id
|
||||
};
|
||||
if (links.next) {
|
||||
obj.next = function () {
|
||||
return new Promise(function (rs, rj) {
|
||||
parseItemsResponse(getRequest(links.next), rs, rj, id);
|
||||
});
|
||||
}
|
||||
}
|
||||
resolve(obj);
|
||||
});
|
||||
}).catch(function (err) {
|
||||
reject(err);
|
||||
});
|
||||
}
|
||||
|
||||
var linkHeaderRegex = /<(.*?)>; rel="(.*?)"/g;
|
||||
function parseLinkHeader(headerValue) {
|
||||
var links = {};
|
||||
if (!headerValue) return links;
|
||||
headerValue = headerValue.trim();
|
||||
if (!headerValue) return links;
|
||||
|
||||
var match;
|
||||
while ((match = linkHeaderRegex.exec(headerValue)) !== null) {
|
||||
links[match[2]] = match[1];
|
||||
}
|
||||
|
||||
return links;
|
||||
resolve(result);
|
||||
})
|
||||
.catch(reject);
|
||||
};
|
||||
|
||||
/**
|
||||
* Universal items response parser
|
||||
* @param {Promise<AscSimpleResponse | FetchResponse>} promise
|
||||
* @param {function(any): void} resolve
|
||||
* @param {function(any): void} reject
|
||||
* @param {number} id
|
||||
*/
|
||||
ZoteroSdk.prototype._parseResponse = function (promise, resolve, reject, id) {
|
||||
if (this._isOnlineAvailable) {
|
||||
const fetchPromise = /** @type {Promise<FetchResponse>} */ (promise);
|
||||
this._parseItemsResponse(fetchPromise, resolve, reject, id);
|
||||
} else {
|
||||
const ascSimplePromise = /** @type {Promise<AscSimpleResponse>} */ (
|
||||
promise
|
||||
);
|
||||
this._parseDesktopItemsResponse(
|
||||
/** @type {Promise<AscSimpleResponse>} */ ascSimplePromise,
|
||||
resolve,
|
||||
reject,
|
||||
id
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get items from user library
|
||||
* @param {string} search
|
||||
* @param {string[]} itemsID
|
||||
* @param {"csljson"|"json"} format
|
||||
*/
|
||||
ZoteroSdk.prototype.getItems = function (search, itemsID, format) {
|
||||
var self = this;
|
||||
format = format || self.DEFAULT_FORMAT;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
var queryParams =
|
||||
/** @type {{format: string, q?: string, itemKey?: string}} */ ({
|
||||
format: format,
|
||||
});
|
||||
|
||||
if (search) {
|
||||
queryParams.q = search;
|
||||
} else if (itemsID) {
|
||||
queryParams.itemKey = itemsID.join(",");
|
||||
}
|
||||
|
||||
function setIsOnlineAvailable(isOnline) {
|
||||
isOnlineAvailable = isOnline;
|
||||
var path =
|
||||
self.API_PATHS.USERS +
|
||||
"/" +
|
||||
self._userId +
|
||||
"/" +
|
||||
self.API_PATHS.ITEMS;
|
||||
var request = self._buildGetRequest(path, queryParams);
|
||||
|
||||
self._parseResponse(request, resolve, reject, self._userId);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get items from group library
|
||||
* @param {string} search
|
||||
* @param {number} groupId
|
||||
* @param {string[]} itemsID
|
||||
* @param {"csljson"|"json"} format
|
||||
*
|
||||
*/
|
||||
ZoteroSdk.prototype.getGroupItems = function (
|
||||
search,
|
||||
groupId,
|
||||
itemsID,
|
||||
format
|
||||
) {
|
||||
var self = this;
|
||||
format = format || self.DEFAULT_FORMAT;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
var queryParams =
|
||||
/** @type {{format: string, q?: string, itemKey?: string}} */ ({
|
||||
format: format,
|
||||
});
|
||||
|
||||
if (search) {
|
||||
queryParams.q = search;
|
||||
} else if (itemsID) {
|
||||
queryParams.itemKey = itemsID.join(",");
|
||||
}
|
||||
|
||||
return {
|
||||
getItems: getItems,
|
||||
getGroupItems: getGroupItems,
|
||||
getUserGroups: getUserGroups,
|
||||
format: format,
|
||||
hasSettings: getSettings,
|
||||
clearSettings: clearSettings,
|
||||
setApiKey: setApiKey,
|
||||
getUserId: getUserId,
|
||||
getLocale: getLocale,
|
||||
setIsOnlineAvailable: setIsOnlineAvailable
|
||||
var path =
|
||||
self.API_PATHS.GROUPS + "/" + groupId + "/" + self.API_PATHS.ITEMS;
|
||||
var request = self._buildGetRequest(path, queryParams);
|
||||
|
||||
self._parseResponse(request, resolve, reject, groupId);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get user groups
|
||||
* @returns {Promise<Array<UserGroupInfo>>}
|
||||
*/
|
||||
ZoteroSdk.prototype.getUserGroups = function () {
|
||||
var self = this;
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (self._userGroups.length > 0) {
|
||||
resolve(self._userGroups);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var path = self.API_PATHS.USERS + "/" + self._userId + "/groups";
|
||||
|
||||
self._buildGetRequest(path)
|
||||
.then(function (
|
||||
/** @type {FetchResponse | AscSimpleResponse} */ response
|
||||
) {
|
||||
if (self._isOnlineAvailable) {
|
||||
var fetchResponse = /** @type {FetchResponse} */ (response);
|
||||
if (!fetchResponse.ok) {
|
||||
throw new Error(
|
||||
fetchResponse.status +
|
||||
" " +
|
||||
fetchResponse.statusText
|
||||
);
|
||||
}
|
||||
return fetchResponse.json();
|
||||
}
|
||||
var ascSimpleResponse = /** @type {AscSimpleResponse} */ (
|
||||
response
|
||||
);
|
||||
return JSON.parse(ascSimpleResponse.responseText);
|
||||
})
|
||||
.then(function (groups) {
|
||||
self._userGroups = groups.map(function (
|
||||
/** @type {ZoteroGroupInfo} */ group
|
||||
) {
|
||||
return {
|
||||
id: group.id,
|
||||
name: group.data.name,
|
||||
};
|
||||
});
|
||||
resolve(self._userGroups);
|
||||
})
|
||||
.catch(reject);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Format citations
|
||||
*/
|
||||
/*ZoteroSdk.prototype.format = function (ids, groupKey, style, locale) {
|
||||
var queryParams = {
|
||||
format: "bib",
|
||||
style: style,
|
||||
locale: locale,
|
||||
itemKey: ids.join(","),
|
||||
};
|
||||
|
||||
var path = groupKey
|
||||
? this.API_PATHS.GROUPS + "/" + groupKey + "/" + this.API_PATHS.ITEMS
|
||||
: this.API_PATHS.USERS +
|
||||
"/" +
|
||||
this._userId +
|
||||
"/" +
|
||||
this.API_PATHS.ITEMS;
|
||||
|
||||
return this._buildGetRequest(path, queryParams).then(function (response) {
|
||||
return response.text();
|
||||
});
|
||||
};*/
|
||||
|
||||
/**
|
||||
* Get locale data
|
||||
* @param {string} langTag
|
||||
*/
|
||||
ZoteroSdk.prototype.getLocale = function (langTag) {
|
||||
var url = this._getLocalesUrl() + "locales-" + langTag + ".xml";
|
||||
return fetch(url).then(function (response) {
|
||||
return response.text();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Set API key and validate it
|
||||
* @param {string} key
|
||||
*/
|
||||
ZoteroSdk.prototype.setApiKey = function (key) {
|
||||
var self = this;
|
||||
var path = this.API_PATHS.KEYS + "/" + key;
|
||||
|
||||
return this._buildGetRequest(path)
|
||||
.then(function (response) {
|
||||
var fetchResponse = /** @type {FetchResponse} */ (response);
|
||||
if (!fetchResponse.ok) {
|
||||
throw new Error(
|
||||
fetchResponse.status + " " + fetchResponse.statusText
|
||||
);
|
||||
}
|
||||
return fetchResponse.json();
|
||||
})
|
||||
.then(function (/** @type {any} */ keyData) {
|
||||
self._saveSettings(keyData.userID, key);
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Apply settings to current session
|
||||
* @param {number} userId
|
||||
* @param {string} apiKey
|
||||
*/
|
||||
ZoteroSdk.prototype._applySettings = function (userId, apiKey) {
|
||||
this._userId = userId;
|
||||
this._apiKey = apiKey;
|
||||
};
|
||||
|
||||
/**
|
||||
* Save settings to localStorage
|
||||
* @param {number} userId
|
||||
* @param {string} apiKey
|
||||
*/
|
||||
ZoteroSdk.prototype._saveSettings = function (userId, apiKey) {
|
||||
this._applySettings(userId, apiKey);
|
||||
localStorage.setItem(this.STORAGE_KEYS.USER_ID, String(userId));
|
||||
localStorage.setItem(this.STORAGE_KEYS.API_KEY, apiKey);
|
||||
};
|
||||
|
||||
/**
|
||||
* Load settings from localStorage
|
||||
*/
|
||||
ZoteroSdk.prototype.hasSettings = function () {
|
||||
var userId = localStorage.getItem(this.STORAGE_KEYS.USER_ID);
|
||||
var apiKey = localStorage.getItem(this.STORAGE_KEYS.API_KEY);
|
||||
|
||||
if (userId && apiKey) {
|
||||
this._applySettings(Number(userId), apiKey);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear stored settings
|
||||
*/
|
||||
ZoteroSdk.prototype.clearSettings = function () {
|
||||
localStorage.removeItem(this.STORAGE_KEYS.USER_ID);
|
||||
localStorage.removeItem(this.STORAGE_KEYS.API_KEY);
|
||||
this._userGroups = [];
|
||||
this._userId = 0;
|
||||
this._apiKey = null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get user ID
|
||||
*/
|
||||
ZoteroSdk.prototype.getUserId = function () {
|
||||
return this._userId;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set online availability
|
||||
* @param {boolean} isOnline
|
||||
*/
|
||||
ZoteroSdk.prototype.setIsOnlineAvailable = function (isOnline) {
|
||||
this._isOnlineAvailable = isOnline;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user