mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-30 01:27:26 +08:00
1 parent
2984b07c83
commit
7b4eb5ff60
3 files changed
+88
-74
No files matched your search
+31
-29
@@ -676,36 +676,38 @@
|
||||
<form id="printForm">
|
||||
<h2 id="printTitle" class="form-title">打印设置</h2>
|
||||
<div class="print-content">
|
||||
<fieldset id="printSettings" class="print-settings">
|
||||
<div class="form-row"><label for="printPrinter">打印设备</label><div class="print-field"><select id="printPrinter"><option value="browser">系统打印</option><option value="pdf">另存输出</option></select><button id="printProperties" class="small-button" type="button" hidden>设备属性</button></div></div>
|
||||
<div class="form-row" data-print-row="device" hidden><label for="printCopies">打印份数</label><div class="print-field"><input id="printCopies" type="number" min="1" max="999" value="1"><label class="print-check"><input id="printCollation" type="checkbox" checked>逐份打印</label></div></div>
|
||||
<div class="form-row"><label for="printScope">打印范围</label><select id="printScope"><option value="all">全部页面</option><option value="current">当前页面</option><option value="selected">所选页面</option><option value="range">指定页码</option></select></div>
|
||||
<div class="form-row" data-print-row="range" hidden><label for="printRange">指定页码</label><input id="printRange" type="text" placeholder="1-3,5" autocomplete="off" spellcheck="false"></div>
|
||||
<div class="form-row"><label for="printParity">奇偶筛选</label><div class="print-field"><select id="printParity"><option value="all">全部页面</option><option value="odd">奇数页面</option><option value="even">偶数页面</option></select><label class="print-check"><input id="printReverse" type="checkbox">逆序打印</label></div></div>
|
||||
<div class="form-row"><label for="printMode">页面排版</label><select id="printMode"><option value="single">单页打印</option><option value="multiple">多页合印</option><option value="booklet">小册打印</option><option value="poster">海报拼接</option></select></div>
|
||||
<div class="form-row"><label for="printPaper">纸张大小</label><select id="printPaper"><option value="210,297">A4</option><option value="297,420">A3</option><option value="148,210">A5</option><option value="176,250">B5</option><option value="215.9,279.4">Letter</option><option value="215.9,355.6">Legal</option><option value="source">原页尺寸</option><option value="custom">自定尺寸</option></select></div>
|
||||
<div class="form-row" data-print-row="paper" hidden><label for="printWidth">纸张尺寸</label><div class="print-field"><input id="printWidth" type="number" value="210" min="1" max="5000" step="any" title="纸张宽度"><span>×</span><input id="printHeight" type="number" value="297" min="1" max="5000" step="any" title="纸张高度"><span>mm</span></div></div>
|
||||
<div class="form-row"><label for="printOrientation">纸张方向</label><select id="printOrientation"><option value="portrait">纵向纸张</option><option value="landscape">横向纸张</option></select></div>
|
||||
<div class="form-row"><label for="printScaling">页面缩放</label><select id="printScaling"><option value="shrink">缩小大页</option><option value="fit">适合纸张</option><option value="actual">实际大小</option><option value="custom">自定比例</option></select></div>
|
||||
<div class="form-row" data-print-row="scale" hidden><label for="printScale">缩放比例</label><div class="print-field"><input id="printScale" type="number" min="1" max="10000" value="100" step="1"><span>%</span></div></div>
|
||||
<div class="form-row"><span>额外边距</span><div class="print-field print-margins"><input id="printMarginTop" type="number" min="0" value="0" step="0.1" title="上边距"><input id="printMarginRight" type="number" min="0" value="0" step="0.1" title="右边距"><input id="printMarginBottom" type="number" min="0" value="0" step="0.1" title="下边距"><input id="printMarginLeft" type="number" min="0" value="0" step="0.1" title="左边距"><span>mm</span></div></div>
|
||||
<div class="form-row" data-print-row="multiple" hidden><label for="printGrid">每面页数</label><select id="printGrid"><option value="1,2">2 页</option><option value="2,2">4 页</option><option value="2,3">6 页</option><option value="3,3">9 页</option><option value="4,4">16 页</option></select></div>
|
||||
<div class="form-row" data-print-row="multiple" hidden><label for="printPageOrder">排列顺序</label><select id="printPageOrder"><option value="horizontal">横向顺序</option><option value="horizontalReverse">横向逆序</option><option value="vertical">纵向顺序</option><option value="verticalReverse">纵向逆序</option></select></div>
|
||||
<div class="form-row" data-print-row="gap" hidden><label for="printGap">页面间距</label><div class="print-field"><input id="printGap" type="number" min="0" value="4" step="0.1"><span>mm</span></div></div>
|
||||
<div class="form-row" data-print-row="booklet" hidden><label for="printBinding">装订方向</label><select id="printBinding"><option value="left">左侧装订</option><option value="right">右侧装订</option></select></div>
|
||||
<div class="form-row" data-print-row="booklet" hidden><label for="printBookletSheets">每册纸数</label><input id="printBookletSheets" type="number" min="0" max="2500" placeholder="不分册" title="0表示不分册"></div>
|
||||
<div class="form-row" data-print-row="booklet" hidden><label for="printSheetFrom">纸张范围</label><div class="print-field"><input id="printSheetFrom" type="number" min="1" placeholder="起始" title="起始纸张编号"><span>至</span><input id="printSheetTo" type="number" min="1" placeholder="结束" title="结束纸张编号"></div></div>
|
||||
<div class="form-row" data-print-row="poster" hidden><label for="printOverlap">重叠宽度</label><div class="print-field"><input id="printOverlap" type="number" min="0" value="5" step="0.1"><span>mm</span></div></div>
|
||||
<div class="form-row"><label for="printDuplex">双面方式</label><select id="printDuplex"><option value="simplex">单面打印</option><option value="longEdge">自动长边</option><option value="shortEdge">自动短边</option><option value="manualLongEdge">手动长边</option><option value="manualShortEdge">手动短边</option></select></div>
|
||||
<div class="form-row" data-print-row="sides" hidden><label for="printSides">打印纸面</label><select id="printSides"><option value="all">正反两面</option><option value="front">只印正面</option><option value="back">只印背面</option></select></div>
|
||||
<div class="form-row" data-print-row="manual" hidden><span>背面处理</span><div class="print-field"><label class="print-check"><input id="printBackReverse" type="checkbox">倒序送纸</label><label class="print-check" title="背面旋转180°"><input id="printBackRotate" type="checkbox">背面旋转</label></div></div>
|
||||
<div class="form-row"><label for="printContents">打印内容</label><select id="printContents"><option value="documentAndAnnotations">文档注解</option><option value="document">文档表单</option><option value="annotations">仅限注解</option><option value="forms">仅限表单</option></select></div>
|
||||
<div class="print-options"><label><input id="printRotate" type="checkbox" checked>自动旋转</label><label><input id="printGrayscale" type="checkbox">灰度打印</label><label><input id="printBorders" type="checkbox">页面边框</label><label><input id="printCropMarks" type="checkbox">裁切标记</label><label><input id="printRaster" type="checkbox">图像打印</label><select id="printDPI" title="图像精度"><option value="96">96 DPI</option><option value="150">150 DPI</option><option value="300" selected>300 DPI</option><option value="600">600 DPI</option></select></div>
|
||||
<div class="print-options" data-print-row="poster" hidden><label title="仅拼接超出纸面的页面"><input id="printTileOnlyLarge" type="checkbox" checked>仅拼大页</label><label><input id="printLabels" type="checkbox" checked>拼接标签</label></div>
|
||||
</fieldset>
|
||||
<div id="printPreview" class="print-preview-page"></div>
|
||||
<div class="print-settings-panel">
|
||||
<fieldset id="printSettings" class="print-settings">
|
||||
<div class="form-row"><label for="printPrinter">打印设备</label><div class="print-field"><select id="printPrinter"><option value="browser">系统打印</option><option value="pdf">另存输出</option></select><button id="printProperties" class="small-button" type="button" hidden>设备属性</button></div></div>
|
||||
<div class="form-row" data-print-row="device" hidden><label for="printCopies">打印份数</label><div class="print-field"><input id="printCopies" type="number" min="1" max="999" value="1"><label class="print-check"><input id="printCollation" type="checkbox" checked>逐份打印</label></div></div>
|
||||
<div class="form-row"><label for="printScope">打印范围</label><select id="printScope"><option value="all">全部页面</option><option value="current">当前页面</option><option value="selected">所选页面</option><option value="range">指定页码</option></select></div>
|
||||
<div class="form-row" data-print-row="range" hidden><label for="printRange">指定页码</label><input id="printRange" type="text" placeholder="1-3,5" autocomplete="off" spellcheck="false"></div>
|
||||
<div class="form-row"><label for="printParity">奇偶筛选</label><div class="print-field"><select id="printParity"><option value="all">全部页面</option><option value="odd">奇数页面</option><option value="even">偶数页面</option></select><label class="print-check"><input id="printReverse" type="checkbox">逆序打印</label></div></div>
|
||||
<div class="form-row"><label for="printMode">页面排版</label><select id="printMode"><option value="single">单页打印</option><option value="multiple">多页合印</option><option value="booklet">小册打印</option><option value="poster">海报拼接</option></select></div>
|
||||
<div class="form-row"><label for="printPaper">纸张大小</label><select id="printPaper"><option value="210,297">A4</option><option value="297,420">A3</option><option value="148,210">A5</option><option value="176,250">B5</option><option value="215.9,279.4">Letter</option><option value="215.9,355.6">Legal</option><option value="source">原页尺寸</option><option value="custom">自定尺寸</option></select></div>
|
||||
<div class="form-row" data-print-row="paper" hidden><label for="printWidth">纸张尺寸</label><div class="print-field"><input id="printWidth" type="number" value="210" min="1" max="5000" step="any" title="纸张宽度"><span>×</span><input id="printHeight" type="number" value="297" min="1" max="5000" step="any" title="纸张高度"><span>mm</span></div></div>
|
||||
<div class="form-row"><label for="printOrientation">纸张方向</label><select id="printOrientation"><option value="portrait">纵向纸张</option><option value="landscape">横向纸张</option></select></div>
|
||||
<div class="form-row"><label for="printScaling">页面缩放</label><select id="printScaling"><option value="shrink">缩小大页</option><option value="fit">适合纸张</option><option value="actual">实际大小</option><option value="custom">自定比例</option></select></div>
|
||||
<div class="form-row" data-print-row="scale" hidden><label for="printScale">缩放比例</label><div class="print-field"><input id="printScale" type="number" min="1" max="10000" value="100" step="1"><span>%</span></div></div>
|
||||
<div class="form-row"><span>额外边距</span><div class="print-field print-margins"><input id="printMarginTop" type="number" min="0" value="0" step="0.1" title="上边距"><input id="printMarginRight" type="number" min="0" value="0" step="0.1" title="右边距"><input id="printMarginBottom" type="number" min="0" value="0" step="0.1" title="下边距"><input id="printMarginLeft" type="number" min="0" value="0" step="0.1" title="左边距"><span>mm</span></div></div>
|
||||
<div class="form-row" data-print-row="multiple" hidden><label for="printGrid">每面页数</label><select id="printGrid"><option value="1,2">2 页</option><option value="2,2">4 页</option><option value="2,3">6 页</option><option value="3,3">9 页</option><option value="4,4">16 页</option></select></div>
|
||||
<div class="form-row" data-print-row="multiple" hidden><label for="printPageOrder">排列顺序</label><select id="printPageOrder"><option value="horizontal">横向顺序</option><option value="horizontalReverse">横向逆序</option><option value="vertical">纵向顺序</option><option value="verticalReverse">纵向逆序</option></select></div>
|
||||
<div class="form-row" data-print-row="gap" hidden><label for="printGap">页面间距</label><div class="print-field"><input id="printGap" type="number" min="0" value="4" step="0.1"><span>mm</span></div></div>
|
||||
<div class="form-row" data-print-row="booklet" hidden><label for="printBinding">装订方向</label><select id="printBinding"><option value="left">左侧装订</option><option value="right">右侧装订</option></select></div>
|
||||
<div class="form-row" data-print-row="booklet" hidden><label for="printBookletSheets">每册纸数</label><input id="printBookletSheets" type="number" min="0" max="2500" placeholder="不分册" title="0表示不分册"></div>
|
||||
<div class="form-row" data-print-row="booklet" hidden><label for="printSheetFrom">纸张范围</label><div class="print-field"><input id="printSheetFrom" type="number" min="1" placeholder="起始" title="起始纸张编号"><span>至</span><input id="printSheetTo" type="number" min="1" placeholder="结束" title="结束纸张编号"></div></div>
|
||||
<div class="form-row" data-print-row="poster" hidden><label for="printOverlap">重叠宽度</label><div class="print-field"><input id="printOverlap" type="number" min="0" value="5" step="0.1"><span>mm</span></div></div>
|
||||
<div class="form-row"><label for="printDuplex">双面方式</label><select id="printDuplex"><option value="simplex">单面打印</option><option value="longEdge">自动长边</option><option value="shortEdge">自动短边</option><option value="manualLongEdge">手动长边</option><option value="manualShortEdge">手动短边</option></select></div>
|
||||
<div class="form-row" data-print-row="sides" hidden><label for="printSides">打印纸面</label><select id="printSides"><option value="all">正反两面</option><option value="front">只印正面</option><option value="back">只印背面</option></select></div>
|
||||
<div class="form-row" data-print-row="manual" hidden><span>背面处理</span><div class="print-field"><label class="print-check"><input id="printBackReverse" type="checkbox">倒序送纸</label><label class="print-check" title="背面旋转180°"><input id="printBackRotate" type="checkbox">背面旋转</label></div></div>
|
||||
<div class="form-row"><label for="printContents">打印内容</label><select id="printContents"><option value="documentAndAnnotations">文档注解</option><option value="document">文档表单</option><option value="annotations">仅限注解</option><option value="forms">仅限表单</option></select></div>
|
||||
<div class="print-options"><label><input id="printRotate" type="checkbox" checked>自动旋转</label><label><input id="printGrayscale" type="checkbox">灰度打印</label><label><input id="printBorders" type="checkbox">页面边框</label><label><input id="printCropMarks" type="checkbox">裁切标记</label><label><input id="printRaster" type="checkbox">图像打印</label><select id="printDPI" title="图像精度"><option value="96">96 DPI</option><option value="150">150 DPI</option><option value="300" selected>300 DPI</option><option value="600">600 DPI</option></select></div>
|
||||
<div class="print-options" data-print-row="poster" hidden><label title="仅拼接超出纸面的页面"><input id="printTileOnlyLarge" type="checkbox" checked>仅拼大页</label><label><input id="printLabels" type="checkbox" checked>拼接标签</label></div>
|
||||
</fieldset>
|
||||
<div class="form-actions"><button id="printCancel" class="button" type="button">关闭</button><button id="printSubmit" class="button" type="submit" disabled>打印</button></div>
|
||||
</div>
|
||||
<div class="print-preview"><div class="print-preview-stage"><div id="printPreview" class="print-preview-page"></div><div id="printProgress" class="progress-panel print-progress"><div id="printSpinner" class="progress-spinner" hidden></div><div id="printStatus" class="progress-label"></div><div id="printProgressTrack" class="progress-track" hidden><div id="printProgressBar" class="progress-bar"></div></div></div></div><div class="print-preview-tools"><button id="printPrevious" class="icon-button arrow-prev" type="button" title="上一页"></button><label id="printPageControl" class="page-control"><input id="printPreviewNumber" type="number" min="1" value="1" title="预览纸面"><span>/</span><span id="printPageCount">0</span></label><button id="printNext" class="icon-button arrow-next" type="button" title="下一页"></button></div></div>
|
||||
</div>
|
||||
<div class="print-footer"><div id="printStatus" class="form-status"></div><div class="print-preview-tools"><button id="printPrevious" class="small-button" type="button">上页</button><input id="printPreviewNumber" type="number" min="1" value="1" title="预览纸面"><span id="printPageCount">/ 0</span><button id="printNext" class="small-button" type="button">下页</button><select id="printZoom" title="预览缩放"><option value="fit">适合</option><option value="0.5">50%</option><option value="1">100%</option><option value="2">200%</option></select></div><div class="form-actions"><button id="printCancel" class="button" type="button">关闭</button><button id="printSubmit" class="button" type="submit" disabled>打印</button></div></div>
|
||||
</form>
|
||||
</dialog>
|
||||
<dialog id="exportPanel" class="form-dialog">
|
||||
|
||||
+16
-21
@@ -39,8 +39,9 @@
|
||||
}
|
||||
|
||||
.print-settings {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
max-height: 100%;
|
||||
min-height: 0;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow: auto;
|
||||
@@ -58,11 +59,9 @@
|
||||
.print-settings [hidden] { display: none !important; }
|
||||
.print-dialog :is(input, select, button):focus-visible { outline-offset: -2px; }
|
||||
.print-field { display: flex; min-width: 0; align-items: center; gap: 6px; }
|
||||
.print-dialog .print-settings input[type="number"] { min-width: 0; width: 100%; }
|
||||
.print-dialog .print-field > :is(input, select) { flex: 1 1 0; min-width: 0; width: 0; }
|
||||
.print-field > :is(.print-check, button) { flex: 0 0 80px; justify-content: center; }
|
||||
.print-field:has(#printBackReverse) { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
|
||||
.print-field:has(#printBackReverse) .print-check { justify-content: start; }
|
||||
.print-field:has(#printBackReverse) .print-check:first-child { flex: 1; justify-content: start; }
|
||||
.print-field > span { flex: none; color: var(--text-muted); white-space: nowrap; }
|
||||
.print-dialog .print-settings .print-margins input { padding: 0 3px; text-align: center; }
|
||||
.print-check { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; }
|
||||
@@ -70,38 +69,36 @@
|
||||
.print-options label { display: inline-flex; align-items: center; gap: 4px; white-space: nowrap; }
|
||||
.print-options > label:nth-child(3n) { justify-content: center; }
|
||||
.print-check input, .print-options input { margin: 0; accent-color: var(--accent); }
|
||||
.print-footer { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; gap: 14px; margin-top: 12px; }
|
||||
.print-footer > .form-status { min-width: 0; margin: 0; overflow-wrap: anywhere; }
|
||||
.print-dialog .form-actions { grid-template-columns: 80px 80px; margin: 0; }
|
||||
.print-settings-panel, .print-preview { display: flex; min-width: 0; min-height: 0; flex-direction: column; gap: 12px; }
|
||||
.print-dialog .form-actions { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
.print-preview-stage { position: relative; display: flex; flex: 1; min-height: 0; }
|
||||
.print-preview-stage .print-progress { position: absolute; bottom: 12px; width: calc(100% - 24px); max-width: 420px; }
|
||||
.print-progress:has(.progress-label:empty) { display: none; }
|
||||
.print-progress:has(.progress-spinner[hidden]) { grid-template-columns: minmax(0, 1fr); }
|
||||
.print-progress .progress-label { white-space: normal; overflow-wrap: anywhere; }
|
||||
|
||||
.print-preview-page {
|
||||
display: grid;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
justify-items: safe center;
|
||||
align-items: safe center;
|
||||
padding: 12px;
|
||||
overflow: auto;
|
||||
overflow: hidden;
|
||||
background: #e1e6e9;
|
||||
border: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.print-preview-page img { display: block; max-width: none; background: white; box-shadow: var(--shadow-soft); }
|
||||
.print-preview-tools { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 7px; }
|
||||
.print-dialog .print-preview-tools input { width: 52px; text-align: center; }
|
||||
.print-dialog .print-preview-tools select { width: 70px; }
|
||||
.print-preview-tools { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 5px; }
|
||||
#ofdgoPrintDocument { display: none; }
|
||||
|
||||
@media (max-width: 680px) {
|
||||
.print-content { grid-template-columns: minmax(0, 1fr); height: auto; min-height: 0; }
|
||||
.print-settings { max-height: 34dvh; }
|
||||
.print-preview-page { height: 32dvh; min-height: 160px; }
|
||||
.print-footer { grid-template-columns: minmax(0, 1fr); gap: 8px; }
|
||||
.print-footer > .form-status:empty { display: none; }
|
||||
.print-preview-tools { gap: 5px; }
|
||||
.print-dialog .print-preview-tools input { width: 42px; }
|
||||
.print-dialog .form-actions { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
||||
.print-settings { flex: none; max-height: 34dvh; }
|
||||
.print-preview-stage { flex: none; height: 32dvh; min-height: 160px; }
|
||||
.print-preview-tools { justify-content: space-between; }
|
||||
}
|
||||
|
||||
@media print {
|
||||
@@ -1488,8 +1485,6 @@ button:not(:disabled):hover {
|
||||
.info-custom-row input,
|
||||
.gradient-stop-row input[type="number"],
|
||||
.structure-attribute > input,
|
||||
.print-preview-tools input,
|
||||
.print-preview-tools select,
|
||||
.print-options select,
|
||||
.form-row input[type="text"],
|
||||
.form-row input[type="password"],
|
||||
|
||||
+41
-24
@@ -1,7 +1,7 @@
|
||||
export class PrintDialog {
|
||||
constructor(options) {
|
||||
Object.assign(this, options);
|
||||
this.el = Object.fromEntries(["Panel", "Form", "Settings", "Printer", "Properties", "Copies", "Collation", "Duplex", "BackReverse", "BackRotate", "Contents", "Scope", "Range", "Parity", "Reverse", "Mode", "Paper", "Width", "Height", "Orientation", "Scaling", "Scale", "MarginTop", "MarginRight", "MarginBottom", "MarginLeft", "Grid", "PageOrder", "Gap", "Binding", "BookletSheets", "SheetFrom", "SheetTo", "Overlap", "Sides", "Rotate", "Grayscale", "Borders", "CropMarks", "Raster", "DPI", "TileOnlyLarge", "Labels", "Preview", "Previous", "Next", "PreviewNumber", "PageCount", "Zoom", "Status", "Cancel", "Submit"].map(name => [name, document.querySelector(`#print${name}`)]));
|
||||
this.el = Object.fromEntries(["Panel", "Form", "Settings", "Printer", "Properties", "Copies", "Collation", "Duplex", "BackReverse", "BackRotate", "Contents", "Scope", "Range", "Parity", "Reverse", "Mode", "Paper", "Width", "Height", "Orientation", "Scaling", "Scale", "MarginTop", "MarginRight", "MarginBottom", "MarginLeft", "Grid", "PageOrder", "Gap", "Binding", "BookletSheets", "SheetFrom", "SheetTo", "Overlap", "Sides", "Rotate", "Grayscale", "Borders", "CropMarks", "Raster", "DPI", "TileOnlyLarge", "Labels", "Preview", "Previous", "Next", "PreviewNumber", "PageControl", "PageCount", "Status", "Spinner", "ProgressTrack", "ProgressBar", "Cancel", "Submit"].map(name => [name, document.querySelector(`#print${name}`)]));
|
||||
this.printerOptions = this.el.Printer.innerHTML;
|
||||
this.paperOptions = this.el.Paper.innerHTML;
|
||||
this.queue = Promise.resolve();
|
||||
@@ -17,7 +17,11 @@ export class PrintDialog {
|
||||
this.el.Previous.addEventListener("click", () => this.preview(this.side - 1));
|
||||
this.el.Next.addEventListener("click", () => this.preview(this.side + 1));
|
||||
this.el.PreviewNumber.addEventListener("change", () => this.preview(Number(this.el.PreviewNumber.value) - 1));
|
||||
this.el.Zoom.addEventListener("change", () => this.resize());
|
||||
this.el.PreviewNumber.addEventListener("keydown", event => {
|
||||
if (event.key !== "Enter") return;
|
||||
event.preventDefault();
|
||||
if (!event.repeat) this.el.PreviewNumber.dispatchEvent(new Event("change"));
|
||||
});
|
||||
new ResizeObserver(([entry]) => { this.previewSize = entry.contentRect; this.resize(); }).observe(this.el.Preview);
|
||||
window.addEventListener("afterprint", () => { if (this.waiting === "browser") this.finishPrint(); });
|
||||
window.addEventListener("beforeprint", () => {
|
||||
@@ -53,7 +57,7 @@ export class PrintDialog {
|
||||
this.el.Scope.value = context.selection.length ? "selected" : "all";
|
||||
this.el.Scope.querySelector('option[value="selected"]').disabled = !context.selection.length;
|
||||
this.el.Contents.value = context.annotations ? "documentAndAnnotations" : "document";
|
||||
this.el.Status.textContent = "";
|
||||
this.status();
|
||||
this.el.Preview.replaceChildren();
|
||||
this.show(this.el.Panel);
|
||||
this.loadDevices();
|
||||
@@ -72,6 +76,7 @@ export class PrintDialog {
|
||||
if (browser.disabled) this.el.Printer.value = "pdf";
|
||||
try {
|
||||
if (this.nativeHost) {
|
||||
this.status("正在读取设备", true);
|
||||
const capabilities = await this.nativeHost.call("print.capabilities", {});
|
||||
if (!this.current(sequence)) return;
|
||||
this.capabilities = capabilities;
|
||||
@@ -82,7 +87,7 @@ export class PrintDialog {
|
||||
const printer = printers.find(printer => printer.default) || printers[0];
|
||||
this.el.Printer.value = printer ? `device:${printer.name}` : "pdf";
|
||||
}
|
||||
} catch (error) { if (this.current(sequence)) this.el.Status.textContent = error.message; }
|
||||
} catch (error) { if (this.current(sequence)) this.status(error.message); }
|
||||
finally {
|
||||
if (this.current(sequence)) { this.loading = false; await this.choosePrinter(); }
|
||||
}
|
||||
@@ -93,6 +98,7 @@ export class PrintDialog {
|
||||
const paper = this.el.Paper.value;
|
||||
this.layout = this.job = this.profile = null;
|
||||
this.loading = true;
|
||||
this.status();
|
||||
this.controls();
|
||||
this.el.Paper.innerHTML = this.paperOptions;
|
||||
if (!this.isDevice()) {
|
||||
@@ -109,6 +115,7 @@ export class PrintDialog {
|
||||
this.el.Properties.hidden = true;
|
||||
try {
|
||||
if (this.isDevice()) {
|
||||
this.status("正在读取纸张", true);
|
||||
const profile = await this.nativeHost.call("print.query", {printer:this.el.Printer.value.slice(7), copies:1, duplex:"simplex"});
|
||||
if (!this.current(sequence)) return;
|
||||
this.profile = profile;
|
||||
@@ -124,7 +131,7 @@ export class PrintDialog {
|
||||
this.el.Grayscale.disabled = !profile.color;
|
||||
this.el.Properties.hidden = !profile.properties;
|
||||
} else this.el.Grayscale.disabled = false;
|
||||
} catch (error) { if (this.current(sequence)) { this.el.Status.textContent = error.message; return; } }
|
||||
} catch (error) { if (this.current(sequence)) { this.status(error.message); return; } }
|
||||
finally { if (this.current(sequence)) { this.loading = false; this.controls(); } }
|
||||
if (this.current(sequence)) this.schedule();
|
||||
}
|
||||
@@ -133,9 +140,10 @@ export class PrintDialog {
|
||||
if (!this.isDevice() || this.running || this.loading) return;
|
||||
const sequence = this.sequence;
|
||||
this.loading = true;
|
||||
this.status("正在打开属性", true);
|
||||
this.controls();
|
||||
try { await this.nativeHost.call("print.properties", {printer:this.el.Printer.value.slice(7)}); }
|
||||
catch (error) { if (this.current(sequence)) this.el.Status.textContent = error.message; }
|
||||
catch (error) { if (this.current(sequence)) this.status(error.message); }
|
||||
finally { if (this.current(sequence)) { this.loading = false; await this.choosePrinter(); } }
|
||||
}
|
||||
|
||||
@@ -215,6 +223,7 @@ export class PrintDialog {
|
||||
const sequence = ++this.sequence;
|
||||
this.layout = null;
|
||||
this.job = null;
|
||||
this.status();
|
||||
this.controls();
|
||||
clearTimeout(this.timer);
|
||||
this.timer = setTimeout(() => {
|
||||
@@ -227,25 +236,26 @@ export class PrintDialog {
|
||||
const context = this.context;
|
||||
try {
|
||||
if (!this.el.Form.reportValidity()) return;
|
||||
this.status("正在准备预览", true);
|
||||
const deviceOptions = this.isDevice() ? this.deviceOptions() : null;
|
||||
const profile = deviceOptions ? await this.nativeHost.call("print.query", deviceOptions) : null;
|
||||
if (!this.current(sequence)) return;
|
||||
this.profile = profile;
|
||||
const options = this.options(profile);
|
||||
this.el.Status.textContent = "准备打印…";
|
||||
const layout = await context.call(this.prepared ? "ofdgoLayoutPrint" : "ofdgoPreparePrint", options);
|
||||
if (!this.current(sequence)) return;
|
||||
this.prepared = true;
|
||||
this.layout = layout;
|
||||
if (this.isDevice()) this.el.Copies.max = Math.min(999, this.profile.maxCopies || 999, layout.copiesLimit > 0 ? layout.copiesLimit : 999);
|
||||
this.job = {deviceOptions, fingerprint:profile?.fingerprint, manual:this.manual(), sides:options.sides, backContent:layout.backContent};
|
||||
this.el.Status.textContent = "";
|
||||
if (layout.sides.some(side => side.placements.some(placement => placement.clipped))) this.el.Status.textContent = "内容超出可打印区域";
|
||||
if (this.manual() && options.sides === "back" && !layout.backContent) this.el.Status.textContent = "背面为空白";
|
||||
this.remember();
|
||||
await this.preview(Math.min(this.side, layout.sides.length - 1));
|
||||
if (!this.current(sequence) || this.layout !== layout) return;
|
||||
this.status();
|
||||
if (layout.sides.some(side => side.placements.some(placement => placement.clipped))) this.status("内容超出可打印区域");
|
||||
if (this.manual() && options.sides === "back" && !layout.backContent) this.status("背面为空白");
|
||||
} catch (error) {
|
||||
if (this.current(sequence)) this.el.Status.textContent = error.code === "printDenied" ? "文档禁止打印" : error.message;
|
||||
if (this.current(sequence)) this.status(error.code === "printDenied" ? "文档禁止打印" : error.message);
|
||||
} finally {
|
||||
if (this.current(sequence)) this.controls();
|
||||
}
|
||||
@@ -275,19 +285,24 @@ export class PrintDialog {
|
||||
this.previewURL = url;
|
||||
this.el.Preview.replaceChildren(img);
|
||||
this.resize();
|
||||
} catch (error) { if (this.current(sequence) && preview === this.previewSequence) { this.el.Status.textContent = error.message; this.layout = null; this.controls(); } }
|
||||
} catch (error) { if (this.current(sequence) && preview === this.previewSequence) { this.status(error.message); this.layout = null; this.controls(); } }
|
||||
}
|
||||
|
||||
resize() {
|
||||
const fit = this.el.Zoom.value === "fit";
|
||||
this.el.Preview.style.overflow = fit ? "hidden" : "auto";
|
||||
const img = this.el.Preview.querySelector("img"), side = this.layout?.sides[this.side];
|
||||
if (!img || !side || !this.previewSize) return;
|
||||
const factor = fit ? Math.min(this.previewSize.width / side.width, this.previewSize.height / side.height) : Number(this.el.Zoom.value) * 96 / 25.4;
|
||||
const factor = Math.min(this.previewSize.width / side.width, this.previewSize.height / side.height);
|
||||
img.style.width = `${Math.max(1, side.width * factor)}px`;
|
||||
img.style.height = `${Math.max(1, side.height * factor)}px`;
|
||||
}
|
||||
|
||||
status(text = "", busy = false, completed = 0, total = 0) {
|
||||
this.el.Status.textContent = total ? `${text} · ${completed} / ${total}` : text;
|
||||
this.el.Spinner.hidden = !busy;
|
||||
this.el.ProgressTrack.hidden = !busy || !total;
|
||||
this.el.ProgressBar.style.width = `${total ? completed / total * 100 : 0}%`;
|
||||
}
|
||||
|
||||
controls() {
|
||||
const count = this.layout?.sides.length || 0, busy = !!this.running || !!this.loading;
|
||||
this.el.Settings.disabled = busy;
|
||||
@@ -298,7 +313,8 @@ export class PrintDialog {
|
||||
this.el.PreviewNumber.disabled = busy || !count;
|
||||
this.el.PreviewNumber.max = count || 1;
|
||||
this.el.PreviewNumber.value = count ? this.side + 1 : 1;
|
||||
this.el.PageCount.textContent = `/ ${count}`;
|
||||
this.el.PageCount.textContent = String(count);
|
||||
this.el.PageControl.style.setProperty("--page-width", `${String(count || 1).length + 0.5}ch`);
|
||||
this.el.Cancel.textContent = busy && !this.waiting ? "取消" : "关闭";
|
||||
this.el.Cancel.disabled = !!this.waiting;
|
||||
}
|
||||
@@ -328,9 +344,9 @@ export class PrintDialog {
|
||||
this.root.replaceChildren();
|
||||
const style = document.createElement("style");
|
||||
this.root.append(style);
|
||||
this.status("正在准备纸面", true, 0, this.layout.sides.length);
|
||||
for (let i = 0; i < this.layout.sides.length; i++) {
|
||||
if (!this.current(sequence)) throw new DOMException("打印已取消", "AbortError");
|
||||
this.el.Status.textContent = `准备纸面 ${i + 1}/${this.layout.sides.length}`;
|
||||
const {svg} = await context.call("ofdgoPrintSide", i);
|
||||
if (!this.current(sequence)) throw new DOMException("打印已取消", "AbortError");
|
||||
const url = URL.createObjectURL(new Blob([svg], {type:"image/svg+xml"}));
|
||||
@@ -342,6 +358,7 @@ export class PrintDialog {
|
||||
style.textContent += `@page ofdgoPrint${i}{size:${side.width}mm ${side.height}mm;margin:0}`;
|
||||
this.root.append(section);
|
||||
await img.decode();
|
||||
if (this.current(sequence)) this.status("正在准备纸面", true, i + 1, this.layout.sides.length);
|
||||
}
|
||||
await document.fonts.ready;
|
||||
if (!this.current(sequence)) throw new DOMException("打印已取消", "AbortError");
|
||||
@@ -349,7 +366,7 @@ export class PrintDialog {
|
||||
document.title = context.name;
|
||||
this.waiting = this.nativeHost ? "native" : "browser";
|
||||
this.controls();
|
||||
this.el.Status.textContent = job.deviceOptions ? "提交打印…" : "打开打印…";
|
||||
this.status(job.deviceOptions ? "正在提交打印" : "正在打开打印", true);
|
||||
if (job.deviceOptions) {
|
||||
const result = await this.nativeHost.call("print", {...job.deviceOptions, fingerprint:job.fingerprint});
|
||||
if (this.current(sequence)) {
|
||||
@@ -357,7 +374,7 @@ export class PrintDialog {
|
||||
if (!result?.submitted) throw new Error("打印作业未被接受");
|
||||
if (job.manual && job.sides === "front") {
|
||||
if (job.backContent) { this.el.Sides.value = "back"; this.schedule(); }
|
||||
else this.el.Status.textContent = "背面为空白";
|
||||
else this.status("背面为空白");
|
||||
}
|
||||
}
|
||||
} else if (this.nativeHost) {
|
||||
@@ -372,7 +389,7 @@ export class PrintDialog {
|
||||
} catch (error) {
|
||||
if (this.current(sequence)) {
|
||||
this.finishPrint();
|
||||
this.el.Status.textContent = error.name === "AbortError" ? "打印已取消" : error.message;
|
||||
this.status(error.name === "AbortError" ? "打印已取消" : error.message);
|
||||
}
|
||||
} finally {
|
||||
if (this.current(sequence)) {
|
||||
@@ -387,7 +404,7 @@ export class PrintDialog {
|
||||
this.root?.replaceChildren();
|
||||
for (const url of this.urls) URL.revokeObjectURL(url);
|
||||
this.urls = [];
|
||||
this.el.Status.textContent = "";
|
||||
this.status();
|
||||
this.waiting = this.running = false;
|
||||
this.controls();
|
||||
}
|
||||
@@ -397,14 +414,14 @@ export class PrintDialog {
|
||||
const sequence = this.sequence, context = this.context;
|
||||
this.running = true;
|
||||
this.controls();
|
||||
this.el.Status.textContent = "生成文件…";
|
||||
this.status("正在生成文件", true);
|
||||
try {
|
||||
const result = await context.call("ofdgoPrintPDF");
|
||||
if (this.current(sequence)) {
|
||||
await this.download(result.bytes, "application/pdf", `${context.name.replace(/\.[^.]+$/, "")}-打印.pdf`);
|
||||
if (this.current(sequence)) this.el.Status.textContent = "";
|
||||
if (this.current(sequence)) this.status();
|
||||
}
|
||||
} catch (error) { if (this.current(sequence)) this.el.Status.textContent = error.message; }
|
||||
} catch (error) { if (this.current(sequence)) this.status(error.message); }
|
||||
finally { if (this.current(sequence)) { this.running = false; this.controls(); } }
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user