添加期刊引用分析
This commit is contained in:
236
src/utils/manuscriptReferenceHtml.js
Normal file
236
src/utils/manuscriptReferenceHtml.js
Normal file
@@ -0,0 +1,236 @@
|
||||
import { htmlToPlainText } from '@/utils/exportTableWord';
|
||||
|
||||
function escapeHtml(text) {
|
||||
return String(text || '')
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"');
|
||||
}
|
||||
|
||||
function hasItalicHtmlTag(html) {
|
||||
return /<i\b|<em\b/i.test(String(html || ''));
|
||||
}
|
||||
|
||||
function stripAvailableAtSuffix(html) {
|
||||
return String(html || '')
|
||||
.replace(/\s*Available at:\s*[\s\S]*$/i, '')
|
||||
.trim();
|
||||
}
|
||||
|
||||
function normalizeReferenceLink(url) {
|
||||
const raw = String(url || '').trim();
|
||||
if (!raw) {
|
||||
return '';
|
||||
}
|
||||
if (/^https?:\/\//i.test(raw)) {
|
||||
return raw;
|
||||
}
|
||||
if (/^10\./.test(raw)) {
|
||||
return 'https://doi.org/' + raw;
|
||||
}
|
||||
return raw;
|
||||
}
|
||||
|
||||
function getReferenceIsbnValue(ref) {
|
||||
if (!ref) {
|
||||
return '';
|
||||
}
|
||||
return String(ref.isbn || ref.doilink || '').trim();
|
||||
}
|
||||
|
||||
function appendHtmlField(parts, html, suffix, options) {
|
||||
const opts = options || {};
|
||||
const raw = String(html || '').trim();
|
||||
if (!raw) {
|
||||
return;
|
||||
}
|
||||
if (opts.italics && !hasItalicHtmlTag(raw)) {
|
||||
parts.push('<i>' + raw + '</i>');
|
||||
} else {
|
||||
parts.push(raw);
|
||||
}
|
||||
if (suffix) {
|
||||
parts.push(escapeHtml(suffix));
|
||||
}
|
||||
}
|
||||
|
||||
/** 将接口参考文献转为可编辑 HTML(支持后续粘贴带 <i> 的内容) */
|
||||
export function referenceRecordToEditableHtml(ref) {
|
||||
if (!ref) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const referType = String(ref.refer_type || 'journal').toLowerCase();
|
||||
|
||||
if (!ref.author && ref.refer_frag) {
|
||||
let html = stripAvailableAtSuffix(ref.refer_frag);
|
||||
const link = normalizeReferenceLink(ref.doilink || getReferenceIsbnValue(ref));
|
||||
if (link) {
|
||||
html += '<br>Available at:<br>' + escapeHtml(ref.doilink || ref.isbn || link);
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
const parts = [];
|
||||
|
||||
if (referType === 'book') {
|
||||
if (ref.author) {
|
||||
appendHtmlField(parts, ref.author, ' ');
|
||||
}
|
||||
if (ref.title) {
|
||||
appendHtmlField(parts, ref.title, '. ', { italics: true });
|
||||
}
|
||||
if (ref.dateno) {
|
||||
appendHtmlField(parts, ref.dateno, '. ');
|
||||
}
|
||||
const isbnValue = getReferenceIsbnValue(ref);
|
||||
if (isbnValue) {
|
||||
parts.push('Available at:<br>ISBN: ' + escapeHtml(isbnValue));
|
||||
}
|
||||
return parts.join('');
|
||||
}
|
||||
|
||||
if (referType === 'other') {
|
||||
let html = stripAvailableAtSuffix(ref.refer_frag);
|
||||
const link = normalizeReferenceLink(ref.doilink);
|
||||
if (link) {
|
||||
html += '<br>Available at:<br>' + escapeHtml(ref.doilink || link);
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
if (ref.author) {
|
||||
appendHtmlField(parts, ref.author, ' ');
|
||||
}
|
||||
if (ref.title) {
|
||||
appendHtmlField(parts, ref.title, '. ');
|
||||
}
|
||||
if (ref.joura) {
|
||||
appendHtmlField(parts, ref.joura, '. ', { italics: !hasItalicHtmlTag(ref.joura) });
|
||||
}
|
||||
if (ref.dateno) {
|
||||
appendHtmlField(parts, ref.dateno, '. ');
|
||||
}
|
||||
const doiLink = normalizeReferenceLink(ref.doilink);
|
||||
if (doiLink) {
|
||||
parts.push('Available at:<br>' + escapeHtml(ref.doilink || doiLink));
|
||||
}
|
||||
|
||||
return parts.join('');
|
||||
}
|
||||
|
||||
export function buildReferencesEditableHtml(references, labels) {
|
||||
const list = (references || []).filter(Boolean);
|
||||
const L = labels || {};
|
||||
const pageTitle = L.pageTitle || 'References Editor';
|
||||
const intro = L.intro || '';
|
||||
const saveTip = L.saveTip || '';
|
||||
const downloadBtn = L.downloadEdited || 'Download edited HTML';
|
||||
const refTitle = L.referencesTitle || 'References';
|
||||
|
||||
let listHtml = '';
|
||||
list.forEach(function (ref, index) {
|
||||
const referType = String(ref.refer_type || 'journal').toLowerCase();
|
||||
const content = referenceRecordToEditableHtml(ref);
|
||||
listHtml +=
|
||||
'<li class="ref-item" contenteditable="true" spellcheck="false"' +
|
||||
' data-ref-index="' + index + '"' +
|
||||
' data-ref-type="' + escapeHtml(referType) + '">' +
|
||||
content +
|
||||
'</li>';
|
||||
});
|
||||
|
||||
return (
|
||||
'<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8">' +
|
||||
'<meta name="viewport" content="width=device-width,initial-scale=1">' +
|
||||
'<title>' + escapeHtml(pageTitle) + '</title>' +
|
||||
'<style>' +
|
||||
'*{box-sizing:border-box}body{margin:0;font-family:Charis SIL,Georgia,"Times New Roman",serif;background:#f5f7fa;color:#303133;line-height:1.5}' +
|
||||
'.page{max-width:920px;margin:0 auto;padding:20px}' +
|
||||
'.header{background:#fff;border-radius:8px;padding:16px 20px;margin-bottom:12px;box-shadow:0 1px 4px rgba(0,0,0,.08)}' +
|
||||
'.header h1{margin:0 0 8px;font-size:20px;text-align:center;font-style:italic;font-weight:bold;color:#008080}' +
|
||||
'.intro{color:#606266;font-size:14px;margin-bottom:12px;white-space:pre-wrap}' +
|
||||
'.actions{display:flex;flex-wrap:wrap;gap:8px;margin-bottom:8px}' +
|
||||
'.btn{border:1px solid #409eff;background:#409eff;color:#fff;border-radius:4px;padding:8px 16px;font-size:13px;cursor:pointer}' +
|
||||
'.btn.plain{background:#ecf5ff;color:#409eff}' +
|
||||
'.ref-panel{background:#fff;border-radius:8px;padding:20px 24px;box-shadow:0 1px 4px rgba(0,0,0,.08);font-size:12px}' +
|
||||
'.ref-list{margin:0;padding-left:1.4em;list-style:decimal}' +
|
||||
'.ref-item{margin-bottom:10px;padding:4px 0;outline:none;min-height:1.4em}' +
|
||||
'.ref-item:focus{background:#fafcff;box-shadow:inset 0 0 0 1px #c6e2ff;border-radius:2px}' +
|
||||
'.ref-item i,.ref-item em{font-style:italic}' +
|
||||
'</style></head><body><div class="page">' +
|
||||
'<div class="header"><h1>' + escapeHtml(refTitle) + '</h1>' +
|
||||
'<div class="intro">' + escapeHtml(intro) + '</div>' +
|
||||
'<div class="actions">' +
|
||||
'<button type="button" class="btn" id="download-edited-btn">' + escapeHtml(downloadBtn) + '</button>' +
|
||||
'</div>' +
|
||||
'<div class="intro" style="font-size:12px;color:#909399">' + escapeHtml(saveTip) + '</div>' +
|
||||
'</div>' +
|
||||
'<div class="ref-panel"><ol class="ref-list" id="ref-list">' +
|
||||
listHtml +
|
||||
'</ol></div></div>' +
|
||||
'<script>(function(){' +
|
||||
'function serializePage(){var clone=document.documentElement.cloneNode(true);' +
|
||||
'var btn=clone.querySelector("#download-edited-btn");if(btn){btn.remove();}' +
|
||||
'return "<!DOCTYPE html>"+clone.outerHTML;}' +
|
||||
'document.getElementById("download-edited-btn").addEventListener("click",function(){' +
|
||||
'var html=serializePage();var blob=new Blob([html],{type:"text/html;charset=utf-8"});' +
|
||||
'var url=URL.createObjectURL(blob);var a=document.createElement("a");' +
|
||||
'a.href=url;a.download=' + JSON.stringify(L.downloadFileName || 'references-edited.html') + ';' +
|
||||
'document.body.appendChild(a);a.click();document.body.removeChild(a);URL.revokeObjectURL(url);});' +
|
||||
'})();<' +
|
||||
'/script></body></html>'
|
||||
);
|
||||
}
|
||||
|
||||
export function parseReferencesEditableHtml(htmlText) {
|
||||
const raw = String(htmlText || '');
|
||||
if (!raw.trim()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const doc = new DOMParser().parseFromString(raw, 'text/html');
|
||||
const nodes = doc.querySelectorAll('#ref-list .ref-item, #ref-list li[data-ref-index], ol.ref-list li');
|
||||
const items = [];
|
||||
|
||||
nodes.forEach(function (node) {
|
||||
const html = (node.innerHTML || '').trim();
|
||||
if (!html) {
|
||||
return;
|
||||
}
|
||||
items.push({
|
||||
refer_type: String(node.getAttribute('data-ref-type') || 'journal').toLowerCase(),
|
||||
html: html
|
||||
});
|
||||
});
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
export function downloadReferencesEditableHtml(references, labels, fileName) {
|
||||
const html = buildReferencesEditableHtml(references, labels);
|
||||
const blob = new Blob([html], { type: 'text/html;charset=utf-8' });
|
||||
const url = URL.createObjectURL(blob);
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
link.download = fileName || 'references-editor.html';
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
export function buildReferencesHtmlLabels(translate) {
|
||||
const t = translate || function (key) {
|
||||
return key;
|
||||
};
|
||||
return {
|
||||
pageTitle: t('commonTable.refHtmlPageTitle'),
|
||||
referencesTitle: t('commonTable.refHtmlReferencesTitle'),
|
||||
intro: t('commonTable.refHtmlIntro'),
|
||||
saveTip: t('commonTable.refHtmlSaveTip'),
|
||||
downloadEdited: t('commonTable.refHtmlDownloadEdited'),
|
||||
downloadFileName: t('commonTable.refHtmlDownloadFileName')
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user