diff --git a/public/static/js/phone-image.js b/public/static/js/phone-image.js
index e0cd02f..a894ba7 100644
--- a/public/static/js/phone-image.js
+++ b/public/static/js/phone-image.js
@@ -58,6 +58,30 @@ var PhoneImageEngine = (function () {
if (userConfig) {
$.extend(config, userConfig);
}
+
+ // 内容流事件委托(只绑定一次)
+ $(document).off('click.phoneImage', '.break-inserter-btn');
+ $(document).off('click.phoneImage', '.remove-break-btn');
+ $(document).off('click.phoneImage', '.page-alignment-toggle');
+
+ $(document).on('click', '.break-inserter-btn', function () {
+ var afterIndex = parseInt($(this).parent().data('after-index'), 10);
+ insertPageBreak(afterIndex);
+ });
+
+ $(document).on('click', '.remove-break-btn', function () {
+ var index = parseInt($(this).data('index'), 10);
+ removePageBreak(index);
+ });
+
+ $(document).on('click', '.page-alignment-toggle', function () {
+ var pageNum = parseInt($(this).data('page-num'), 10);
+ var currentAlign = (config.pageAlignments && config.pageAlignments[pageNum]) || 'top';
+ var newAlign = currentAlign === 'top' ? 'center' : 'top';
+
+ setPageAlignment(pageNum, newAlign);
+ render();
+ });
}
/**
@@ -99,6 +123,12 @@ var PhoneImageEngine = (function () {
// 渲染到DOM
renderToDOM(sizeConfig);
+ // 渲染内容流(中间栏)
+ renderContentFlow(blocks);
+
+ // 渲染逐页对齐指示器
+ renderAlignmentToggles();
+
return pages;
}
@@ -588,6 +618,122 @@ var PhoneImageEngine = (function () {
}
}
+ /**
+ * 为每页渲染逐页对齐切换指示器
+ */
+ function renderAlignmentToggles() {
+ var $pages = $('#paginated-preview .phone-image-page');
+ $pages.each(function (index) {
+ var $page = $(this);
+
+ // 只给内容页添加(跳过封面页和总结页)
+ if (!$page.hasClass('page-body')) return;
+
+ // 通过 pages 数组获取真正的 pageNum
+ var pageNum = index;
+ if (pages[index] && pages[index].pageNum) {
+ pageNum = pages[index].pageNum;
+ }
+
+ // 移除旧的 toggle
+ $page.find('.page-alignment-toggle').remove();
+
+ // 当前对齐状态
+ var currentAlign = (config.pageAlignments && config.pageAlignments[pageNum]) || 'top';
+ var isActiveCenter = currentAlign === 'center';
+
+ var $toggle = $('');
+
+ $page.append($toggle);
+ });
+ }
+
+ /**
+ * 渲染内容流到 #content-flow 容器
+ * @param {Array} blocks - parseHtmlToBlocks 返回的块数组
+ */
+ function renderContentFlow(blocks) {
+ var $flow = $('#content-flow');
+ if (!$flow.length) return;
+
+ $flow.empty();
+
+ for (var i = 0; i < blocks.length; i++) {
+ var block = blocks[i];
+
+ // 分页标记
+ if (block.type === 'page-break') {
+ var $marker = $('
' +
+ '-- 分页标记 --' +
+ '' +
+ '
');
+ $flow.append($marker);
+ continue;
+ }
+
+ // 内容块
+ var $block = $('' + block.html + '
');
+ $flow.append($block);
+
+ // 块与块之间的分页插入区域(不在最后一个块之后添加)
+ if (i < blocks.length - 1) {
+ var $inserter = $('' +
+ '' +
+ '
');
+ $flow.append($inserter);
+ }
+ }
+ }
+
+ /**
+ * 在指定位置插入分页标记
+ * 修改 postData.content_html,在对应位置插入
+ * @param {number} blockIndex - 在哪个块之后插入 (对应 break-inserter 的 data-after-index)
+ */
+ function insertPageBreak(blockIndex) {
+ var cleanHtml = preprocessContent(postData.content_html);
+ var $temp = $('').html(cleanHtml);
+ var children = $temp.children();
+
+ // 在 blockIndex 位置的元素之后插入
+ if (blockIndex >= 0 && blockIndex < children.length) {
+ $(children[blockIndex]).after('
');
+ } else {
+ $temp.append('
');
+ }
+
+ postData.content_html = $temp.html();
+
+ // 重新渲染
+ render();
+ }
+
+ /**
+ * 删除指定位置的分页标记
+ * @param {number} blockIndex - 分页标记的 data-index
+ */
+ function removePageBreak(blockIndex) {
+ // 统计这是第几个 page-break
+ var cleanHtml = preprocessContent(postData.content_html);
+ var $temp = $('
').html(cleanHtml);
+ var hrElements = $temp.find('hr');
+
+ // 在 blocks 数组中找到这个 page-break 是第几个
+ var breakOrder = 0;
+ var currentBlocks = parseHtmlToBlocks(cleanHtml);
+ for (var i = 0; i < currentBlocks.length && i < blockIndex; i++) {
+ if (currentBlocks[i].type === 'page-break') breakOrder++;
+ }
+
+ if (breakOrder < hrElements.length) {
+ $(hrElements[breakOrder]).remove();
+ postData.content_html = $temp.html();
+ render();
+ }
+ }
+
// ===== 图片生成 =====
/**
@@ -723,6 +869,54 @@ var PhoneImageEngine = (function () {
config.pageAlignments[pageNum] = align;
}
+ /**
+ * 导出内容流为长图
+ */
+ function exportLongImage() {
+ var deferred = $.Deferred();
+ var $flow = $('#content-flow');
+ if (!$flow.length) {
+ deferred.reject('内容流容器不存在');
+ return deferred.promise();
+ }
+
+ // 临时隐藏交互元素
+ $flow.find('.break-inserter').hide();
+ $flow.find('.page-break-marker').hide();
+
+ // 获取内容流的实际高度
+ var flowWidth = $flow.outerWidth();
+ var flowHeight = $flow[0].scrollHeight;
+
+ html2canvas($flow[0], {
+ scale: 2,
+ useCORS: true,
+ backgroundColor: '#ffffff',
+ width: flowWidth,
+ height: flowHeight,
+ logging: false
+ }).then(function (canvas) {
+ // 恢复交互元素
+ $flow.find('.break-inserter').show();
+ $flow.find('.page-break-marker').show();
+
+ // 触发下载
+ var link = document.createElement('a');
+ link.download = 'phone-image-long-' + Date.now() + '.png';
+ link.href = canvas.toDataURL('image/png');
+ link.click();
+
+ deferred.resolve(canvas);
+ }).catch(function (err) {
+ // 恢复交互元素
+ $flow.find('.break-inserter').show();
+ $flow.find('.page-break-marker').show();
+ deferred.reject('长图导出失败: ' + err);
+ });
+
+ return deferred.promise();
+ }
+
// ===== 工具方法 =====
/**
@@ -759,6 +953,11 @@ var PhoneImageEngine = (function () {
switchSize: switchSize,
getConfig: getConfig,
getPages: getPages,
- setPageAlignment: setPageAlignment
+ setPageAlignment: setPageAlignment,
+ renderContentFlow: renderContentFlow,
+ insertPageBreak: insertPageBreak,
+ removePageBreak: removePageBreak,
+ renderAlignmentToggles: renderAlignmentToggles,
+ exportLongImage: exportLongImage
};
})();