update at 2025-10-16 16:10:58

This commit is contained in:
douboer
2025-10-16 16:10:58 +08:00
parent 9f3a4e8812
commit 28942bea17
17 changed files with 1843 additions and 23 deletions

263
src/core/html-processor.ts Normal file
View File

@@ -0,0 +1,263 @@
/**
* 文件html-processor.ts
* 作用处理HTML内容的生成和格式化
*
* 职责:
* 1. HTML内容清理和格式化
* 2. CSS样式内联处理
* 3. HTML结构生成
* 4. 代码高亮处理
*/
import { sanitizeHTMLToDom } from 'obsidian';
import { applyCSS } from '../utils';
import InlineCSS from '../inline-css';
import { NMPSettings } from '../settings';
import AssetsManager from '../assets';
import { ErrorHandler } from './error-handler';
export interface HtmlProcessOptions {
enableCodeHighlight?: boolean;
enableInlineCSS?: boolean;
theme?: string;
highlight?: string;
customCSS?: string;
}
/**
* HTML处理器类
*/
export class HtmlProcessor {
private settings: NMPSettings;
private assetsManager: AssetsManager;
constructor() {
this.settings = NMPSettings.getInstance();
this.assetsManager = AssetsManager.getInstance();
}
/**
* 生成完整的HTML文档
*/
generateFullHtml(content: string, options: HtmlProcessOptions = {}): string {
try {
const theme = options.theme || this.settings.defaultStyle;
const highlight = options.highlight || this.settings.defaultHighlight;
// 获取基础样式
const baseCSS = this.getBaseCSS(theme, highlight);
// 处理自定义CSS
let customCSS = options.customCSS || '';
if (this.settings.useCustomCss && this.settings.customCSSNote) {
customCSS += '\n' + this.settings.customCSSNote;
}
// 构建完整HTML
const html = `
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Note2Any Export</title>
<style>
${baseCSS}
${customCSS}
</style>
</head>
<body>
<div class="note2any">
${content}
</div>
</body>
</html>`;
return html;
} catch (error) {
ErrorHandler.handle(error as Error, 'HtmlProcessor.generateFullHtml');
throw error;
}
}
/**
* 处理HTML内容的内联CSS
*/
async processInlineCSS(html: string): Promise<string> {
// 简化版内联CSS处理使用原生方法
try {
// 这里可以实现一个简单的CSS内联功能
// 或者集成第三方库如 juice
return html;
} catch (error) {
ErrorHandler.handle(error as Error, 'HtmlProcessor.processInlineCSS');
console.warn('[HtmlProcessor] 内联CSS处理失败使用原始HTML', error);
return html;
}
}
/**
* 清理和格式化HTML内容
*/
sanitizeHtml(html: string): DocumentFragment {
try {
return sanitizeHTMLToDom(html);
} catch (error) {
ErrorHandler.handle(error as Error, 'HtmlProcessor.sanitizeHtml');
throw error;
}
}
/**
* 应用CSS样式到元素
*/
applyStylesToElement(html: string, css: string): string {
try {
return applyCSS(html, css);
} catch (error) {
ErrorHandler.handle(error as Error, 'HtmlProcessor.applyStylesToElement');
throw error;
}
}
/**
* 获取基础CSS样式
*/
private getBaseCSS(theme: string, highlight: string): string {
try {
let css = '';
// 主题样式
const themeCSS = this.assetsManager.getTheme(theme);
if (themeCSS) {
css += themeCSS + '\n';
}
// 代码高亮样式
const highlightCSS = this.assetsManager.getHighlight(highlight);
if (highlightCSS) {
css += highlightCSS + '\n';
}
return css;
} catch (error) {
ErrorHandler.handle(error as Error, 'HtmlProcessor.getBaseCSS');
return '';
}
}
/**
* 生成响应式HTML包装器
*/
wrapWithResponsive(content: string, maxWidth = '800px'): string {
return `
<div style="max-width: ${maxWidth}; margin: 0 auto; padding: 20px; box-sizing: border-box;">
${content}
</div>`;
}
/**
* 添加打印样式
*/
addPrintStyles(): string {
return `
<style media="print">
@page {
margin: 2cm;
size: A4;
}
.note2any {
max-width: none !important;
margin: 0 !important;
padding: 0 !important;
}
.no-print {
display: none !important;
}
pre {
white-space: pre-wrap !important;
word-break: break-word !important;
}
img {
max-width: 100% !important;
height: auto !important;
page-break-inside: avoid;
}
h1, h2, h3, h4, h5, h6 {
page-break-after: avoid;
}
p, li {
orphans: 3;
widows: 3;
}
</style>`;
}
/**
* 处理代码块高亮
*/
processCodeHighlight(html: string, highlight: string): string {
try {
// 这里可以添加更复杂的代码高亮处理逻辑
// 目前主要依赖 AssetsManager 提供的高亮样式
return html;
} catch (error) {
ErrorHandler.handle(error as Error, 'HtmlProcessor.processCodeHighlight');
return html;
}
}
/**
* 优化HTML结构用于移动端显示
*/
optimizeForMobile(html: string): string {
try {
// 添加移动端优化的meta标签和样式
const mobileOptimizations = `
<meta name="format-detection" content="telephone=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<style>
/* 移动端优化样式 */
@media screen and (max-width: 768px) {
.note2any {
padding: 15px 10px !important;
font-size: 16px !important;
line-height: 1.6 !important;
}
pre, code {
font-size: 14px !important;
overflow-x: auto !important;
white-space: pre-wrap !important;
}
table {
font-size: 14px !important;
display: block !important;
overflow-x: auto !important;
white-space: nowrap !important;
}
img {
max-width: 100% !important;
height: auto !important;
}
}
</style>`;
// 在head标签中插入移动端优化
return html.replace('</head>', mobileOptimizations + '</head>');
} catch (error) {
ErrorHandler.handle(error as Error, 'HtmlProcessor.optimizeForMobile');
return html;
}
}
}