右对齐文本显示修复(如"巫鸿"只显示"鸿"的问题): - RDEPUBChapterTailNormalizer: 短尾页合并时检查 avoidPageBreakInside 语义, 避免将带有此标记的短文本(如 right-info 署名)错误合并回上一页 - RDEPUBTextContentView: 续段归一化时跳过右对齐/居中对齐的段落, 防止错误修改 firstLineHeadIndent 导致首字不可见 - RDEPUBCSSCompatibilityLayer: 为含 text-align:right/center 的 CSS 块 自动注入 text-indent:0 !important,确保右对齐/居中文本无首行缩进 - RDEPUBTextRendererSupport: 排版属性归一化时将右对齐/居中段落的 firstLineHeadIndent 重置为 0 图片查看器及脚注点击功能: - 新增 RDEPUBImageViewController 和 RDEPUBImageViewerCoordinator, 支持从 WebView 和 TextPage 两种模式查看图片 - epub-bridge.js: 检测图片和脚注图片的点击事件,脚注图片显示弹窗 - RDEPUBJavaScriptBridge: 新增 imageDidTap/footnoteDidTap 桥接消息 - RDEPUBWebView: 新增图片和脚注点击的 delegate 方法 - RDEPUBAttachmentNormalizer: 改进脚注检测,优先使用 alt 文本判断 - RDEPUBPaginationModels: 新增 .footnote 附件类型 - RDEPUBPageLayoutSnapshot: 运行时动态解析附件类型,脚注优先级高于图片 位置解析改进: - RDEPUBReaderController+LocationResolution: 利用 rangeInfo 提升页码定位精度 其他: - RDEPUBTextBookCache: schema 版本升级至 13 - RDEPUBReaderTheme: 主题更新 - Pod 项目文件更新 Co-Authored-By: Claude <noreply@anthropic.com>
551 lines
19 KiB
JavaScript
551 lines
19 KiB
JavaScript
(function() {
|
|
if (window.RDReaderBridge) { return; }
|
|
window.addEventListener('error', function(event) {
|
|
try {
|
|
var message = event && (event.message || (event.error && event.error.message)) || 'Unknown JavaScript error';
|
|
window.webkit.messageHandlers.{{JAVASCRIPT_ERROR_MESSAGE}}.postMessage(message);
|
|
} catch (error) {
|
|
}
|
|
});
|
|
function serializeRange(range) {
|
|
if (window.rangy && typeof window.rangy.serializeRange === 'function') {
|
|
return window.rangy.serializeRange(range, range && range.startContainer && range.startContainer.ownerDocument);
|
|
}
|
|
return null;
|
|
}
|
|
function rangeFromInfo(rangeInfo) {
|
|
if (window.rangy && typeof window.rangy.deserializeRange === 'function') {
|
|
return window.rangy.deserializeRange(rangeInfo, document);
|
|
}
|
|
return null;
|
|
}
|
|
var visiblePageIndex = 0;
|
|
var configuredPageCount = 1;
|
|
var configuredPageStride = 1;
|
|
var relayoutTimer = null;
|
|
var fixedLayoutDocument = false;
|
|
function isFixedLayoutDocument() {
|
|
if (fixedLayoutDocument) { return true; }
|
|
fixedLayoutDocument = !!document.getElementById('ss-fixed-root') || !!document.querySelector('.ss-fixed-page');
|
|
return fixedLayoutDocument;
|
|
}
|
|
function ensurePaginationStructure() {
|
|
if (isFixedLayoutDocument()) {
|
|
return null;
|
|
}
|
|
var viewport = document.getElementById('ss-reader-viewport');
|
|
var content = document.getElementById('ss-reader-content');
|
|
if (viewport && content) {
|
|
return content;
|
|
}
|
|
|
|
viewport = document.createElement('div');
|
|
viewport.id = 'ss-reader-viewport';
|
|
content = document.createElement('div');
|
|
content.id = 'ss-reader-content';
|
|
|
|
while (document.body.firstChild) {
|
|
content.appendChild(document.body.firstChild);
|
|
}
|
|
|
|
viewport.appendChild(content);
|
|
document.body.appendChild(viewport);
|
|
return content;
|
|
}
|
|
function paginationContent() {
|
|
if (isFixedLayoutDocument()) {
|
|
return null;
|
|
}
|
|
return ensurePaginationStructure();
|
|
}
|
|
function effectivePageStride() {
|
|
return Math.max(1, configuredPageStride || 1);
|
|
}
|
|
function measuredPageCount() {
|
|
if (isFixedLayoutDocument()) {
|
|
return 1;
|
|
}
|
|
var content = paginationContent();
|
|
var scrollingElement = document.scrollingElement || document.documentElement || document.body;
|
|
var scrollWidth = Math.max(
|
|
content ? content.scrollWidth : 0,
|
|
content ? content.offsetWidth : 0,
|
|
scrollingElement ? scrollingElement.scrollWidth : 0,
|
|
document.documentElement ? document.documentElement.scrollWidth : 0,
|
|
document.body ? document.body.scrollWidth : 0,
|
|
effectivePageStride()
|
|
);
|
|
return Math.max(1, Math.ceil(scrollWidth / effectivePageStride()));
|
|
}
|
|
function totalPageCount() {
|
|
return Math.max(configuredPageCount, measuredPageCount());
|
|
}
|
|
function currentPageOffset() {
|
|
return Math.round(visiblePageIndex * effectivePageStride());
|
|
}
|
|
function reportProgression(fragment) {
|
|
var pageCount = totalPageCount();
|
|
var progression = pageCount <= 1 ? 0 : visiblePageIndex / Math.max(pageCount - 1, 1);
|
|
var lastProgression = progression;
|
|
window.webkit.messageHandlers.{{PROGRESSION_CHANGED_MESSAGE}}.postMessage({
|
|
progression: progression,
|
|
lastProgression: lastProgression,
|
|
fragment: fragment || null
|
|
});
|
|
}
|
|
function setVisiblePageIndex(pageIndex) {
|
|
if (isFixedLayoutDocument()) {
|
|
visiblePageIndex = 0;
|
|
return;
|
|
}
|
|
var pageCount = totalPageCount();
|
|
var maxPageIndex = Math.max(0, pageCount - 1);
|
|
var safePageIndex = Math.max(0, Math.min(maxPageIndex, Math.round(pageIndex || 0)));
|
|
visiblePageIndex = safePageIndex;
|
|
var content = paginationContent();
|
|
if (content) {
|
|
content.style.transform = 'translate3d(' + (-currentPageOffset()) + 'px, 0, 0)';
|
|
}
|
|
}
|
|
function scheduleRelayout() {
|
|
if (isFixedLayoutDocument()) { return; }
|
|
clearTimeout(relayoutTimer);
|
|
relayoutTimer = setTimeout(function() {
|
|
setVisiblePageIndex(visiblePageIndex);
|
|
reportProgression(null);
|
|
}, 60);
|
|
}
|
|
function pageIndexForElement(target) {
|
|
if (isFixedLayoutDocument()) { return 0; }
|
|
if (!target) { return 0; }
|
|
var rect = target.getBoundingClientRect();
|
|
var absoluteLeft = Math.max(0, rect.left + currentPageOffset());
|
|
return Math.max(0, Math.floor(absoluteLeft / effectivePageStride()));
|
|
}
|
|
function fragmentTarget(fragment) {
|
|
if (!fragment) { return null; }
|
|
var contexts = documentContexts(document, 0, 0);
|
|
for (var index = 0; index < contexts.length; index += 1) {
|
|
var context = contexts[index];
|
|
var target = context.doc.getElementById(fragment)
|
|
|| context.doc.querySelector('[name="' + fragment.replace(/"/g, '\\"') + '"]');
|
|
if (target) {
|
|
return {
|
|
context: context,
|
|
target: target
|
|
};
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
var storedHighlights = [];
|
|
var storedSearchPresentation = null;
|
|
function normalizeHref(rawHref) {
|
|
if (!rawHref) { return ''; }
|
|
var value = String(rawHref);
|
|
value = value.replace(/^.*?:\/\/[^/]+\//, '');
|
|
value = value.split('#')[0];
|
|
value = value.replace(/^\/+/, '');
|
|
try {
|
|
value = decodeURIComponent(value);
|
|
} catch (error) {
|
|
}
|
|
return value;
|
|
}
|
|
function clearHighlights() {
|
|
storedHighlights = [];
|
|
}
|
|
function setHighlights(items) {
|
|
storedHighlights = Array.isArray(items) ? items.slice() : [];
|
|
}
|
|
function setSearchPresentation(payload) {
|
|
storedSearchPresentation = payload || null;
|
|
}
|
|
function textNodes(doc) {
|
|
if (!doc || !doc.body) { return []; }
|
|
var walker = doc.createTreeWalker(doc.body, NodeFilter.SHOW_TEXT, {
|
|
acceptNode: function(node) {
|
|
if (!node || !node.nodeValue || !node.nodeValue.trim()) {
|
|
return NodeFilter.FILTER_REJECT;
|
|
}
|
|
var parent = node.parentNode;
|
|
if (!parent || !parent.nodeName) {
|
|
return NodeFilter.FILTER_REJECT;
|
|
}
|
|
var name = parent.nodeName.toLowerCase();
|
|
if (['script', 'style', 'noscript'].indexOf(name) >= 0) {
|
|
return NodeFilter.FILTER_REJECT;
|
|
}
|
|
return NodeFilter.FILTER_ACCEPT;
|
|
}
|
|
});
|
|
var nodes = [];
|
|
while (walker.nextNode()) {
|
|
nodes.push(walker.currentNode);
|
|
}
|
|
return nodes;
|
|
}
|
|
function documentContexts(rootDoc, baseOffsetX, baseOffsetY) {
|
|
var items = [];
|
|
if (!rootDoc) { return items; }
|
|
var offsetX = baseOffsetX || 0;
|
|
var offsetY = baseOffsetY || 0;
|
|
items.push({
|
|
doc: rootDoc,
|
|
href: normalizeHref(rootDoc.location && rootDoc.location.href),
|
|
offsetX: offsetX,
|
|
offsetY: offsetY
|
|
});
|
|
var frames = rootDoc.querySelectorAll ? rootDoc.querySelectorAll('iframe') : [];
|
|
frames.forEach(function(frame) {
|
|
try {
|
|
if (!frame.contentDocument) { return; }
|
|
var frameRect = frame.getBoundingClientRect();
|
|
documentContexts(
|
|
frame.contentDocument,
|
|
offsetX + frameRect.left,
|
|
offsetY + frameRect.top
|
|
).forEach(function(item) {
|
|
items.push(item);
|
|
});
|
|
} catch (error) {
|
|
}
|
|
});
|
|
return items;
|
|
}
|
|
var hookedDocuments = new WeakSet();
|
|
var hookedFrames = new WeakSet();
|
|
function selectionForDocument(doc) {
|
|
if (!doc) { return null; }
|
|
try {
|
|
var view = doc.defaultView || window;
|
|
return view.getSelection ? view.getSelection() : null;
|
|
} catch (error) {
|
|
return null;
|
|
}
|
|
}
|
|
function currentSelectionContext() {
|
|
var contexts = documentContexts(document, 0, 0);
|
|
for (var index = 0; index < contexts.length; index += 1) {
|
|
var context = contexts[index];
|
|
var selection = selectionForDocument(context.doc);
|
|
if (!selection || selection.rangeCount === 0 || selection.isCollapsed) {
|
|
continue;
|
|
}
|
|
var text = selection.toString ? selection.toString() : '';
|
|
if (!text || !text.trim()) {
|
|
continue;
|
|
}
|
|
return {
|
|
context: context,
|
|
selection: selection
|
|
};
|
|
}
|
|
return null;
|
|
}
|
|
function rectPayloadForRange(range, offsetX, offsetY) {
|
|
if (!range || range.collapsed) { return []; }
|
|
var rects = [];
|
|
Array.prototype.forEach.call(range.getClientRects(), function(rect) {
|
|
if (!rect || rect.width < 0.5 || rect.height < 0.5) { return; }
|
|
rects.push({
|
|
x: rect.left + (offsetX || 0),
|
|
y: rect.top + (offsetY || 0),
|
|
width: rect.width,
|
|
height: rect.height
|
|
});
|
|
});
|
|
return rects;
|
|
}
|
|
function collectHighlightDecorations() {
|
|
return storedHighlights.map(function(item, index) {
|
|
if (!item || !item.rangeInfo) { return null; }
|
|
var range = rangeFromInfo(item.rangeInfo);
|
|
var rects = rectPayloadForRange(range, 0, 0);
|
|
if (!rects.length) { return null; }
|
|
return {
|
|
key: item.id || ('highlight-' + index),
|
|
kind: item.style === 'underline' ? 'underline' : 'highlight',
|
|
color: item.color || '#F8E16C',
|
|
rangeInfo: item.rangeInfo,
|
|
rects: rects
|
|
};
|
|
}).filter(Boolean);
|
|
}
|
|
function collectSearchDecorations() {
|
|
if (!storedSearchPresentation || !storedSearchPresentation.keyword) {
|
|
return [];
|
|
}
|
|
|
|
var resources = new Map();
|
|
if (Array.isArray(storedSearchPresentation.resources)) {
|
|
storedSearchPresentation.resources.forEach(function(resource) {
|
|
resources.set(normalizeHref(resource.href), resource);
|
|
});
|
|
}
|
|
|
|
var keyword = String(storedSearchPresentation.keyword);
|
|
var lowerKeyword = keyword.toLowerCase();
|
|
var decorations = [];
|
|
|
|
documentContexts(document, 0, 0).forEach(function(context) {
|
|
var resourceState = resources.get(context.href);
|
|
if (!resourceState || resourceState.matchCount <= 0) {
|
|
return;
|
|
}
|
|
|
|
var activeIndex = typeof resourceState.activeLocalMatchIndex === 'number' ? resourceState.activeLocalMatchIndex : null;
|
|
var currentLocalIndex = 0;
|
|
var activeRect = null;
|
|
var contextStartIndex = decorations.length;
|
|
|
|
textNodes(context.doc).forEach(function(node) {
|
|
var source = node.nodeValue || '';
|
|
var lowerSource = source.toLowerCase();
|
|
var cursor = 0;
|
|
|
|
while (cursor < source.length) {
|
|
var foundIndex = lowerSource.indexOf(lowerKeyword, cursor);
|
|
if (foundIndex < 0) {
|
|
break;
|
|
}
|
|
|
|
var range = context.doc.createRange();
|
|
range.setStart(node, foundIndex);
|
|
range.setEnd(node, foundIndex + keyword.length);
|
|
var rects = rectPayloadForRange(range, context.offsetX, context.offsetY);
|
|
if (rects.length) {
|
|
var isActive = currentLocalIndex === activeIndex;
|
|
decorations.push({
|
|
key: context.href + ':' + currentLocalIndex,
|
|
kind: isActive ? 'activeSearch' : 'search',
|
|
rects: rects
|
|
});
|
|
if (isActive) {
|
|
activeRect = rects[0];
|
|
}
|
|
}
|
|
|
|
currentLocalIndex += 1;
|
|
cursor = foundIndex + keyword.length;
|
|
}
|
|
});
|
|
|
|
if (activeRect && !isFixedLayoutDocument()) {
|
|
var previousPageIndex = visiblePageIndex;
|
|
var activePageIndex = Math.max(0, Math.floor(Math.max(0, activeRect.x + currentPageOffset()) / effectivePageStride()));
|
|
setVisiblePageIndex(activePageIndex);
|
|
var deltaX = (activePageIndex - previousPageIndex) * effectivePageStride();
|
|
if (deltaX !== 0) {
|
|
for (var index = contextStartIndex; index < decorations.length; index += 1) {
|
|
decorations[index].rects = decorations[index].rects.map(function(rect) {
|
|
return {
|
|
x: rect.x - deltaX,
|
|
y: rect.y,
|
|
width: rect.width,
|
|
height: rect.height
|
|
};
|
|
});
|
|
}
|
|
}
|
|
}
|
|
});
|
|
return decorations;
|
|
}
|
|
function resolveDecorations() {
|
|
return {
|
|
highlights: collectHighlightDecorations(),
|
|
search: collectSearchDecorations()
|
|
};
|
|
}
|
|
function selectionPayload() {
|
|
var payloadContext = currentSelectionContext();
|
|
if (!payloadContext) {
|
|
return null;
|
|
}
|
|
var range = payloadContext.selection.getRangeAt(0);
|
|
var text = payloadContext.selection.toString();
|
|
if (!text || !text.trim()) { return null; }
|
|
var pageCount = totalPageCount();
|
|
var progression = pageCount <= 1 ? 0 : visiblePageIndex / Math.max(pageCount - 1, 1);
|
|
var lastProgression = progression;
|
|
return {
|
|
href: payloadContext.context.href || null,
|
|
text: text,
|
|
rangeInfo: serializeRange(range),
|
|
progression: progression,
|
|
lastProgression: lastProgression
|
|
};
|
|
}
|
|
var selectionTimer = null;
|
|
function notifySelectionChange() {
|
|
clearTimeout(selectionTimer);
|
|
selectionTimer = setTimeout(function() {
|
|
var payload = selectionPayload();
|
|
window.webkit.messageHandlers.{{SELECTION_CHANGED_MESSAGE}}.postMessage(payload);
|
|
}, 120);
|
|
}
|
|
function handleDocumentClick(event) {
|
|
// Check for image tap. Footnote images always show the note popup; regular
|
|
// images inside links are left to the link handler below.
|
|
var img = event.target;
|
|
while (img && img.tagName !== 'IMG') {
|
|
img = img.parentElement;
|
|
}
|
|
if (img && img.tagName === 'IMG') {
|
|
var src = img.getAttribute('src');
|
|
var classes = (img.getAttribute('class') || '').toLowerCase();
|
|
var alt = (img.getAttribute('alt') || '').trim();
|
|
var isFootnote = classes.indexOf('qqreader-footnote') >= 0 || alt.length > 0;
|
|
if (isFootnote) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
var footnoteRect = img.getBoundingClientRect();
|
|
window.webkit.messageHandlers.{{FOOTNOTE_DID_TAP_MESSAGE}}.postMessage({
|
|
alt: alt,
|
|
rect: { x: footnoteRect.x, y: footnoteRect.y, width: footnoteRect.width, height: footnoteRect.height }
|
|
});
|
|
return;
|
|
}
|
|
|
|
// If a regular image is inside a link, let the link handler deal with it.
|
|
var linkParent = img.closest ? img.closest('a[href]') : null;
|
|
if (!linkParent) {
|
|
if (src) {
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
var rect = img.getBoundingClientRect();
|
|
window.webkit.messageHandlers.{{IMAGE_DID_TAP_MESSAGE}}.postMessage({
|
|
src: src,
|
|
rect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height }
|
|
});
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
var anchor = event.target.closest ? event.target.closest('a[href]') : null;
|
|
if (!anchor) { return; }
|
|
var href = anchor.getAttribute('href');
|
|
if (!href) { return; }
|
|
if (/^(https?:|mailto:|tel:)/i.test(href)) {
|
|
event.preventDefault();
|
|
window.webkit.messageHandlers.{{EXTERNAL_LINK_MESSAGE}}.postMessage({ url: href });
|
|
return;
|
|
}
|
|
event.preventDefault();
|
|
window.webkit.messageHandlers.{{INTERNAL_LINK_MESSAGE}}.postMessage({ href: href });
|
|
}
|
|
function installDocumentHooks(doc) {
|
|
if (!doc || hookedDocuments.has(doc)) { return; }
|
|
hookedDocuments.add(doc);
|
|
doc.addEventListener('selectionchange', notifySelectionChange);
|
|
doc.addEventListener('click', handleDocumentClick, true);
|
|
}
|
|
function installFrameHooks(rootDoc) {
|
|
if (!rootDoc || !rootDoc.querySelectorAll) { return; }
|
|
Array.prototype.forEach.call(rootDoc.querySelectorAll('iframe'), function(frame) {
|
|
if (hookedFrames.has(frame)) { return; }
|
|
hookedFrames.add(frame);
|
|
var hookFrameDocument = function() {
|
|
try {
|
|
if (!frame.contentDocument) { return; }
|
|
installDocumentHooks(frame.contentDocument);
|
|
installFrameHooks(frame.contentDocument);
|
|
} catch (error) {
|
|
}
|
|
};
|
|
frame.addEventListener('load', function() {
|
|
hookFrameDocument();
|
|
scheduleRelayout();
|
|
}, { passive: true });
|
|
hookFrameDocument();
|
|
});
|
|
}
|
|
installDocumentHooks(document);
|
|
installFrameHooks(document);
|
|
window.addEventListener('resize', function() {
|
|
if (isFixedLayoutDocument()) { return; }
|
|
setVisiblePageIndex(visiblePageIndex);
|
|
reportProgression(null);
|
|
}, { passive: true });
|
|
window.addEventListener('load', scheduleRelayout, { passive: true });
|
|
if (!isFixedLayoutDocument() && document.fonts && document.fonts.ready) {
|
|
document.fonts.ready.then(scheduleRelayout).catch(function() {});
|
|
}
|
|
if (!isFixedLayoutDocument()) {
|
|
Array.prototype.forEach.call(document.querySelectorAll('img, iframe, video'), function(node) {
|
|
node.addEventListener('load', scheduleRelayout, { passive: true });
|
|
node.addEventListener('error', scheduleRelayout, { passive: true });
|
|
});
|
|
}
|
|
window.RDReaderBridge = {
|
|
applyPagination: function(styleText) {
|
|
if (isFixedLayoutDocument()) { return; }
|
|
if (window.RDInjectedCSS) {
|
|
window.RDInjectedCSS.setStyle('ss-reader-pagination', styleText, { includeFrames: false });
|
|
} else {
|
|
var style = document.getElementById('ss-reader-pagination');
|
|
if (!style) {
|
|
style = document.createElement('style');
|
|
style.id = 'ss-reader-pagination';
|
|
document.head.appendChild(style);
|
|
}
|
|
style.textContent = styleText;
|
|
}
|
|
ensurePaginationStructure();
|
|
installFrameHooks(document);
|
|
},
|
|
setPageMetrics: function(pageCount, pageStride) {
|
|
if (isFixedLayoutDocument()) { return; }
|
|
configuredPageCount = Math.max(1, Math.round(pageCount || 1));
|
|
configuredPageStride = Math.max(1, Number(pageStride) || configuredPageStride || 1);
|
|
setVisiblePageIndex(visiblePageIndex);
|
|
scheduleRelayout();
|
|
},
|
|
scrollToPage: function(pageIndex) {
|
|
if (isFixedLayoutDocument()) { return; }
|
|
setVisiblePageIndex(pageIndex);
|
|
reportProgression(null);
|
|
},
|
|
scrollToLocation: function(location, fallbackPageIndex, targetRangeInfo) {
|
|
if (targetRangeInfo) {
|
|
var highlightRange = rangeFromInfo(targetRangeInfo);
|
|
var highlightRects = rectPayloadForRange(highlightRange, 0, 0);
|
|
if (highlightRects.length) {
|
|
var highlightRect = highlightRects[0];
|
|
var highlightAbsoluteLeft = Math.max(0, highlightRect.x + currentPageOffset());
|
|
setVisiblePageIndex(Math.max(0, Math.floor(highlightAbsoluteLeft / effectivePageStride())));
|
|
reportProgression(location && location.fragment ? location.fragment : null);
|
|
return;
|
|
}
|
|
}
|
|
if (location && location.fragment) {
|
|
var resolvedTarget = fragmentTarget(location.fragment);
|
|
if (resolvedTarget) {
|
|
if (isFixedLayoutDocument()) {
|
|
reportProgression(location.fragment);
|
|
return;
|
|
}
|
|
var rect = resolvedTarget.target.getBoundingClientRect();
|
|
var absoluteLeft = Math.max(0, rect.left + resolvedTarget.context.offsetX + currentPageOffset());
|
|
setVisiblePageIndex(Math.max(0, Math.floor(absoluteLeft / effectivePageStride())));
|
|
reportProgression(location.fragment);
|
|
return;
|
|
}
|
|
}
|
|
var pageCount = totalPageCount();
|
|
var progression = location && typeof location.progression === 'number' ? location.progression : 0;
|
|
var derivedPageIndex = progression > 0 && pageCount > 1
|
|
? Math.round(progression * Math.max(pageCount - 1, 0))
|
|
: (fallbackPageIndex || 0);
|
|
this.scrollToPage(derivedPageIndex);
|
|
},
|
|
setHighlights: setHighlights,
|
|
clearHighlights: clearHighlights,
|
|
setSearchPresentation: setSearchPresentation,
|
|
resolveDecorations: resolveDecorations,
|
|
reportProgression: reportProgression,
|
|
selectionPayload: selectionPayload
|
|
};
|
|
})();
|