refactor: 添加中文注释 + 优化模块结构
- 给全部 78 个 Swift 源文件添加详细的中文注释(文件级、类级、方法级) - 删除 LegacyRDReaderController/ 死代码目录(16 文件 4592 行) - 根目录翻页容器文件移入 ReaderView/ 目录 - Resources/ 移入 EPUBCore/Resources/(与使用者归属一致) - RDEPUBTextIndexTable.swift 移入 EPUBTextRendering/(消除反向依赖) - RDURLReaderController.swift 移入 EPUBUI/(入口控制器归入 UI 层) - 更新 podspec 资源路径
This commit is contained in:
@@ -1,19 +1,35 @@
|
||||
// RDEPUBJavaScriptBridge.swift
|
||||
// 原生与 WebView 之间的 JavaScript 桥接层
|
||||
// 定义所有 JS 消息类型(progression/selection/link/error 等),
|
||||
// 生成注入到 WebView 的用户脚本,以及分页渲染、搜索高亮等执行脚本。
|
||||
|
||||
import Foundation
|
||||
|
||||
/// JS 桥接消息类型枚举,每种消息对应 WebView 向原生发送的一种事件
|
||||
enum RDEPUBJavaScriptBridgeMessage: String, CaseIterable {
|
||||
/// 阅读进度变化事件
|
||||
case progressionChanged = "ssReaderProgressionChanged"
|
||||
/// 文本选择变化事件
|
||||
case selectionChanged = "ssReaderSelectionChanged"
|
||||
/// 内部链接点击事件(ss-reader:// 协议)
|
||||
case internalLink = "ssReaderInternalLink"
|
||||
/// 外部链接点击事件(http/https/mailto/tel)
|
||||
case externalLink = "ssReaderExternalLink"
|
||||
/// JavaScript 运行时错误事件
|
||||
case javaScriptError = "ssReaderJSError"
|
||||
/// 固定版式渲染就绪事件
|
||||
case fixedLayoutReady = "ssReaderFixedLayoutReady"
|
||||
}
|
||||
|
||||
/// JavaScript 桥接工具集,负责生成注入脚本和执行脚本
|
||||
enum RDEPUBJavaScriptBridge {
|
||||
/// 所有需要注册的 JS 消息名称列表,用于 WKUserContentController 注册
|
||||
static var messageNames: [String] {
|
||||
RDEPUBJavaScriptBridgeMessage.allCases.map(\.rawValue)
|
||||
}
|
||||
|
||||
/// 获取注入到 WebView 的桥接用户脚本(在 document end 注入)
|
||||
/// 将消息类型占位符替换为实际值,使 JS 端能通过 window.webkit.messageHandlers 发送消息
|
||||
static var userScript: String {
|
||||
RDEPUBAssetRepository.string(
|
||||
for: .bridgeScript,
|
||||
@@ -28,6 +44,10 @@ enum RDEPUBJavaScriptBridge {
|
||||
)
|
||||
}
|
||||
|
||||
/// 生成重排模式下的分页渲染脚本
|
||||
/// 注入 CSS 分页样式、设置页码参数、高亮和目标位置,最后触发进度汇报
|
||||
/// - Parameter request: 重排渲染请求,包含展示样式、高亮、目标位置等信息
|
||||
/// - Returns: 可直接通过 evaluateJavaScript 执行的脚本字符串
|
||||
static func applyPresentationScript(for request: RDEPUBReflowableRenderRequest) -> String {
|
||||
let style = escapedJavaScriptTemplateLiteral(RDEPUBStyleSheetBuilder.renderCSS(for: request.presentation))
|
||||
let pageStride = max(1, request.presentation.viewportSize.width)
|
||||
@@ -52,6 +72,11 @@ enum RDEPUBJavaScriptBridge {
|
||||
"""
|
||||
}
|
||||
|
||||
/// 生成搜索高亮脚本
|
||||
/// 在当前文档和所有 iframe 中查找关键词并用 span 标记高亮,
|
||||
/// 活跃匹配项使用特殊样式并自动滚动到视图中央
|
||||
/// - Parameter presentation: 搜索展示信息(关键词、各资源的匹配数量等)
|
||||
/// - Returns: 搜索高亮脚本字符串
|
||||
static func applySearchScript(for presentation: RDEPUBSearchPresentation?) -> String {
|
||||
let payload = jsonString(from: searchPayload(presentation), fallback: "null")
|
||||
return """
|
||||
@@ -213,12 +238,14 @@ enum RDEPUBJavaScriptBridge {
|
||||
"""
|
||||
}
|
||||
|
||||
/// 转义字符串中的反斜杠和反引号,避免 JS 模板字面量语法错误
|
||||
private static func escapedJavaScriptTemplateLiteral(_ string: String) -> String {
|
||||
string
|
||||
.replacingOccurrences(of: "\\", with: "\\\\")
|
||||
.replacingOccurrences(of: "`", with: "\\`")
|
||||
}
|
||||
|
||||
/// 将高亮数组转换为 JS 可用的字典数组
|
||||
private static func highlightsPayload(_ highlights: [RDEPUBHighlight]) -> [[String: String]] {
|
||||
highlights.compactMap { highlight in
|
||||
guard let rangeInfo = highlight.rangeInfo, !rangeInfo.isEmpty else { return nil }
|
||||
@@ -231,6 +258,7 @@ enum RDEPUBJavaScriptBridge {
|
||||
}
|
||||
}
|
||||
|
||||
/// 将目标位置转换为 JS 可用的字典(含 progression、fragment)
|
||||
private static func targetLocationPayload(_ location: RDEPUBLocation?) -> [String: Any]? {
|
||||
guard let location else { return nil }
|
||||
return [
|
||||
@@ -240,6 +268,7 @@ enum RDEPUBJavaScriptBridge {
|
||||
]
|
||||
}
|
||||
|
||||
/// 将搜索展示信息转换为 JS 可用的字典
|
||||
private static func searchPayload(_ presentation: RDEPUBSearchPresentation?) -> [String: Any]? {
|
||||
guard let presentation else { return nil }
|
||||
return [
|
||||
@@ -254,6 +283,7 @@ enum RDEPUBJavaScriptBridge {
|
||||
]
|
||||
}
|
||||
|
||||
/// 将任意对象序列化为 JSON 字符串,失败时返回 fallback
|
||||
private static func jsonString(from object: Any?, fallback: String) -> String {
|
||||
guard let object else { return fallback }
|
||||
guard JSONSerialization.isValidJSONObject(object),
|
||||
|
||||
Reference in New Issue
Block a user