fix: 移除遗留fmfuncs目录创建 + 清理init_service无用导入 + 文件管理器SVG图标 + 示例插件MD3改造
- init_service: 删除_load_fmfuncs方法和fmfuncs目录创建(已迁移到sdk/) - init_service: 清理未使用的importlib.util和sys导入 - 文件管理器: 全部emoji替换为MD3 SVG矢量图标(文件夹/文件类型/右键菜单) - 示例插件: dashboard.html改为MD3风格 CSS变量自动适配日夜主题 - 面包屑: 加底色+模糊+左右外边距 - CSS: .btn::after加pointer-events:none - 插件开发指南: 更新2.6节MD3主题同步和完善的CSS变量/组件类参考表 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+78
-26
@@ -154,8 +154,12 @@ async function loadPluginPage(pluginName) {
|
||||
var scripts = [];
|
||||
clean = clean.replace(/<script\b[^>]*>([\s\S]*?)<\/script>/gi, function(m,code){ scripts.push(code.trim()); return ''; });
|
||||
|
||||
// Scope plugin styles: replace body selector with .plugin-page-root to avoid
|
||||
// styling the main page's <body> element
|
||||
styles = styles.replace(/body\s*\{/gi, '.plugin-page-root{').replace(/body\b/gi, '.plugin-page-root');
|
||||
|
||||
content.style.padding = '0';
|
||||
content.innerHTML = '<style>'+styles+'</style>'+clean;
|
||||
content.innerHTML = '<div class="plugin-page-root"><style>'+styles+'</style>'+clean+'</div>';
|
||||
|
||||
scripts.forEach(function(code){
|
||||
try { var s=document.createElement('script'); s.textContent=code; document.head.appendChild(s); document.head.removeChild(s); }
|
||||
@@ -172,51 +176,99 @@ async function loadPluginPage(pluginName) {
|
||||
}
|
||||
|
||||
|
||||
// ═══ Global file/dir picker (in-page iframe modal) ═══
|
||||
// ═══ Global file/dir picker (in-page overlay, no iframe) ═══
|
||||
window.pickPath = function(mode, callback) {
|
||||
var id = 'picker_' + Date.now();
|
||||
var url = './static/pages/files.html?picker=1&mode=' + (mode || 'dir') + '&cb=' + id;
|
||||
|
||||
// Create modal overlay
|
||||
var overlay = document.createElement('div');
|
||||
overlay.id = 'fm-picker-overlay';
|
||||
overlay.style.cssText = 'position:fixed;inset:0;z-index:500;background:rgba(0,0,0,.5);display:flex;align-items:center;justify-content:center';
|
||||
overlay.onclick = function(e) { if (e.target === overlay) closePicker(); };
|
||||
|
||||
var box = document.createElement('div');
|
||||
box.style.cssText = 'background:var(--md-sys-color-surface-container-high);border-radius:var(--shape-lg);width:720px;height:520px;max-width:95vw;max-height:85vh;display:flex;flex-direction:column;overflow:hidden;box-shadow:var(--md-sys-elevation-5)';
|
||||
|
||||
// Header
|
||||
// Header with close button
|
||||
var header = document.createElement('div');
|
||||
header.style.cssText = 'display:flex;justify-content:space-between;align-items:center;padding:12px 16px;border-bottom:1px solid var(--outline);flex-shrink:0';
|
||||
header.innerHTML = '<span style="font-weight:500;color:var(--primary)">📂 选择' + (mode==='file'?'文件':'目录') + '</span>' +
|
||||
'<button class="btn btn-sm btn-outlined" onclick="closePicker()" style="font-size:16px;line-height:1">✕</button>';
|
||||
var headerTitle = document.createElement('span');
|
||||
headerTitle.style.cssText = 'font-weight:500;color:var(--primary)';
|
||||
headerTitle.textContent = '📂 选择' + (mode==='file'?'文件':'目录');
|
||||
header.appendChild(headerTitle);
|
||||
var closeBtn = document.createElement('span');
|
||||
closeBtn.style.cssText = 'cursor:pointer;font-size:20px;line-height:1;padding:4px 8px;border-radius:4px;color:var(--text-dim)';
|
||||
closeBtn.textContent = '✕';
|
||||
closeBtn.onclick = function(){ closePicker(); };
|
||||
header.appendChild(closeBtn);
|
||||
box.appendChild(header);
|
||||
|
||||
// Iframe
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.src = url;
|
||||
iframe.style.cssText = 'flex:1;border:none;width:100%';
|
||||
box.appendChild(iframe);
|
||||
// Content area — load file manager via fetch
|
||||
var contentArea = document.createElement('div');
|
||||
contentArea.style.cssText = 'flex:1;overflow:hidden;display:flex;flex-direction:column';
|
||||
box.appendChild(contentArea);
|
||||
overlay.appendChild(box);
|
||||
document.body.appendChild(overlay);
|
||||
|
||||
function closePicker() {
|
||||
window.removeEventListener('message', handler);
|
||||
if (overlay.parentNode) overlay.parentNode.removeChild(overlay);
|
||||
}
|
||||
window._closePicker = closePicker;
|
||||
// Close on backdrop click
|
||||
overlay.addEventListener('click', function(e){ if(e.target===overlay) closePicker(); });
|
||||
|
||||
// Listen for pick result from iframe
|
||||
window.addEventListener('message', function handler(e) {
|
||||
try {
|
||||
var d = JSON.parse(e.data);
|
||||
if (d.action === 'fm-picked' && d.callback_id === id) {
|
||||
closePicker();
|
||||
if (d.path && callback) callback(d.path);
|
||||
function closePicker() {
|
||||
if(overlay.parentNode) overlay.parentNode.removeChild(overlay);
|
||||
}
|
||||
|
||||
// Load file manager HTML into content area
|
||||
fetch('./static/pages/files.html?t=' + Date.now())
|
||||
.then(function(r){ return r.text(); })
|
||||
.then(function(html){
|
||||
// Strip meta and CSS link (already available in main page)
|
||||
html = html.replace(/<meta[^>]*>/gi, '').replace(/<link[^>]*>/gi, '');
|
||||
// Extract inline scripts
|
||||
var scripts = [];
|
||||
var clean = html.replace(/<script\b[^>]*>([\s\S]*?)<\/script>/gi, function(m,code){ scripts.push(code.trim()); return ''; });
|
||||
contentArea.innerHTML = clean;
|
||||
// Execute scripts
|
||||
scripts.forEach(function(code){
|
||||
try { var s=document.createElement('script'); s.textContent=code; document.head.appendChild(s); document.head.removeChild(s); }
|
||||
catch(ex){}
|
||||
});
|
||||
// Load files.js if not already loaded
|
||||
// Fix container height for overlay
|
||||
var fmContainer = contentArea.querySelector('.fm-container');
|
||||
if(fmContainer) fmContainer.style.height = '100%';
|
||||
function doInit(){
|
||||
window.FilesModule._apiBase = '';
|
||||
window.FilesModule.currentPath = '';
|
||||
window.FilesModule.pickerMode = mode || 'dir';
|
||||
window.FilesModule.pickerCallback = id;
|
||||
window.FilesModule._scope = contentArea;
|
||||
window.FilesModule._getEl = function(sel){ return contentArea.querySelector(sel); };
|
||||
// Override _pickResult to close overlay instead of alert
|
||||
window.FilesModule._pickResult = function(path){
|
||||
closePicker();
|
||||
if(callback) callback(path || window.FilesModule.currentPath || '/');
|
||||
};
|
||||
if(window.FilesModule.destroy) window.FilesModule.destroy();
|
||||
if(window.FilesModule.init) window.FilesModule.init();
|
||||
}
|
||||
} catch(ex) {}
|
||||
});
|
||||
// Override picker actions to close overlay and call callback
|
||||
window._fmPick = function(){
|
||||
var p = window.FilesModule && window.FilesModule.currentPath || '/';
|
||||
closePicker();
|
||||
if(callback) callback(p);
|
||||
};
|
||||
window._fmCancel = function(){ closePicker(); };
|
||||
|
||||
if(window.FilesModule){ doInit(); }
|
||||
else {
|
||||
var s=document.createElement('script');
|
||||
s.src='./static/pages/files.js?v=0603';
|
||||
s.onload=doInit;
|
||||
document.head.appendChild(s);
|
||||
}
|
||||
})
|
||||
.catch(function(e){
|
||||
contentArea.innerHTML = '<div style="color:var(--error);padding:40px;text-align:center">加载失败: '+e.message+'</div>';
|
||||
});
|
||||
};
|
||||
|
||||
// ═══ Sidebar toggle ═══
|
||||
|
||||
Reference in New Issue
Block a user