Skip to content

Commit

Permalink
✨ Support multiple rows and full auto layouting
Browse files Browse the repository at this point in the history
The PDF generation will now - unless configured
otherwise - try to make the best of the available
space and generate multiple rows of cards. It
will also detect whether a horizontal or vertical
fold line is best to get as many as possible cards
on one page.

All of this can of course be turned off by deselecting
"Auto" for foldline and unchecking "allow multiple rows".
  • Loading branch information
foosel committed May 26, 2024
1 parent 8d509cf commit e871246
Show file tree
Hide file tree
Showing 11 changed files with 370 additions and 160 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

- Added a share button to the presets area that will copy the current settings as shareable URL to the clipboard.
- Turned selected cards into a setting, like the page selection. That way they can also be shared.
- The PDF generation will now - unless configured otherwise - try to make the best of the available space and generate multiple rows of cards. It will also detect whether a horizontal or vertical fold line is best to get as many as possible cards on one page. This should make the generated PDFs more efficient in terms of paper usage, especially in case of tiny cards - or tiles.

### 🐛 Bug fixes

Expand Down
17 changes: 17 additions & 0 deletions src/assets/cardfoldr.css
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,23 @@ input[type="number"]:invalid {
color: red;
}

.pure-form-aligned label {
margin-left: .2em;
}

.pure-form-aligned .pure-control-group .spacer {
width: 10em;
margin: 0 1em 0 0;
display: inline-block;
}

.pure-form-aligned .pure-control-group label:not(:first-child) {
text-align: left;
margin: .5em 0 .2em .2em;
width: inherit;
vertical-align: inherit;
}

/* pdf rendering */

#pages,
Expand Down
6 changes: 4 additions & 2 deletions src/assets/cardfoldr.js
Original file line number Diff line number Diff line change
Expand Up @@ -607,10 +607,11 @@ const generatePdf = async () => {
const foldingMargin = parseFloat(document.getElementById('foldingMargin').value);
const printerMargin = parseFloat(document.getElementById('printerMargin').value);
const cutterOffset = parseFloat(document.getElementById('cutterOffset').value);
const foldLine = document.getElementById('foldLine').value;
const foldLinePreference = document.getElementById('foldLine').value;

const foldLineEdge = document.getElementById('foldLineEdge').value;
const downloadFilename = document.getElementById('downloadFilename').value;
const allowMultipleRows = document.getElementById('allowMultipleRows').checked;

const generateLog = document.getElementById('generate-output');
generateLog.textContent = "Collecting cards...";
Expand Down Expand Up @@ -701,7 +702,8 @@ const generatePdf = async () => {
cutterOffset,

pageSize,
foldLine,
foldLinePreference,
allowMultipleRows,
title,
}
}
Expand Down
378 changes: 237 additions & 141 deletions src/assets/worker.js

Large diffs are not rendered by default.

14 changes: 11 additions & 3 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,8 @@ <h2>Step 3: Extract Cards</h2>
<span class="pure-form-message-inline">Comma separated list of cards or ranges of all included cards</span>
</div>

<div class="pure-controls">
<div class="pure-control-group">
<span class="spacer"></span>
<input type="checkbox" id="rotateBacks" data-query="cards-rotate-backs" data-preset="cards-rotate-backs" /> <label for="rotateBacks">Rotate backs 180°</label>
<span class="pure-form-message-inline">Use this if the backs are otherwise upside down</span>
</div>
Expand Down Expand Up @@ -260,10 +261,11 @@ <h2>Step 4: Generate PDF</h2>
<div class="pure-control-group">
<label for="foldLine">Fold line:</label>
<select id="foldLine" class="min-width-medium" data-query="output-foldline">
<option value="vertical" selected>Vertical</option>
<option value="auto" selected>Auto</option>
<option value="vertical">Vertical</option>
<option value="horizontal">Horizontal</option>
</select>
<span class="pure-form-message-inline">Direction of the fold line</span>
<span class="pure-form-message-inline">Direction of the fold line, "Auto" will optimize for cards per page</span>
</div>

<div class="pure-control-group">
Expand Down Expand Up @@ -300,6 +302,12 @@ <h2>Step 4: Generate PDF</h2>
</div>
<span class="pure-form-message-inline">Distance from the fold line to the edge of the card</span>
</div>

<div class="pure-control-group">
<span class="spacer"></span>
<input type="checkbox" id="allowMultipleRows" data-query="output-multiple-rows" checked /> <label for="allowMultipleRows">Allow multiple rows</label>
<span class="pure-form-message-inline">Allowing multiple rows will possibly allow more cards per page</span>
</div>
</fieldset>

<fieldset>
Expand Down
Binary file added tests/files/test-pdf.foldable.horizontal.pdf
Binary file not shown.
Binary file added tests/files/test-pdf.foldable.no-rows.pdf
Binary file not shown.
Binary file modified tests/files/test-pdf.foldable.pdf
Binary file not shown.
Binary file added tests/files/test-pdf.foldable.vertical.pdf
Binary file not shown.
5 changes: 4 additions & 1 deletion tests/fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ const testPdf = {
preset: {"grid-count-x":"3","grid-count-y":"3","grid-width":"40","grid-height":"40","grid-start-x":"0","grid-start-y":"0","grid-margin-x":"0","grid-margin-y":"0","grid-cut-margin":"0","grid-step-size":"0.1","cards-backs":"fileall","cards-rotate-backs":false,"_key":"test-pdf","_name":"Test PDF"},
path: "./files/test-pdf.pdf",
filename: "test-pdf.pdf",
outputPath : "./files/test-pdf.foldable.pdf",
outputPathDefault: "./files/test-pdf.foldable.pdf",
outputPathVerticalOnly: "./files/test-pdf.foldable.vertical.pdf",
outputPathHorizontalOnly: "./files/test-pdf.foldable.horizontal.pdf",
outputPathNoRows: "./files/test-pdf.foldable.no-rows.pdf",
outputFilename: "test-pdf.foldable.pdf"
}

Expand Down
109 changes: 96 additions & 13 deletions tests/specs/generate-pdf.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const { test, expect } = require('../fixtures');
const ComparePdf = require("compare-pdf");
const fs = require("fs");

test.describe.configure({ mode: 'serial' });

const pdfCompare = async (actual, expected) => {
return await new ComparePdf()
Expand All @@ -9,6 +10,24 @@ const pdfCompare = async (actual, expected) => {
.compare();
};

const checkPdf = async (download, expected, testInfo) => {
if (testInfo.project.name === "chromium") {
// compare PDFs, but only in Chrome for now due to different rendering in Firefox
let result;
try {
result = await pdfCompare(await download.path(), expected);
} catch (error) {
result.message = error;
}

const actualPath = testInfo.outputPath("test-pdf.foldable.pdf");
await download.saveAs(actualPath);

expect(result.message).toBeUndefined();
expect(result.status).toBe("passed")
}
};

test.beforeEach(async ({page, testPdf}) => {
await page.goto(`./?${testPdf.query}`);

Expand All @@ -24,7 +43,7 @@ test.beforeEach(async ({page, testPdf}) => {
await expect(page.locator("#generate")).toBeEnabled();
});

test("Simple PDF generation", async ({page, testPdf}, testInfo) => {
test("PDF generation: defaults", async ({page, testPdf}, testInfo) => {
// generate PDF
await page.locator("#generate").click();

Expand All @@ -41,18 +60,82 @@ test("Simple PDF generation", async ({page, testPdf}, testInfo) => {
// verify the PDF is downloaded
expect(download.url()).toContain("blob:");
expect(download.suggestedFilename()).toMatch(/.pdf$/i);
await checkPdf(download, testPdf.outputPathDefault, testInfo);

// cleanup
await download.delete();
});

if (testInfo.project === "chromium") {
// compare PDFs, but only in Chrome for now due to different rendering in Firefox
let result;
try {
result = await pdfCompare(await download.path(), testPdf.outputPath);
} catch (error) {
result = error;
}
expect(result.message).toBeUndefined();
expect(result.status).toBe("passed")
}
test("PDF generation: vertical enforced", async ({page, testPdf}, testInfo) => {
await page.locator("#foldLine").selectOption("vertical");

// generate PDF
await page.locator("#generate").click();

// verify the PDF is generated
await expect(await page.locator("#download-button").getAttribute("href")).toContain("blob:");
await expect(await page.locator("#output iframe").getAttribute("src")).toContain("blob:");

// download PDF
const downloadPromise = page.waitForEvent('download');
await expect(await page.locator("#download-button").getAttribute("download")).toBe(testPdf.outputFilename);
await page.locator("#download-button").click();
const download = await downloadPromise;

// verify the PDF is downloaded
expect(download.url()).toContain("blob:");
expect(download.suggestedFilename()).toMatch(/.pdf$/i);
await checkPdf(download, testPdf.outputPathVerticalOnly, testInfo);

// cleanup
await download.delete();
});

test("PDF generation: horizontal enforced", async ({page, testPdf}, testInfo) => {
await page.locator("#foldLine").selectOption("horizontal");

// generate PDF
await page.locator("#generate").click();

// verify the PDF is generated
await expect(await page.locator("#download-button").getAttribute("href")).toContain("blob:");
await expect(await page.locator("#output iframe").getAttribute("src")).toContain("blob:");

// download PDF
const downloadPromise = page.waitForEvent('download');
await expect(await page.locator("#download-button").getAttribute("download")).toBe(testPdf.outputFilename);
await page.locator("#download-button").click();
const download = await downloadPromise;

// verify the PDF is downloaded
expect(download.url()).toContain("blob:");
expect(download.suggestedFilename()).toMatch(/.pdf$/i);
await checkPdf(download, testPdf.outputPathHorizontalOnly, testInfo);

// cleanup
await download.delete();
});

test("PDF generation: no rows", async ({page, testPdf}, testInfo) => {
await page.locator("#allowMultipleRows").uncheck();

// generate PDF
await page.locator("#generate").click();

// verify the PDF is generated
await expect(await page.locator("#download-button").getAttribute("href")).toContain("blob:");
await expect(await page.locator("#output iframe").getAttribute("src")).toContain("blob:");

// download PDF
const downloadPromise = page.waitForEvent('download');
await expect(await page.locator("#download-button").getAttribute("download")).toBe(testPdf.outputFilename);
await page.locator("#download-button").click();
const download = await downloadPromise;

// verify the PDF is downloaded
expect(download.url()).toContain("blob:");
expect(download.suggestedFilename()).toMatch(/.pdf$/i);
await checkPdf(download, testPdf.outputPathNoRows, testInfo);

// cleanup
await download.delete();
Expand Down

0 comments on commit e871246

Please sign in to comment.