diff --git a/.github/workflows/test-pages.yml b/.github/workflows/test-pages.yml index 3914f6e..8142169 100644 --- a/.github/workflows/test-pages.yml +++ b/.github/workflows/test-pages.yml @@ -20,7 +20,7 @@ permissions: # Allow one concurrent deployment concurrency: - group: preview-${{ github.ref }} + group: 'pages' cancel-in-progress: true jobs: diff --git a/.gitignore b/.gitignore index e80742c..29db87f 100644 --- a/.gitignore +++ b/.gitignore @@ -110,6 +110,3 @@ docs/*.aux # Mac's Finder's DS_Store files **/.DS_Store - -# Firefox debug storage -tmp diff --git a/index.html b/index.html index b059e65..d9eead6 100644 --- a/index.html +++ b/index.html @@ -25,75 +25,57 @@

Bookbinder JS

current version: %PACKAGE_VERSION%
+
+

Settings

+ + + The page is able to save and load your current settings via the site URL. Clicking this button will reset those to the default settings. + +

File Info

+ Number of Pages: - While some PDF viewers display the first two pages as a spread, be aware the first page, which is odd, will be on the right when printed. The first printed spread are pages 2 & 3 of your PDF document. Evens always on the left, odds always on the right. - - - + While some PDF viewers may display the first two pages as a spread, be aware that the first page, which is odd, will be on the right when printed. The first printed spread are pages 2 & 3 of your PDF document. Evens always on the left, odds always on the right.

Source Manipulation

- - -
-
- -

-
- For books that read like a standard novel
- no rotation of pages applied -

-
- - - - -
+ + + +
Details
+
+ + +
Details
+
+ + + +
Details
+
+ + +
+ Details + For books with the bound edge at the bottom of the page -- rotate all odd pages 90° clockwise, all even pages 90° anti-clockwise +
+ +
+
+ + +
+ Details + For books with the bound edge at the top of the page -- rotate all odd pages 90° anti-clockwise, all even pages 90° clockwise
+ +
+
draw this: ",{ - start: { - x: (sigDetails.isSigStart) ? position.spineMarkTop[0] - w/2: position.spineMarkBottom[0] - w/2, - y: ((sigDetails.isSigStart) ? position.spineMarkTop[1] : position.spineMarkBottom[1] ) - }, - end: { - x: (sigDetails.isSigStart) ? position.spineMarkTop[0] + w/2: position.spineMarkBottom[0]+ w/2, - y: ((sigDetails.isSigStart) ? position.spineMarkTop[1] : position.spineMarkBottom[1] ) - }, - thickness: 0.5, - color: rgb(0,0,0), - opacity: 1, - }) - curPage.drawLine({ - start: { - x: (sigDetails.isSigStart) ? position.spineMarkTop[0] - w/2: position.spineMarkBottom[0] - w/2, - y: ((sigDetails.isSigStart) ? position.spineMarkTop[1] : position.spineMarkBottom[1] ) - }, - end: { - x: (sigDetails.isSigStart) ? position.spineMarkTop[0] + w/2: position.spineMarkBottom[0]+ w/2, - y: ((sigDetails.isSigStart) ? position.spineMarkTop[1] : position.spineMarkBottom[1] ) - }, - thickness: 0.5, - color: rgb(0,0,0), - opacity: 1, - }) - } else { - curPage.drawLine({ - start: { - x: (sigDetails.isSigStart) ? position.spineMarkTop[0] : position.spineMarkBottom[0], - y: ((sigDetails.isSigStart) ? position.spineMarkTop[1] - w/2: position.spineMarkBottom[1] ) - w/2 - }, - end: { - x: (sigDetails.isSigStart) ? position.spineMarkTop[0] : position.spineMarkBottom[0], - y: ((sigDetails.isSigStart) ? position.spineMarkTop[1] + w/2: position.spineMarkBottom[1] ) + w/2 - }, - thickness: 0.25, - color: rgb(0,0,0), - opacity: 1, - }) - } - } - draw_cropmarks(currPage, side2flag) { switch(this.per_sheet){ case 32: @@ -800,37 +734,25 @@ export class Book { let isLeftPage = j % 2 == 0; //page on 'left' side of open book let x = (j * cellWidth) + ((isLeftPage) ? xForeEdgeShift : xBindingShift); let y = (i * cellHeight) + yBottomShift; - let spineMarkTop = [(j * cellWidth), ((i + 1) * cellHeight) - yTopShift] - let spineMarkBottom = [((j+1) * cellWidth), (i * cellHeight) + yBottomShift] if (col == -180) { // upside-down page isLeftPage = j % 2 == 1; //page on 'left' (right side on screen) y = (i + 1) * cellHeight - yBottomShift; x = (j + 1) * cellWidth - ((isLeftPage) ? xForeEdgeShift : xBindingShift); - spineMarkTop = [(j + 1) * cellWidth, (i + 1) * cellHeight]; - spineMarkBottom = [(j + 1) * cellWidth, i * cellHeight]; } else if (col == 90) { // 'top' of page is on left, right side of screen isLeftPage = i % 2 == 0; // page is on 'left' (top side of screen) x = (1 + j) * cellHeight - yBottomShift; y = i * cellWidth + ((isLeftPage) ? xBindingShift : xForeEdgeShift); - spineMarkTop = [(1 + j) * cellHeight, i * cellWidth]; - spineMarkBottom = [j * cellHeight, i * cellWidth]; } else if (col == -90) { // 'top' of page is on the right, left sight of screen isLeftPage = i % 2 == 1; // page is on 'left' (bottom side of screen) x = j * cellHeight + yBottomShift; y = (1+i) * cellWidth - ((isLeftPage) ? xForeEdgeShift : xBindingShift); - spineMarkTop = [(j+1) * cellHeight - yTopShift, (isLeftPage ? i : i+1) * cellWidth]; - spineMarkBottom = [j * cellHeight + yBottomShift, (isLeftPage ? i : i+1) * cellWidth]; } console.log(">> (", i, ",",j,")[",col,"] : [",x,", ",y,"] :: [xForeEdgeShift: ",xForeEdgeShift,"][xBindingShift: ",xBindingShift,"]"); - positions.push({rotation: col, sx: l.pdfScale[0], sy: l.pdfScale[1], x: x, y: y, - spineMarkTop: spineMarkTop, - spineMarkBottom: spineMarkBottom, - isLeftPage: isLeftPage - }); + positions.push({rotation: col, sx: l.pdfScale[0], sy: l.pdfScale[1], x: x, y: y}); }); }); console.log("And in the end of it all, (calculatelayout) we get: ",positions); @@ -841,7 +763,7 @@ export class Book { * PDF builder base function for Classic (non-Wacky) layouts. Called by [createoutputfiles] * * @param config - object w/ the following parameters: - * - pageIndexDetails : a nested list of objects. Each object: {info: page # or 'b', isSigStart: boolean, isSigEnd: boolean} ( [0] for duplex & front, [1] for backs -- value is null if no aggregate printing enabled). Ex: [[{info: 3, isSigStart: true, isSigend: false},{info: 4, isSigStart: false, isSigend: true}]] + * - pageIndexes : a nested list of original source document page numbers ordered for layout. ( [0] for duplex & front, [1] for backs -- value is null if no aggregate printing enabled). Ex: [[4, 3, 2, 5, 6, 1, 0, 7]] * - aggregatePdfs : list of destination PDF(s_ for aggregated content ( [0] for duplex & front, [1] for backs -- value is null if no aggregate printing enabled) * - embeddedPages : list of lists of embedded pages from source document ( [0] for duplex & front, [1] for backs -- value is null if no aggregate printing enabled) * - id : string dentifier for signature file name (null if no signature files to be generated) @@ -851,7 +773,7 @@ export class Book { async createsignatures(config) { const printAggregate = config.aggregatePdfs != null; const printSignatures = config.id != null; - const pages = config.pageIndexDetails; + const pages = config.pageIndexes; // duplex printers print both sides of the sheet, if (config.isDuplex) { let outduplex = (printSignatures) ? config.id + 'duplex' + '.pdf' : null; diff --git a/src/book.test.js b/src/book.test.js index d4aa67c..c4ba718 100644 --- a/src/book.test.js +++ b/src/book.test.js @@ -35,7 +35,6 @@ describe("Book model", () => { }, per_sheet: 4, cropmarks: false, - pdfEdgeMarks: false, cutmarks: false, fore_edge_padding_pt: 0, pack_pages: true, diff --git a/src/main.js b/src/main.js index b1d1217..59662a2 100644 --- a/src/main.js +++ b/src/main.js @@ -20,8 +20,6 @@ window.addEventListener('DOMContentLoaded', () => { const bookbinderForm = document.getElementById('bookbinder'); const fileInput = document.getElementById('input_file'); const inputs = document.querySelectorAll('input, select'); - const sourceRotation = document.getElementById('source_rotation'); - const sourceRotationExamples = Array.from(document.getElementsByClassName('source_rotation_example')); // spin up a book to pass to listeners const book = new Book(configuration); @@ -47,10 +45,4 @@ window.addEventListener('DOMContentLoaded', () => { console.log('Resetting settings...'); handleResetSettingsClick(book); }); - sourceRotation.addEventListener('change', (e) => { - const selectedValue = e.target.value + '_example'; - sourceRotationExamples.forEach((example) => { - example.style.display = (example.id === selectedValue ? 'block' : 'none'); - }); - }); }); diff --git a/src/models/configuration.js b/src/models/configuration.js index d96465f..f4f4cfc 100644 --- a/src/models/configuration.js +++ b/src/models/configuration.js @@ -65,7 +65,6 @@ export const schema = z.object({ pageLayout, cropMarks: urlSafe(coercedBoolean).default(false), cutMarks: urlSafe(coercedBoolean).default(false), - pdfEdgeMarks: urlSafe(coercedBoolean).default(false), pageScaling, pagePositioning, mainForeEdgePaddingPt: urlSafe(z.coerce.number()).default(0), diff --git a/src/perfectbound.js b/src/perfectbound.js index 89f6a01..c8e8261 100644 --- a/src/perfectbound.js +++ b/src/perfectbound.js @@ -23,7 +23,7 @@ export class PerfectBound { const front_config = front; const back_config = duplexrotate ? rotate : back; - this.pagelistdetails = duplex ? [[]] : [[], []]; + this.pagelist = duplex ? [[]] : [[], []]; // Pad the page list with blanks if necessary const totalpages = this.sheets * per_sheet; @@ -38,22 +38,14 @@ export class PerfectBound { front_config.forEach((pnum) => { let page = block[pnum - 1]; //page layouts are 1-indexed, not 0-index - this.pagelistdetails[0].push({ - info: page, - isSigStart: true, - isSigEnd: true - }); + this.pagelist[0].push(page); }); const backlist = this.duplex ? 0 : 1; back_config.forEach((pnum) => { let page = block[pnum - 1]; - this.pagelistdetails[backlist].push({ - info: page, - isSigStart: true, - isSigEnd: true - }); + this.pagelist[backlist].push(page); }); } diff --git a/src/perfectbound.test.js b/src/perfectbound.test.js index ee0bc35..dd3184a 100644 --- a/src/perfectbound.test.js +++ b/src/perfectbound.test.js @@ -8,7 +8,6 @@ import { PerfectBound } from './perfectbound'; const testPages = []; const testPagesEven = Array.from({length: 32}, (x, i) => i + 1); -const generatePageInfo = (page) => {return {info: page, isSigEnd: true, isSigStart: true}}; describe('PerfectBound model', () => { it('returns config for a perfectbound booklet based on params (default)', () => { @@ -19,7 +18,7 @@ describe('PerfectBound model', () => { per_sheet: 4, duplexrotate: true, sigconfig: ['N/A'], - pagelistdetails: [[]], + pagelist: [[]], }; const actual = new PerfectBound(testPages, testDuplex, 4, true); expect(actual).toEqual(expected); @@ -33,7 +32,7 @@ describe('PerfectBound model', () => { sheets: 0, per_sheet: 4, sigconfig: ['N/A'], - pagelistdetails: [[], []], + pagelist: [[], []], }; const actual = new PerfectBound(testPages, testDuplex, 4, false); expect(actual).toEqual(expected); @@ -47,7 +46,7 @@ describe('PerfectBound model', () => { sheets: 8, per_sheet: 4, sigconfig: ['N/A'], - pagelistdetails: [[3,2,7,6,11,10,15,14,19,18,23,22,27,26,31,30].map(generatePageInfo), [1,4,5,8,9,12,13,16,17,20,21,24,25,28,29,32].map(generatePageInfo)], + pagelist: [[3,2,7,6,11,10,15,14,19,18,23,22,27,26,31,30], [1,4,5,8,9,12,13,16,17,20,21,24,25,28,29,32]], }; const actual = new PerfectBound(testPagesEven, testDuplex, 4, false); expect(actual).toEqual(expected); @@ -61,7 +60,7 @@ describe('PerfectBound model', () => { sheets: 4, per_sheet: 8, sigconfig: ['N/A'], - pagelistdetails: [[4,1,7,6,12,9,15,14,20,17,23,22,28,25,31,30].map(generatePageInfo), [8,5,3,2,16,13,11,10,24,21,19,18,32,29,27,26].map(generatePageInfo)], + pagelist: [[4,1,7,6,12,9,15,14,20,17,23,22,28,25,31,30], [8,5,3,2,16,13,11,10,24,21,19,18,32,29,27,26]], }; const actual = new PerfectBound(testPagesEven, testDuplex, 8, false); expect(actual).toEqual(expected); diff --git a/src/signatures.js b/src/signatures.js index 1a15123..fd14d6b 100644 --- a/src/signatures.js +++ b/src/signatures.js @@ -15,7 +15,7 @@ export class Signatures { this.per_sheet = per_sheet || 4; // pages per sheet - default is 4. this.duplexrotate = duplexrotate || false; - this.pagelistdetails = []; + this.pagelist = []; this.sheets = Math.ceil(pages.length / this.per_sheet); @@ -41,7 +41,7 @@ export class Signatures { let blanks = new Array(diff).fill('b'); this.inputpagelist.push(...blanks); } - this.pagelistdetails = []; + this.pagelist = []; this.signaturepagelists = []; this.splitpagelist(); @@ -49,7 +49,7 @@ export class Signatures { createsigconfig() { this.sigconfig = this.generatesignatureindex(); - this.pagelistdetails = []; + this.pagelist = []; this.signaturepagelists = []; this.splitpagelist(); @@ -78,11 +78,11 @@ export class Signatures { // Use the booklet class for each signature this.signaturepagelists.forEach(pagerange => { - let pagelistdetails = this.booklet(pagerange, this.duplex, this.per_sheet, this.duplexrotate); - newsigs.push(pagelistdetails); + let pagelist = this.booklet(pagerange, this.duplex, this.per_sheet, this.duplexrotate); + newsigs.push(pagelist); }); - this.pagelistdetails = newsigs; + this.pagelist = newsigs; } generatesignatureindex() { @@ -117,7 +117,7 @@ export class Signatures { } booklet(pages, duplex, per_sheet, duplexrotate) { - let pagelistdetails = duplex ? [[]] : [[], []]; + let pagelist = duplex ? [[]] : [[], []]; let sheets = 1; const {front, rotate, back} = BOOKLET_LAYOUTS[per_sheet]; @@ -142,22 +142,14 @@ export class Signatures { front_config.forEach((pnum) => { let page = block[pnum - 1]; //page layouts are 1-indexed, not 0-index - pagelistdetails[0].push({ - info: page, - isSigStart:front_start == 0 && pnum == 1, - isSigEnd: front_start == 0 && pnum == block.length - }); + pagelist[0].push(page); }); const backlist = this.duplex ? 0 : 1; back_config.forEach((pnum) => { let page = block[pnum - 1]; - pagelistdetails[backlist].push({ - info: page, - isSigStart:front_start == 0 && pnum == 1, - isSigEnd: front_start == 0 && pnum == block.length - }); + pagelist[backlist].push(page); }); // Update all our counters @@ -167,6 +159,6 @@ export class Signatures { back_end += pageblock; } - return pagelistdetails; + return pagelist; } } \ No newline at end of file diff --git a/src/signatures.test.js b/src/signatures.test.js index db0310e..bd60010 100644 --- a/src/signatures.test.js +++ b/src/signatures.test.js @@ -19,7 +19,7 @@ describe('Signatures model', () => { inputpagelist: [], per_sheet: 8, duplexrotate: true, - pagelistdetails: [], + pagelist: [], sheets: 0, sigconfig: [], signaturepagelists: [], diff --git a/src/utils/clickHandlers.js b/src/utils/clickHandlers.js index 2d515d3..fe0c99d 100644 --- a/src/utils/clickHandlers.js +++ b/src/utils/clickHandlers.js @@ -7,7 +7,6 @@ import { updateAddOrRemoveCustomPaperOption, updatePaperSelectOptionsUnits } fro export function handleGenerateClick(generateEl, book) { generateEl.setAttribute('disabled', true); - generateEl.style.fontSize = "13px"; generateEl.innerText = 'Generating, this may take a little while...'; console.log('The whole Book model:', book); const result = book.createoutputfiles(false); @@ -20,14 +19,13 @@ export function handleGenerateClick(generateEl, book) { }) .finally((_) => { generateEl.removeAttribute('disabled'); - generateEl.style.fontSize = "24px"; - generateEl.innerText = 'Generate PDF Output'; + generateEl.innerText = 'Generate Output'; }); } export function handlePreviewClick(previewEl, book) { previewEl.setAttribute('disabled', true); - previewEl.innerText = 'Generating Preview...'; + previewEl.innerText = 'Generating Preview, please wait....'; const result = book.createoutputfiles(true); result .then((_) => { @@ -47,4 +45,4 @@ export function handleResetSettingsClick(book) { book.update(defaultConfiguration); updateAddOrRemoveCustomPaperOption(); updatePaperSelectOptionsUnits(); -} +} \ No newline at end of file diff --git a/src/utils/formUtils.js b/src/utils/formUtils.js index 8853706..09bbd4c 100644 --- a/src/utils/formUtils.js +++ b/src/utils/formUtils.js @@ -22,7 +22,6 @@ const fromFormToConfiguration = (form) => paperRotation90: form.has("paper_rotation_90"), pageLayout: form.get("pagelayout"), cropMarks: form.has("cropmarks"), - pdfEdgeMarks: form.has("pdf_edge_marks"), cutMarks: form.has("cutmarks"), pageScaling: form.get("page_scaling"), pagePositioning: form.get("page_positioning"), diff --git a/src/utils/renderUtils.js b/src/utils/renderUtils.js index efebef4..bf070cf 100644 --- a/src/utils/renderUtils.js +++ b/src/utils/renderUtils.js @@ -18,7 +18,7 @@ export function renderInfoBox(book) { if (book.book == null || book.book == undefined) return - const outputPages = book.book.pagelistdetails.reduce((acc, list) => { + const outputPages = book.book.pagelist.reduce((acc, list) => { list.forEach((sublist) => (acc += (sublist.length ? sublist.length : 1))); return acc; }, 0); @@ -167,17 +167,15 @@ export function renderFormFromSettings(configuration) { document.querySelector("input[name='cropmarks']").checked = true; } - if (configuration.pdfEdgeMarks) { - document.querySelector("input[name='pdf_edge_marks']").checked = true; - } - if (configuration.cutMarks) { document.querySelector("input[name='cutmarks']").checked = true; } // Set radio options + document.querySelector(`input[name="pagelayout"][value="${configuration.pageLayout}"]`).checked = true; document.querySelector(`input[name="sig_format"][value="${configuration.sigFormat}"]`).checked = true; document.querySelector(`input[name="wacky_spacing"][value="${configuration.wackySpacing}"]`).checked = true; + document.querySelector(`input[name="source_rotation"][value="${configuration.sourceRotation}"]`).checked = true; // Set freeform inputs document.querySelector('input[name="main_fore_edge_padding_pt"]').value = configuration.mainForeEdgePaddingPt; @@ -188,8 +186,6 @@ export function renderFormFromSettings(configuration) { document.querySelector('input[name="flyleafs"]').value = configuration.flyleafs; // Set select options - document.querySelector('select[name="source_rotation"]').value = configuration.sourceRotation; - document.querySelector('select[name="pagelayout"]').value = configuration.pageLayout; document.querySelector('select[name="page_scaling"]').value = configuration.pageScaling; document.querySelector('select[name="page_positioning"]').value = configuration.pagePositioning; document.querySelector('select[name="print_file"]').value = configuration.printFile; @@ -211,11 +207,4 @@ export function renderFormFromSettings(configuration) { } else { document.querySelector("input[name='sig_length']").value = configuration.sigLength; } - - // Hide and show elements based on configuration - let sourceRotationExamples = Array.from(document.getElementsByClassName('source_rotation_example')); - const selectedValue = configuration.sourceRotation + '_example'; - sourceRotationExamples.forEach((example) => { - example.style.display = (example.id === selectedValue ? 'block' : 'none'); - }); } diff --git a/src/wacky_imposition.js b/src/wacky_imposition.js index cc21632..77976e8 100644 --- a/src/wacky_imposition.js +++ b/src/wacky_imposition.js @@ -11,7 +11,7 @@ export class WackyImposition{ constructor(pages, duplex,format, isPacked) { this.duplex=duplex; this.sigconfig=[] // sig_count looks at the length of this array, sig_arrange joins them together with a ,; - this.pagelistdetails = [[]]; + this.pagelist = [[]]; this.isPacked = isPacked; console.log("Constructor sees ", pages) // for UI estimates @@ -623,4 +623,4 @@ export class WackyImposition{ rotate180(page) { page.vFlip = !page.vFlip; } -} +} \ No newline at end of file diff --git a/src/wacky_imposition.test.js b/src/wacky_imposition.test.js index b53b217..6c0396b 100644 --- a/src/wacky_imposition.test.js +++ b/src/wacky_imposition.test.js @@ -14,7 +14,7 @@ describe('WackyImposition model', () => { const expected = { duplex: true, sigconfig: [], - pagelistdetails: [[]], + pagelist: [[]], sheets: 0, }; const actual = new WackyImposition(testPages, testDuplex, testFormat);