273 lines
12 KiB
JavaScript
273 lines
12 KiB
JavaScript
/* ============================================================
|
||
* API 接口文档交互脚本
|
||
* 从 ApiDocGenerator.appendJs() 提取,版块化便于独立维护
|
||
*
|
||
* AI 定位指引:
|
||
* - 搜索过滤 → 搜索 "filterDocs"
|
||
* - 展开/折叠 → 搜索 "expandAll" / "collapseAll"
|
||
* - 复制功能 → 搜索 "copyToClip" / "copyImage" / "copyRtfFromEl"
|
||
* - DTO/字段展开 → 搜索 "toggleDto" / "toggleChildren"
|
||
* ============================================================ */
|
||
|
||
/* ===== 导航分组折叠 ===== */
|
||
document.querySelectorAll('.nav-group-title').forEach(function(el) {
|
||
el.classList.add('open');
|
||
});
|
||
function toggleGroup(el) {
|
||
el.classList.toggle('open');
|
||
document.querySelectorAll('.nav-group-title.open + .nav-group-items').forEach(function(i) {
|
||
i.style.maxHeight = i.scrollHeight + 'px';
|
||
});
|
||
}
|
||
document.querySelectorAll('.nav-group-title.open + .nav-group-items').forEach(function(i) {
|
||
i.style.maxHeight = i.scrollHeight + 'px';
|
||
});
|
||
|
||
/* ===== 方法卡片折叠 ===== */
|
||
function toggleMethod(el) {
|
||
el.classList.toggle('collapsed');
|
||
}
|
||
function toggleDto(el) {
|
||
el.classList.toggle('collapsed');
|
||
}
|
||
|
||
/* ===== 字段子行折叠 ===== */
|
||
function toggleChildren(el) {
|
||
el.classList.toggle('open');
|
||
var row = el.closest('tr');
|
||
if (!row) return;
|
||
var d = parseInt(row.dataset.depth) || 0;
|
||
var hide = el.classList.contains('open');
|
||
var next = row.nextElementSibling;
|
||
while (next && next.classList.contains('field-row')) {
|
||
var nd = parseInt(next.dataset.depth) || 0;
|
||
if (nd <= d) break;
|
||
next.style.display = hide ? '' : 'none';
|
||
next = next.nextElementSibling;
|
||
}
|
||
}
|
||
|
||
/* ===== 展开/折叠全部 ===== */
|
||
function expandAll() {
|
||
document.querySelectorAll('.method-header').forEach(function(h) { h.classList.remove('collapsed'); });
|
||
document.querySelectorAll('.dto-block-title').forEach(function(t) { t.classList.remove('collapsed'); });
|
||
}
|
||
function collapseAll() {
|
||
document.querySelectorAll('.method-header').forEach(function(h) { h.classList.add('collapsed'); });
|
||
document.querySelectorAll('.dto-block-title').forEach(function(t) { t.classList.add('collapsed'); });
|
||
}
|
||
|
||
/* ===== 导航高亮(IntersectionObserver) ===== */
|
||
var observer = new IntersectionObserver(function(entries) {
|
||
entries.forEach(function(e) {
|
||
if (e.isIntersecting) {
|
||
document.querySelectorAll('.nav-item.active').forEach(function(a) { a.classList.remove('active'); });
|
||
var n = document.querySelector('.nav-item[href="#' + e.target.id + '"]');
|
||
if (n) n.classList.add('active');
|
||
}
|
||
});
|
||
});
|
||
document.querySelectorAll('.api-card[id]').forEach(function(c) { observer.observe(c); });
|
||
|
||
/* ===== 侧栏导航点击展开对应方法 ===== */
|
||
document.querySelectorAll('.nav-method').forEach(function(link) {
|
||
link.addEventListener('click', function(e) {
|
||
var targetId = this.getAttribute('href');
|
||
if (!targetId || !targetId.startsWith('#')) return;
|
||
var el = document.getElementById(targetId.substring(1));
|
||
if (!el) return;
|
||
var methodCard = el.closest('.method-card');
|
||
if (!methodCard) return;
|
||
var header = methodCard.querySelector('.method-header');
|
||
if (header) header.classList.remove('collapsed');
|
||
var body = methodCard.querySelector('.method-body');
|
||
if (body) body.style.display = '';
|
||
var apiCard = methodCard.closest('.api-card');
|
||
if (apiCard) { apiCard.classList.remove('collapsed'); var apiBody = apiCard.querySelector('.api-body'); if (apiBody) apiBody.style.display = ''; }
|
||
});
|
||
});
|
||
|
||
/* ===== 复制到剪贴板(纯文本) ===== */
|
||
function copyToClip(text, btn) {
|
||
if (navigator.clipboard) {
|
||
navigator.clipboard.writeText(text).then(function() {
|
||
markCopied(btn, '✔ 已复制');
|
||
}).catch(function() {
|
||
fallbackCopy(text, btn);
|
||
});
|
||
} else {
|
||
fallbackCopy(text, btn);
|
||
}
|
||
}
|
||
function fallbackCopy(text, btn) {
|
||
var ta = document.createElement('textarea');
|
||
ta.value = text;
|
||
ta.style.position = 'fixed';
|
||
ta.style.left = '-999px';
|
||
document.body.appendChild(ta);
|
||
ta.select();
|
||
try { document.execCommand('copy'); markCopied(btn, '✔ 已复制'); } catch (e) { markCopied(btn, '⚠ 失败'); }
|
||
document.body.removeChild(ta);
|
||
}
|
||
function markCopied(btn, msg) {
|
||
var orig = btn.textContent;
|
||
btn.textContent = msg;
|
||
btn.classList.add('copied');
|
||
setTimeout(function() { btn.textContent = orig; btn.classList.remove('copied'); }, 1500);
|
||
}
|
||
|
||
/* ===== 复制代码签名 ===== */
|
||
function copyCode(btn) {
|
||
var pre = btn.closest('.method-signature');
|
||
if (!pre) { var card = btn.closest('.method-card'); if (card) pre = card.querySelector('.method-signature'); }
|
||
var codeEl = pre ? pre.querySelector('code') : null;
|
||
var text = codeEl ? codeEl.textContent : (pre ? pre.textContent.replace('复制', '') : '');
|
||
copyToClip(text.trim(), btn);
|
||
}
|
||
|
||
/* ===== 复制为图片(需要 html2canvas) ===== */
|
||
function copyImage(el, btn) {
|
||
if (!el || typeof html2canvas === 'undefined') { markCopied(btn, '⚠ 不可用'); return; }
|
||
var clone = el.cloneNode(true);
|
||
clone.querySelectorAll('.method-header').forEach(function(h) { h.classList.remove('collapsed'); });
|
||
clone.querySelectorAll('.method-body').forEach(function(b) { b.style.display = ''; });
|
||
clone.querySelectorAll('.dto-block-title').forEach(function(t) { t.classList.remove('collapsed'); });
|
||
clone.style.position = 'fixed';
|
||
clone.style.left = '-9999px';
|
||
clone.style.top = '0';
|
||
clone.style.zIndex = '-1';
|
||
document.body.appendChild(clone);
|
||
html2canvas(clone, { scale: 2, useCORS: true, allowTaint: true, backgroundColor: '#ffffff', windowWidth: clone.scrollWidth, windowHeight: clone.scrollHeight }).then(function(canvas) {
|
||
canvas.toBlob(function(blob) {
|
||
if (blob && navigator.clipboard && navigator.clipboard.write) {
|
||
var item = new ClipboardItem({ 'image/png': blob });
|
||
navigator.clipboard.write([item]).then(function() {
|
||
markCopied(btn, '✔ 图片已复制');
|
||
}).catch(function() {
|
||
markCopied(btn, '⚠ 请粘贴');
|
||
});
|
||
} else { markCopied(btn, '⚠ 不支持'); }
|
||
}, 'image/png');
|
||
}).catch(function() {
|
||
markCopied(btn, '⚠ html2canvas 失败');
|
||
}).finally(function() {
|
||
if (clone.parentNode) document.body.removeChild(clone);
|
||
});
|
||
}
|
||
|
||
/* ===== 复制为 Word 富文本 (RTF) ===== */
|
||
function copyRtfFromEl(el, btn) {
|
||
if (!el) { markCopied(btn, '⚠ 无内容'); return; }
|
||
var wrap = document.createElement('div');
|
||
wrap.innerHTML = el.innerHTML;
|
||
// 清除按钮
|
||
wrap.querySelectorAll('button').forEach(function(b) { b.remove(); });
|
||
wrap.querySelectorAll('.copy-btn,.api-copy-btn,.method-copy-btn').forEach(function(b) { b.remove(); });
|
||
wrap.querySelectorAll('.field-expand-toggle').forEach(function(b) { b.remove(); });
|
||
// 展开所有折叠区域
|
||
wrap.querySelectorAll('.method-header').forEach(function(h) { h.classList.remove('collapsed'); });
|
||
wrap.querySelectorAll('.method-body').forEach(function(b) { b.style.display = ''; });
|
||
wrap.querySelectorAll('.dto-block-title').forEach(function(t) { t.classList.remove('collapsed'); });
|
||
// 清除 script/style
|
||
wrap.querySelectorAll('script,style').forEach(function(s) { s.remove(); });
|
||
var html = '<html><head><meta charset="utf-8"><style>' + getDocStyles() + '</style></head><body>' + wrap.innerHTML + '</body></html>';
|
||
if (navigator.clipboard && navigator.clipboard.write) {
|
||
var blob = new Blob([html], { type: 'text/html' });
|
||
navigator.clipboard.write([new ClipboardItem({ 'text/html': blob, 'text/plain': new Blob([wrap.textContent || ''], { type: 'text/plain' }) })])
|
||
.then(function() { markCopied(btn, '✔ 富文本已复制'); })
|
||
.catch(function() { legacyRich(html, btn); markCopied(btn, '⚠ 已复制富文本'); });
|
||
} else {
|
||
legacyRich(html, btn);
|
||
markCopied(btn, '⚠ 已复制富文本');
|
||
}
|
||
}
|
||
|
||
/* ===== 获取文档样式 ===== */
|
||
function getDocStyles() {
|
||
var css = '';
|
||
document.querySelectorAll('style').forEach(function(s) { css += s.textContent; });
|
||
return css;
|
||
}
|
||
|
||
/* ===== 旧版富文本复制兼容 ===== */
|
||
function legacyRich(html, btn) {
|
||
var listener = function(e) {
|
||
e.clipboardData.setData('text/html', html);
|
||
e.clipboardData.setData('text/plain', '');
|
||
e.preventDefault();
|
||
document.removeEventListener('copy', listener);
|
||
};
|
||
document.addEventListener('copy', listener);
|
||
document.execCommand('copy');
|
||
document.removeEventListener('copy', listener);
|
||
}
|
||
|
||
/* ===== 搜索过滤 ===== */
|
||
function filterDocs() {
|
||
var kw = (document.getElementById('searchInput') || {}).value;
|
||
if (!kw || !kw.trim()) { resetSearch(); return; }
|
||
kw = kw.trim().toLowerCase();
|
||
var visible = 0;
|
||
// 导航过滤
|
||
document.querySelectorAll('.nav-group').forEach(function(g) {
|
||
var hasVisible = false;
|
||
g.querySelectorAll('.nav-item').forEach(function(item) {
|
||
var txt = (item.textContent || '').toLowerCase();
|
||
if (txt.indexOf(kw) >= 0) { item.classList.remove('search-hidden'); hasVisible = true; visible++; }
|
||
else { item.classList.add('search-hidden'); }
|
||
});
|
||
if (hasVisible) {
|
||
g.classList.remove('search-hidden');
|
||
var t = g.querySelector('.nav-group-title');
|
||
if (t) t.classList.add('open');
|
||
var items = g.querySelector('.nav-group-items');
|
||
if (items) items.style.maxHeight = items.scrollHeight + 'px';
|
||
} else { g.classList.add('search-hidden'); }
|
||
});
|
||
// 内容过滤
|
||
document.querySelectorAll('.api-card').forEach(function(card) {
|
||
var txt = (card.textContent || '').toLowerCase();
|
||
var match = txt.indexOf(kw) >= 0;
|
||
if (!match) {
|
||
card.querySelectorAll('.method-card').forEach(function(mc) {
|
||
var mt = (mc.textContent || '').toLowerCase();
|
||
if (mt.indexOf(kw) >= 0) { match = true; mc.classList.remove('search-hidden'); mc.querySelector('.method-header').classList.remove('collapsed'); mc.querySelector('.method-body').style.display = ''; }
|
||
else { mc.classList.add('search-hidden'); }
|
||
});
|
||
}
|
||
if (match) { card.classList.remove('search-hidden'); var body = card.querySelector('.api-body'); if (body) { body.style.display = ''; card.classList.remove('collapsed'); } }
|
||
else { card.classList.add('search-hidden'); }
|
||
});
|
||
var searchCount = document.getElementById('searchCount');
|
||
if (searchCount) searchCount.textContent = visible > 0 ? '匹配 ' + visible + ' 项' : '无匹配';
|
||
}
|
||
|
||
function resetSearch() {
|
||
document.querySelectorAll('.search-hidden').forEach(function(el) { el.classList.remove('search-hidden'); });
|
||
document.querySelectorAll('.search-highlight').forEach(function(el) { var p = el.parentNode; if (p) p.replaceChild(document.createTextNode(el.textContent), el); });
|
||
var searchCount = document.getElementById('searchCount');
|
||
if (searchCount) searchCount.textContent = '';
|
||
}
|
||
|
||
/* ===== ESC 清空搜索 ===== */
|
||
(function() {
|
||
var si = document.getElementById('searchInput');
|
||
if (si) { si.addEventListener('keydown', function(e) { if (e.key === 'Escape') { this.value = ''; resetSearch(); this.blur(); } }); }
|
||
})();
|
||
|
||
/* ===== 手动选择区域复制富文本兼容 ===== */
|
||
document.querySelectorAll('.api-card .api-body, .method-body').forEach(function(el) {
|
||
el.addEventListener('copy', function(e) {
|
||
var sel = window.getSelection();
|
||
if (!sel.rangeCount) return;
|
||
var range = sel.getRangeAt(0);
|
||
var wrapper = document.createElement('div');
|
||
wrapper.appendChild(range.cloneContents());
|
||
wrapper.querySelectorAll('button,.copy-btn,.api-copy-btn,.method-copy-btn').forEach(function(b) { b.remove(); });
|
||
var html = wrapper.innerHTML;
|
||
var css = getDocStyles();
|
||
e.clipboardData.setData('text/html', '<html><head><meta charset="utf-8"><style>' + css + '</style></head><body>' + html + '</body></html>');
|
||
e.preventDefault();
|
||
});
|
||
});
|