citation doc service

This commit is contained in:
Artur
2025-10-13 19:26:13 +03:00
parent 4d62c8eea2
commit d071a2672f
7 changed files with 211 additions and 75 deletions

View File

@ -46,6 +46,8 @@
<script src="scripts/csl/styles/styles-manager.js"></script>
<script src="scripts/csl/styles/style-parser.js"></script>
<script src="scripts/csl/styles/storage.js"></script>
<script src="scripts/citation-doc-service.js"></script>
</head>
<body id="body" spellcheck="false" class="noselect">

View File

@ -0,0 +1,155 @@
// @ts-check
/**
* @typedef {Object} CustomField
* @property {string} Value
* @property {string} Content
* @property {string} [FieldId]
*/
/**
* @param {string} citPrefix
* @param {string} citSuffix
* @param {string} bibPrefix
* @param {string} bibSuffix
* @param {StyleFormat} styleFormat
*/
function CitationDocService(
citPrefix,
citSuffix,
bibPrefix,
bibSuffix,
styleFormat
) {
this._citPrefixOld = "ZOTERO_CITATION";
this._bibPrefixOld = "ZOTERO_BIBLIOGRAPHY";
this._citPrefix = citPrefix;
this._citSuffix = citSuffix;
this._bibPrefix = bibPrefix;
this._bibSuffix = bibSuffix;
this._styleFormat = styleFormat;
/** @type {number} */
this._repeatTimeout;
/**
* @type {{ updateItems: (arg0: string[]) => void; makeCitationCluster: (arg0: SuppressAuthor[]) => string; makeBibliography: () => any[][]; } | null}
*/
this._formatter = null;
}
/**
* @param {string} text
* @param {string} value
*/
CitationDocService.prototype.addBibliography = function (text, value) {
/** @type {CustomField} */
const field = {
Value: this._bibPrefix + value + this._bibSuffix,
Content: text,
};
return new Promise(function (resolve) {
window.Asc.plugin.executeMethod("AddAddinField", [field], resolve);
});
};
/**
* @param {string} text
* @param {string} value
* @returns
*/
CitationDocService.prototype.addCitation = function (text, value) {
/** @type {CustomField} */
const field = {
Value: this._citPrefix + " " + this._citSuffix + value,
Content: text,
};
if (["note", "note-ibid"].indexOf(this._styleFormat) !== -1) {
window.Asc.plugin.callCommand(function () {
const oDocument = Api.GetDocument();
oDocument.AddFootnote();
});
}
return new Promise(function (resolve, reject) {
window.Asc.plugin.executeMethod("AddAddinField", [field], resolve);
});
};
/**
* @returns {Promise<Array<CustomField>>}
*/
CitationDocService.prototype.getAllAddinFields = function () {
const self = this;
return new Promise(function (resolve, reject) {
window.Asc.plugin.executeMethod("GetAllAddinFields", null, resolve);
});
};
/**
* @returns {Promise<Array<CustomField>>}
*/
CitationDocService.prototype.getAddinZoteroFields = function () {
const self = this;
return new Promise(function (resolve, reject) {
self.getAllAddinFields().then(function (arrFields) {
try {
if (arrFields.length) {
arrFields = arrFields.filter(function (field) {
return (
field.Value.indexOf(self._citPrefix) !== -1 ||
field.Value.indexOf(self._bibPrefix) !== -1 ||
field.Value.indexOf(self._citPrefixOld) !== -1 ||
field.Value.indexOf(self._bibPrefixOld) !== -1
);
});
}
} catch (e) {
reject(e);
}
resolve(arrFields);
});
});
};
/**
* @returns {Promise<boolean>}
*/
CitationDocService.prototype.saveAsText = function () {
// TODO потом добавить ещё форматы, пока только как текст
return this.getAddinZoteroFields().then(function (arrFields) {
let count = arrFields.length;
if (!count) {
window.Asc.plugin.executeCommand("close", "");
return false;
}
return new Promise(function (resolve) {
arrFields.forEach(function (field) {
window.Asc.plugin.executeMethod(
"RemoveFieldWrapper",
[field.FieldId],
function () {
count--;
if (!count) {
resolve(true);
window.Asc.plugin.executeCommand("close", "");
}
}
);
});
});
});
};
/**
* @param {StyleFormat} styleFormat
*/
CitationDocService.prototype.setStyleFormat = function (styleFormat) {
this._styleFormat = styleFormat;
};
CitationDocService.prototype.updateAddinFields = function (fields) {
return new Promise(function (resolve, reject) {
window.Asc.plugin.executeMethod("UpdateAddinFields", [fields], resolve);
});
};

View File

@ -66,6 +66,7 @@
var sdk = null;
var cslStylesManager = null;
var citationDocService = null;
var lastSearch = {
text: "",
@ -121,7 +122,7 @@
window.Asc.plugin.init = function () {
showLoader(true);
setTimeout(function () { searchField.focus(); },100);
updateCslItems(true, false, false, false);
sdk = window.Asc.plugin.zotero.api({});
initSdkApis().then(function (availableApis) {
@ -130,6 +131,15 @@
if (availableApis.online || availableApis.desktop) {
loadStyles();
}
citationDocService = new CitationDocService(
citPrefixNew,
citSuffixNew,
bibPrefixNew,
bibSuffixNew,
cslStylesManager.getLastUsedFormat()
);
updateCslItems(true, false, false, false);
});
window.Asc.plugin.onTranslate = applyTranslations;
@ -143,14 +153,6 @@
elements.styleSelectList.onopen = function () {
elements.styleSelectList.style.width = (elements.styleWrapper.clientWidth - 2) + "px";
}
Asc.scope.text = "note";
/*window.Asc.plugin.callCommand(function () {
var oDocument = Api.GetDocument();
oDocument.AddFootnote();
let footnotesFirstParagraphs = oDocument.GetFootnotesFirstParagraphs();
footnotesFirstParagraphs[0].AddText(Asc.scope.text);
}, true);*/
};
window.Asc.plugin.onThemeChanged = function(theme)
@ -384,7 +386,7 @@
elements.saveAsTextBtn.onclick = function() {
showLoader(true);
saveAs();
citationDocService.saveAsText();
}
elements.styleSelect.oninput = function (e, filter) {
var input = elements.styleSelect;
@ -405,7 +407,9 @@
showLoader(true);
getStyle(val)
.then(function(style) {
bNumFormat = (style.indexOf('citation-format="numeric"') !== -1);
let styleFormat = cslStylesManager.getLastUsedFormat();
citationDocService.setStyleFormat(styleFormat);
bNumFormat = styleFormat == 'numeric';
if (isClick)
updateCslItems(true, true, false, false);
})
@ -965,7 +969,7 @@
showError(getMessage("Language is not selected"));
return;
}
window.Asc.plugin.executeMethod("GetAllAddinFields", null, function(arrFields) {
citationDocService.getAllAddinFields().then(function(arrFields) {
if (!arrFields.length) {
showLoader(false);
return;
@ -1012,28 +1016,25 @@
updatedFields.push(field);
} else if (field.Value.indexOf(bibPrefix) !== -1 || field.Value.indexOf(bibPrefixNew) !== -1) {
bibField = field;
bibField["Content"] = bibliography;
if (typeof citationObject === "object" && Object.keys(citationObject).length > 0) {
bibFieldValue = JSON.stringify(citationObject);
}
}
});
if (bibField) {
bibField["Content"] = bibliography;
updatedFields.push(bibField);
} else if (bPastBib) {
bibField = {
"Value" : bibPrefixNew + bibFieldValue + bibSuffixNew,
"Content" : bibliography
};
window.Asc.plugin.executeMethod("AddAddinField", [bibField], function() {
if (!updatedFields.length) {
showLoader(false);
}
});
citationDocService.addBibliography(bibliography, bibFieldValue)
.then(function() {
if (!updatedFields.length) {
showLoader(false);
}
});
}
if (updatedFields.length) {
window.Asc.plugin.executeMethod("UpdateAddinFields", [updatedFields], function() {
citationDocService.updateAddinFields(updatedFields).then(function() {
showLoader(false);
});
}
@ -1083,7 +1084,8 @@
// Refresh (1,1,0,0)
function updateCslItems(bUpdadeFormatter, bUpadteAll, bPastBib, bPastLink) {
CSLCitationStorage.clear();
window.Asc.plugin.executeMethod("GetAllAddinFields", null, function(arrFields) {
return citationDocService.getAllAddinFields().then(function(arrFields) {
if (arrFields.length) {
var numOfItems = 0;
var bibField = null;
@ -1118,18 +1120,18 @@
// нет смысла ещё раз искать поле библиографии
bUpdadeFormatter = false;
bibField["Content"] = getMessage(bibPlaceholder);
window.Asc.plugin.executeMethod("UpdateAddinFields", [[bibField]], function() {
showLoader(false);
});
citationDocService.updateAddinFields([bibField]).then(function() {
showLoader(false);
});
}
} else if (bUpdadeFormatter && bPastBib) {
bibField = {
"Value" : bibPrefixNew + bibFieldValue + bibSuffixNew,
"Content" : getMessage(bibPlaceholder)
};
window.Asc.plugin.executeMethod("AddAddinField", [bibField], function() {
showLoader(false);
});
citationDocService.addBibliography(
getMessage(bibPlaceholder),
bibFieldValue
).then(function() {
showLoader(false);
});
}
if (bUpdadeFormatter)
updateFormatter(bUpadteAll, bPastBib, bPastLink, false);
@ -1176,18 +1178,10 @@
// TODO может ещё очистить поиск (подумать над этим)
elements.tempDiv.innerHTML = formatter.makeCitationCluster(keysL[0]);
var field = {
"Value" : citPrefixNew + ' ' + citSuffixNew + JSON.stringify(obj.toJSON()),
"Content" : elements.tempDiv.innerText
};
if (['note', 'note-ibid'].indexOf(cslStylesManager.getLastUsedFormat()) !== -1) {
window.Asc.plugin.callCommand(function () {
var oDocument = Api.GetDocument();
oDocument.AddFootnote();
});
}
window.Asc.plugin.executeMethod("AddAddinField", [field], function() {
citationDocService.addCitation(
elements.tempDiv.innerHTML,
JSON.stringify(obj.toJSON())
).then(function() {
showLoader(false);
// TODO есть проблема, что в плагине мы индексы обновили, а вот в документе нет (по идее надо обновить и индексы в документе перед вставкой)
// но тогда у нас уедет селект и новое поле вставится не там, поэтому пока обновлять приходится в конце
@ -1221,31 +1215,6 @@
};
function saveAs() {
// TODO потом добавить ещё форматы, пока только как текст
window.Asc.plugin.executeMethod("GetAllAddinFields", null, function(arrFields) {
let count = 0;
arrFields.forEach(function(field) {
if (
( field.Value.indexOf(bibPrefix) !== -1 ) ||
( field.Value.indexOf(citPrefix) !== -1 ) ||
( field.Value.indexOf(bibPrefixNew) !== -1 ) ||
( field.Value.indexOf(citPrefixNew) !== -1 )
) {
count++;
window.Asc.plugin.executeMethod("RemoveFieldWrapper", [field.FieldId], function() {
count--;
if (!count)
window.Asc.plugin.executeCommand("close", "");
});
}
});
if (!arrFields.length)
window.Asc.plugin.executeCommand("close", "");
});
};
function synchronizeData() {
// form an array for request (one array for user and other for groups)
// todo now we should make full update (because when we make refresh, we check fields into the document). Fix it in new version (when we change refreshing and updating processes)

View File

@ -1,3 +1,9 @@
/**
* @typedef {Object} SuppressAuthor
* @property {string} id
* @property {boolean} "suppress-author"
*/
/**
* @param {string} citationID
* @param {number} [itemsStartIndex]
@ -16,6 +22,10 @@ function CSLCitation(citationID, itemsStartIndex) {
"https://raw.githubusercontent.com/citation-style-language/schema/master/schemas/input/csl-citation.json";
}
/**
*
* @returns {Array<SuppressAuthor>}
*/
CSLCitation.prototype.getSuppressAuthors = function () {
return this._citationItems.map(function (item) {
return {

View File

@ -1,7 +1,10 @@
var CSLCitationStorage = {
/** @type {Array<CSLCitation>} */
_items: [],
/** @type {Array<string>} */
_ids: [],
size: 0,
/** @returns {CSLCitation} */
get: function (id) {
var id = this._ids.indexOf(id);
if (id >= 0) return this._items[id];

View File

@ -1,8 +1,6 @@
// @ts-check
function CslStylesStorage() {
this._dbName = "ZoteroStylesDB";
this._storeName = "cslFiles";
this._customStyleNamesKey = "zoteroCustomStyleNames";
this._customStylesKey = "zoteroCustomStyles";
}

View File

@ -107,8 +107,7 @@ CslStylesManager.prototype.getStyle = function (styleName) {
}
const customStyleNames = self._customStylesStorage.getStyleNames();
if (customStyleNames.indexOf(styleName) !== -1) {
return self._customStylesStorage
.getStyle(styleName);
return self._customStylesStorage.getStyle(styleName);
}
let url = self._STYLES_LOCAL + styleName + ".csl";
if (self._isOnlineAvailable) {