- 给全部 78 个 Swift 源文件添加详细的中文注释(文件级、类级、方法级) - 删除 LegacyRDReaderController/ 死代码目录(16 文件 4592 行) - 根目录翻页容器文件移入 ReaderView/ 目录 - Resources/ 移入 EPUBCore/Resources/(与使用者归属一致) - RDEPUBTextIndexTable.swift 移入 EPUBTextRendering/(消除反向依赖) - RDURLReaderController.swift 移入 EPUBUI/(入口控制器归入 UI 层) - 更新 podspec 资源路径
64 lines
3.2 KiB
Swift
64 lines
3.2 KiB
Swift
// RDEPUBFixedLayoutTemplate.swift
|
||
// 固定版式(Fixed Layout)HTML 模板生成器
|
||
// 根据渲染请求和 Publication 信息,将 iframe 拼装到 HTML 模板中,
|
||
// 生成适配视口尺寸和内边距的固定版式页面 HTML。
|
||
|
||
import Foundation
|
||
|
||
/// 固定版式模板生成器,负责将 spine 资源渲染为 iframe 嵌套的 HTML 页面
|
||
enum RDEPUBFixedLayoutTemplate {
|
||
/// 根据渲染请求和 Publication 生成固定版式页面的完整 HTML
|
||
/// - Parameters:
|
||
/// - request: 固定版式渲染请求(含 spread、视口尺寸、内边距、适配模式等)
|
||
/// - publication: EPUB 出版物,用于解析资源 URL
|
||
/// - Returns: 完整的 HTML 字符串
|
||
static func html(for request: RDEPUBFixedRenderRequest, publication: RDEPUBPublication) -> String {
|
||
// 遍历 spread 中的每个资源,生成对应的 iframe pane HTML
|
||
let panes = request.spread.resources.enumerated().compactMap { index, resource -> String? in
|
||
guard let url = publication.resourceResolver.resourceURL(forRelativePath: resource.href)?.absoluteString else {
|
||
return nil
|
||
}
|
||
|
||
// 根据 spread 中的资源数量判断页面类型:单页/左页/右页/居中
|
||
let pageType: String
|
||
if request.spread.resources.count == 1 {
|
||
pageType = "single"
|
||
} else if request.spread.resources.count == 2 {
|
||
pageType = index == 0 ? "left" : "right"
|
||
} else {
|
||
pageType = "center"
|
||
}
|
||
|
||
return """
|
||
<div class=\"ss-fixed-viewport\" data-page-type=\"\(pageType)\">
|
||
<iframe class=\"ss-fixed-page\" data-page-type=\"\(pageType)\" scrolling=\"no\" src=\"\(url)\"></iframe>
|
||
</div>
|
||
"""
|
||
}.joined()
|
||
|
||
// 计算视口区域(去除内边距后的可用区域)
|
||
let background = request.backgroundColorCSS ?? "#FFFFFF"
|
||
let viewportWidth = max(1, Int((request.viewportSize.width - request.contentInset.left - request.contentInset.right).rounded(.down)))
|
||
let viewportHeight = max(1, Int((request.viewportSize.height - request.contentInset.top - request.contentInset.bottom).rounded(.down)))
|
||
let insetTop = Int(request.contentInset.top.rounded(.down))
|
||
let insetRight = Int(request.contentInset.right.rounded(.down))
|
||
let insetBottom = Int(request.contentInset.bottom.rounded(.down))
|
||
let insetLeft = Int(request.contentInset.left.rounded(.down))
|
||
// 从资源仓库加载 HTML 模板并替换占位符
|
||
return RDEPUBAssetRepository.string(
|
||
for: .fixedLayoutTemplate,
|
||
replacements: [
|
||
"BACKGROUND": background,
|
||
"INSET_TOP": String(insetTop),
|
||
"INSET_RIGHT": String(insetRight),
|
||
"INSET_BOTTOM": String(insetBottom),
|
||
"INSET_LEFT": String(insetLeft),
|
||
"VIEWPORT_WIDTH": String(viewportWidth),
|
||
"VIEWPORT_HEIGHT": String(viewportHeight),
|
||
"PANES": panes,
|
||
"FIT_MODE": request.fit.rawValue,
|
||
"FIXED_LAYOUT_READY_MESSAGE": RDEPUBJavaScriptBridgeMessage.fixedLayoutReady.rawValue
|
||
]
|
||
)
|
||
}
|
||
} |