-
Notifications
You must be signed in to change notification settings - Fork 3
Open
Description
Hello, thank you for developing this excellent add-on. While using it, I noticed that images in cards cannot be conveniently viewed in full size. I temporarily integrated ViewerJS by modifying the template, enabling click-to-zoom functionality for images, and the experience has been great.
<!-- 先加载必要的CSS(ViewerJS核心样式) -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.7/viewer.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/css/font-awesome.min.css">
<script>
(function() {
// 全局变量只保留必要的
let viewer = null;
let isViewerActive = false;
// 增强的图片查找函数 - 覆盖正面所有图片
function findAllImages() {
// 按优先级查找图片,确保覆盖正面所有图片
const selectors = [
'img', // 匹配所有图片(最高优先级)
'#front-card-basic img',
'.card img',
'.content img',
'body img:not([data-viewer-inited="true"])'
];
// 去重收集所有图片
const imagesSet = new Set();
selectors.forEach(selector => {
const elements = document.querySelectorAll(selector);
elements.forEach(el => imagesSet.add(el));
});
const imagesArray = Array.from(imagesSet);
console.log('Found total images (front template):', imagesArray.length);
// 打印每个图片的信息,方便调试
imagesArray.forEach((img, index) => {
console.log(`Image ${index} (front):`, {
src: img.src,
id: img.id,
className: img.className,
parent: img.parentElement.tagName,
container: img.closest('[id*="-card-"]')?.id || 'unknown'
});
});
return imagesArray;
}
// 等待页面完全加载(包括图片)
function waitForCompleteLoad() {
return new Promise(resolve => {
// 如果页面已加载完成
if (document.readyState === 'complete') {
resolve();
} else {
// 等待所有资源加载完成
const onLoad = () => {
document.removeEventListener('DOMContentLoaded', onLoad);
window.removeEventListener('load', onLoad);
resolve();
};
document.addEventListener('DOMContentLoaded', onLoad);
window.addEventListener('load', onLoad);
// 超时保护:1秒后强制解析
setTimeout(resolve, 1000);
}
});
}
// 加载ViewerJS
function loadViewerJS() {
return new Promise((resolve, reject) => {
if (window.Viewer) {
resolve(window.Viewer);
return;
}
const script = document.createElement('script');
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.7/viewer.min.js';
script.onload = () => resolve(window.Viewer);
script.onerror = (e) => reject(e);
document.head.appendChild(script);
});
}
// 初始化图片查看器
async function initImageViewer() {
try {
// 等待页面完全加载(包括图片)
await waitForCompleteLoad();
console.log('Page fully loaded (front template), starting viewer init');
// 加载ViewerJS
await loadViewerJS();
console.log('ViewerJS loaded successfully (front template)');
// 查找所有图片(增强版)
const images = findAllImages();
if (images.length === 0) {
console.warn('No images found in front template');
// 尝试延迟再查找一次
setTimeout(() => {
const retryImages = findAllImages();
if (retryImages.length > 0) {
setupImageClickHandlers(retryImages);
}
}, 500);
return;
}
// 为图片绑定点击事件
setupImageClickHandlers(images);
} catch (error) {
console.error('Failed to initialize viewer (front template):', error);
}
}
// 为图片绑定点击事件
function setupImageClickHandlers(images) {
images.forEach(img => {
// 避免重复处理
if (img.dataset.viewerInited) return;
img.dataset.viewerInited = 'true';
// 设置基础样式
img.style.cursor = 'zoom-in';
img.style.maxWidth = '100%';
img.style.height = 'auto';
console.log('Binding click handler to image (front):', img.src);
// 点击图片打开查看器
img.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
console.log('Image clicked (front), opening viewer:', this.src);
openViewer(this);
});
});
console.log('Viewer initialized for', images.length, 'images (front template)');
}
// 打开查看器(修复了点击图片显示不正确的问题)
function openViewer(targetImg) {
// 如果已有查看器,先销毁
if (viewer) {
try {
viewer.destroy();
} catch (e) {
console.warn('Error destroying old viewer (front):', e);
}
}
// 收集所有已初始化的图片
const imageElements = Array.from(document.querySelectorAll('img[data-viewer-inited="true"]'));
// 找到当前图片的索引
const startIndex = imageElements.indexOf(targetImg);
console.log('Opening viewer for image index (front):', startIndex, 'out of', imageElements.length);
if (startIndex === -1) {
console.error('Target image not found in imageElements');
return;
}
// 创建一个临时的图片容器,仅用于ViewerJS初始化
const tempContainer = document.createElement('div');
tempContainer.style.display = 'none';
tempContainer.id = 'viewer-temp-container';
// 为临时容器添加所有图片
imageElements.forEach((img, index) => {
const imgClone = img.cloneNode(true);
imgClone.style.display = 'block';
imgClone.style.width = '100%';
imgClone.style.height = 'auto';
tempContainer.appendChild(imgClone);
});
document.body.appendChild(tempContainer);
// 创建Viewer实例,使用临时容器中的图片
viewer = new Viewer(tempContainer, {
button: true,
toolbar: {
zoomIn: 1,
zoomOut: 1,
oneToOne: 1,
reset: 1,
prev: 1,
play: 0,
next: 1,
rotateLeft: 1,
rotateRight: 1,
flipHorizontal: 1,
flipVertical: 1,
},
navbar: true,
title: true,
keyboard: true,
movable: true,
zoomable: true,
rotatable: true,
scalable: true,
fullscreen: true,
loop: true,
inline: false,
shown: function() {
console.log('Viewer opened successfully (front template)');
isViewerActive = true;
// 立即跳转到点击的图片
if (startIndex >= 0) {
viewer.view(startIndex);
}
// 确保关闭按钮可见
setTimeout(() => {
const closeBtn = document.querySelector('.viewer-button.viewer-close');
if (closeBtn) {
closeBtn.style.display = 'block';
closeBtn.style.opacity = '1';
closeBtn.style.zIndex = '999999';
closeBtn.style.pointerEvents = 'auto';
}
}, 100);
},
hidden: function() {
console.log('Viewer closed (front template)');
isViewerActive = false;
// 清理临时容器和实例
setTimeout(() => {
try {
if (tempContainer && tempContainer.parentNode) {
tempContainer.parentNode.removeChild(tempContainer);
}
viewer.destroy();
viewer = null;
} catch (e) {
console.warn('Error cleaning up viewer (front):', e);
}
}, 200);
}
});
// 显示查看器
viewer.show();
}
// 添加必要的样式修复(包含移动端优化)
function addFixStyles() {
const style = document.createElement('style');
style.textContent = `
/* 确保ViewerJS样式正常显示 */
.viewer-container { z-index: 999999 !important; }
.viewer-backdrop { z-index: 999998 !important; }
/* 修复关闭按钮样式 */
.viewer-button {
display: block !important;
visibility: visible !important;
opacity: 1 !important;
z-index: 1000000 !important;
pointer-events: auto !important;
}
/* 修复工具栏样式 */
.viewer-toolbar {
z-index: 1000001 !important;
margin-bottom: 20px !important;
}
.viewer-toolbar ul {
display: flex !important;
justify-content: center !important;
padding: 10px !important;
background: rgba(0,0,0,0.5) !important;
border-radius: 10px !important;
margin: 0 auto !important;
}
.viewer-toolbar li {
margin: 0 5px !important;
width: 44px !important;
height: 44px !important;
border-radius: 50% !important;
background: rgba(255,255,255,0.1) !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
cursor: pointer !important;
pointer-events: auto !important;
}
.viewer-toolbar li:hover {
background: rgba(255,255,255,0.3) !important;
}
/* 确保图片可点击 */
img[data-viewer-inited="true"] {
pointer-events: auto !important;
}
/* 移动端适配 */
@media (max-width: 768px) {
.viewer-toolbar li {
width: 40px !important;
height: 40px !important;
}
/* 移动端优化正面图片显示 */
#front-card-basic img {
max-width: 100% !important;
height: auto !important;
display: block !important;
margin: 0 auto !important;
}
}
/* 确保正面字段的图片样式正常 */
#front-card-basic img {
max-width: 100%;
height: auto;
margin: 10px 0;
}
`;
document.head.appendChild(style);
}
// 初始化
addFixStyles();
// 延迟初始化,确保DOM完全加载
setTimeout(initImageViewer, 300);
// 页面卸载时清理
window.addEventListener('beforeunload', () => {
if (viewer) {
try {
viewer.destroy();
} catch (e) {}
}
});
})();
</script>
<div id="front-card-basic">
{{Front}}
</div>
<div id="tags-card">
{{Tags}}
</div>
<div id="difficulty-card">
{{Difficulty}}
</div>
<!-- 加载其他资源(保留原有逻辑) -->
<script>
(function() {
var jsLocal = '_better_markdown_anki.js';
var jsCDN = 'https://cdn.jsdelivr.net/gh/alexthillen/[email protected]/better-markdown-anki/dist/_better_markdown_anki.js';
var cssLocal = '_better_markdown_anki.css';
var cssCDN = 'https://cdn.jsdelivr.net/gh/alexthillen/[email protected]/better-markdown-anki/dist/_better_markdown_anki.css';
var cssUser = '_better_markdown_anki_user_style.css';
function loadCSS(href, fallback) {
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = href;
link.onerror = function() {
if (fallback) {
var fallbackLink = document.createElement('link');
fallbackLink.rel = 'stylesheet';
fallbackLink.href = fallback;
document.head.appendChild(fallbackLink);
}
};
document.head.appendChild(link);
}
function loadCSSSilent(href) {
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = href;
link.onerror = function() {
console.log('CSS failed to load:', href);
};
document.head.appendChild(link);
}
function loadJS(src, fallback) {
var scriptSelector = 'script[src="' + src + '"]';
if (!document.querySelector(scriptSelector)) {
var script = document.createElement('script');
script.type = 'module'; // Essential for ES modules
script.src = src;
script.onerror = function() {
if (fallback && !document.querySelector('script[src="' + fallback + '"]')) {
var fallbackScript = document.createElement('script');
fallbackScript.type = 'module';
fallbackScript.src = fallback;
document.head.appendChild(fallbackScript);
}
};
document.head.appendChild(script);
}
}
loadCSS(cssLocal, cssCDN);
loadCSSSilent(cssUser);
loadJS(jsLocal, jsCDN);
})();
</script>
<!-- prettier-ignore -->
<!-- format-ignore -->
<div id="front-card-basic">
{{Front}}
</div>
<div id="back-card-basic">
{{Back}}
</div>
<div id="extra-card-basic">
{{Extra}}
</div>
<div id="tags-card">
{{Tags}}
</div>
<div id="difficulty-card">
{{Difficulty}}
</div>
<!-- 先加载必要的CSS(ViewerJS核心样式) -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.7/viewer.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/css/font-awesome.min.css">
<script>
(function() {
// 全局变量只保留必要的
let viewer = null;
let isViewerActive = false;
// 增强的图片查找函数 - 覆盖所有卡片区域的图片
function findAllImages() {
// 按优先级查找图片,包含正面、背面、额外字段的所有图片
const selectors = [
'img', // 匹配所有图片(最高优先级)
'#front-card-basic img',
'#back-card-basic img',
'#extra-card-basic img',
'.card img',
'.content img',
'body img:not([data-viewer-inited="true"])'
];
// 去重收集所有图片
const imagesSet = new Set();
selectors.forEach(selector => {
const elements = document.querySelectorAll(selector);
elements.forEach(el => imagesSet.add(el));
});
const imagesArray = Array.from(imagesSet);
console.log('Found total images (back template):', imagesArray.length);
// 打印每个图片的信息,方便调试
imagesArray.forEach((img, index) => {
console.log(`Image ${index} (back):`, {
src: img.src,
id: img.id,
className: img.className,
parent: img.parentElement.tagName,
container: img.closest('[id*="-card-"]')?.id || 'unknown'
});
});
return imagesArray;
}
// 等待页面完全加载(包括图片)
function waitForCompleteLoad() {
return new Promise(resolve => {
// 如果页面已加载完成
if (document.readyState === 'complete') {
resolve();
} else {
// 等待所有资源加载完成
const onLoad = () => {
document.removeEventListener('DOMContentLoaded', onLoad);
window.removeEventListener('load', onLoad);
resolve();
};
document.addEventListener('DOMContentLoaded', onLoad);
window.addEventListener('load', onLoad);
// 超时保护:1秒后强制解析
setTimeout(resolve, 1000);
}
});
}
// 加载ViewerJS
function loadViewerJS() {
return new Promise((resolve, reject) => {
if (window.Viewer) {
resolve(window.Viewer);
return;
}
const script = document.createElement('script');
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/viewerjs/1.11.7/viewer.min.js';
script.onload = () => resolve(window.Viewer);
script.onerror = (e) => reject(e);
document.head.appendChild(script);
});
}
// 初始化图片查看器
async function initImageViewer() {
try {
// 等待页面完全加载(包括图片)
await waitForCompleteLoad();
console.log('Page fully loaded (back template), starting viewer init');
// 加载ViewerJS
await loadViewerJS();
console.log('ViewerJS loaded successfully (back template)');
// 查找所有图片(增强版)
const images = findAllImages();
if (images.length === 0) {
console.warn('No images found in back template');
// 尝试延迟再查找一次
setTimeout(() => {
const retryImages = findAllImages();
if (retryImages.length > 0) {
setupImageClickHandlers(retryImages);
}
}, 500);
return;
}
// 为图片绑定点击事件
setupImageClickHandlers(images);
} catch (error) {
console.error('Failed to initialize viewer (back template):', error);
}
}
// 为图片绑定点击事件
function setupImageClickHandlers(images) {
images.forEach(img => {
// 避免重复处理
if (img.dataset.viewerInited) return;
img.dataset.viewerInited = 'true';
// 设置基础样式
img.style.cursor = 'zoom-in';
img.style.maxWidth = '100%';
img.style.height = 'auto';
console.log('Binding click handler to image (back):', img.src);
// 点击图片打开查看器
img.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
console.log('Image clicked (back), opening viewer:', this.src);
openViewer(this);
});
});
console.log('Viewer initialized for', images.length, 'images (back template)');
}
// 打开查看器(修复了点击图片显示不正确的问题)
function openViewer(targetImg) {
// 如果已有查看器,先销毁
if (viewer) {
try {
viewer.destroy();
} catch (e) {
console.warn('Error destroying old viewer (back):', e);
}
}
// 收集所有已初始化的图片
const imageElements = Array.from(document.querySelectorAll('img[data-viewer-inited="true"]'));
// 找到当前图片的索引
const startIndex = imageElements.indexOf(targetImg);
console.log('Opening viewer for image index (back):', startIndex, 'out of', imageElements.length);
if (startIndex === -1) {
console.error('Target image not found in imageElements');
return;
}
// 创建一个临时的图片容器,仅用于ViewerJS初始化
const tempContainer = document.createElement('div');
tempContainer.style.display = 'none';
tempContainer.id = 'viewer-temp-container';
// 为临时容器添加所有图片
imageElements.forEach((img, index) => {
const imgClone = img.cloneNode(true);
imgClone.style.display = 'block';
imgClone.style.width = '100%';
imgClone.style.height = 'auto';
tempContainer.appendChild(imgClone);
});
document.body.appendChild(tempContainer);
// 创建Viewer实例,使用临时容器中的图片
viewer = new Viewer(tempContainer, {
button: true,
toolbar: {
zoomIn: 1,
zoomOut: 1,
oneToOne: 1,
reset: 1,
prev: 1,
play: 0,
next: 1,
rotateLeft: 1,
rotateRight: 1,
flipHorizontal: 1,
flipVertical: 1,
},
navbar: true,
title: true,
keyboard: true,
movable: true,
zoomable: true,
rotatable: true,
scalable: true,
fullscreen: true,
loop: true,
inline: false,
shown: function() {
console.log('Viewer opened successfully (back template)');
isViewerActive = true;
// 立即跳转到点击的图片
if (startIndex >= 0) {
viewer.view(startIndex);
}
// 确保关闭按钮可见
setTimeout(() => {
const closeBtn = document.querySelector('.viewer-button.viewer-close');
if (closeBtn) {
closeBtn.style.display = 'block';
closeBtn.style.opacity = '1';
closeBtn.style.zIndex = '999999';
closeBtn.style.pointerEvents = 'auto';
}
}, 100);
},
hidden: function() {
console.log('Viewer closed (back template)');
isViewerActive = false;
// 清理临时容器和实例
setTimeout(() => {
try {
if (tempContainer && tempContainer.parentNode) {
tempContainer.parentNode.removeChild(tempContainer);
}
viewer.destroy();
viewer = null;
} catch (e) {
console.warn('Error cleaning up viewer (back):', e);
}
}, 200);
}
});
// 显示查看器
viewer.show();
}
// 添加必要的样式修复
function addFixStyles() {
const style = document.createElement('style');
style.textContent = `
/* 确保ViewerJS样式正常显示 */
.viewer-container { z-index: 999999 !important; }
.viewer-backdrop { z-index: 999998 !important; }
/* 修复关闭按钮样式 */
.viewer-button {
display: block !important;
visibility: visible !important;
opacity: 1 !important;
z-index: 1000000 !important;
pointer-events: auto !important;
}
/* 修复工具栏样式 */
.viewer-toolbar {
z-index: 1000001 !important;
margin-bottom: 20px !important;
}
.viewer-toolbar ul {
display: flex !important;
justify-content: center !important;
padding: 10px !important;
background: rgba(0,0,0,0.5) !important;
border-radius: 10px !important;
margin: 0 auto !important;
}
.viewer-toolbar li {
margin: 0 5px !important;
width: 44px !important;
height: 44px !important;
border-radius: 50% !important;
background: rgba(255,255,255,0.1) !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
cursor: pointer !important;
pointer-events: auto !important;
}
.viewer-toolbar li:hover {
background: rgba(255,255,255,0.3) !important;
}
/* 确保图片可点击 */
img[data-viewer-inited="true"] {
pointer-events: auto !important;
}
/* 移动端适配 */
@media (max-width: 768px) {
.viewer-toolbar li {
width: 40px !important;
height: 40px !important;
}
/* 移动端优化图片显示 */
#back-card-basic img, #extra-card-basic img {
max-width: 100% !important;
height: auto !important;
display: block !important;
margin: 0 auto !important;
}
}
/* 确保背面和额外字段的图片样式正常 */
#back-card-basic img, #extra-card-basic img {
max-width: 100%;
height: auto;
margin: 10px 0;
}
`;
document.head.appendChild(style);
}
// 初始化
addFixStyles();
// 延迟初始化,确保DOM完全加载(背面模板延迟稍长,确保内容加载)
setTimeout(initImageViewer, 500);
// 页面卸载时清理
window.addEventListener('beforeunload', () => {
if (viewer) {
try {
viewer.destroy();
} catch (e) {}
}
});
})();
</script>
<!-- 加载其他资源(保留原有逻辑) -->
<script>
(function() {
var jsLocal = '_better_markdown_anki.js';
var jsCDN = 'https://cdn.jsdelivr.net/gh/alexthillen/[email protected]/better-markdown-anki/dist/_better_markdown_anki.js';
var cssLocal = '_better_markdown_anki.css';
var cssCDN = 'https://cdn.jsdelivr.net/gh/alexthillen/[email protected]/better-markdown-anki/dist/_better_markdown_anki.css';
var cssUser = '_better_markdown_anki_user_style.css';
function loadCSS(href, fallback) {
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = href;
link.onerror = function() {
if (fallback) {
var fallbackLink = document.createElement('link');
fallbackLink.rel = 'stylesheet';
fallbackLink.href = fallback;
document.head.appendChild(fallbackLink);
}
};
document.head.appendChild(link);
}
function loadCSSSilent(href) {
var link = document.createElement('link');
link.rel = 'stylesheet';
link.href = href;
link.onerror = function() {
console.log('CSS failed to load:', href);
};
document.head.appendChild(link);
}
function loadJS(src, fallback) {
var scriptSelector = 'script[src="' + src + '"]';
if (!document.querySelector(scriptSelector)) {
var script = document.createElement('script');
script.type = 'module'; // Essential for ES modules
script.src = src;
script.onerror = function() {
if (fallback && !document.querySelector('script[src="' + fallback + '"]')) {
var fallbackScript = document.createElement('script');
fallbackScript.type = 'module';
fallbackScript.src = fallback;
document.head.appendChild(fallbackScript);
}
};
document.head.appendChild(script);
}
}
loadCSS(cssLocal, cssCDN);
loadCSSSilent(cssUser);
loadJS(jsLocal, jsCDN);
})();
</script>
Metadata
Metadata
Assignees
Labels
No labels