Skip to content

Commit

Permalink
✨ Turn card selection into a setting
Browse files Browse the repository at this point in the history
Now that can also be shared through the URL.
  • Loading branch information
foosel committed May 26, 2024
1 parent 17c48a2 commit e43a4b2
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 51 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
# Changelog

## 2024-05-26

### ✨ Improvements

- 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.

### 🐛 Bug fixes

- Fixed an error in the pdf generation logic in case of a horizontal foldline.

## 2024-05-24

### ✨ Improvements
Expand Down
101 changes: 50 additions & 51 deletions src/assets/cardfoldr.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,40 +13,40 @@ const roundValue = (value, digits) => {
return Math.round(value * factor) / factor;
}

const clearPages = (container) => {
const clearContainer = (container) => {
while (container.firstChild) {
container.removeChild(container.firstChild);
}
}

const parsePageSelection = (pageSelection, pageCount) => {
if (!pageSelection) {
return Array.from({ length: pageCount }, (_, i) => i + 1);
const parseRangeSelection = (rangeSelection, count) => {
if (!rangeSelection) {
return Array.from({ length: count }, (_, i) => i + 1);
}

let pages = [];
for (const page of pageSelection.split(',')) {
const p = page.trim();
let range = [];
for (const item of rangeSelection.split(',')) {
const p = item.trim();
if (p.includes("-")) {
const parts = p.split('-').map(x => x.trim());

let first = parts[0] === "" ? 1 : parseInt(parts[0]);
let last = parts[1] === "" ? pageCount : parseInt(parts[1]);
let last = parts[1] === "" ? count : parseInt(parts[1]);
if (first > last) {
const tmp = first;
first = last;
last = tmp;
}
pages = pages.concat(Array.from({ length: last - first + 1 }, (_, i) => i + first));
range = range.concat(Array.from({ length: last - first + 1 }, (_, i) => i + first));
} else {
pages.push(parseInt(p));
range.push(parseInt(p));
}
}

return pages.filter(x => x >= 1 && x <= pageCount);
return range.filter(x => x >= 1 && x <= count);
}

const toPageSelection = (selected, pageCount) => {
const toRangeSelection = (selected, pageCount) => {
let last = null, rangeStart = null;
const output = [];
for (const page of selected) {
Expand Down Expand Up @@ -94,6 +94,19 @@ const toPageSelection = (selected, pageCount) => {
return output.join(", ");
}

const refreshRangeSelection = async (selection, container, entryLocator) => {
const range = parseRangeSelection(selection, container.querySelectorAll(entryLocator).length);
for (const entry of container.querySelectorAll(entryLocator)) {
const p = parseInt(entry.id.split('-')[1]);
if (range.includes(p)) {
entry.classList.remove("excluded");
} else {
entry.classList.add("excluded");
}
}

}

// --- PDF rendering ---

let _currentScale;
Expand All @@ -102,12 +115,13 @@ const updatePageSelection = (which) => {
if (which === "pdf" && pdf) {
const pagesContainer = document.getElementById('pages');
const selectedPages = Array.from(pagesContainer.querySelectorAll('.page:not(.excluded)')).map(x => parseInt(x.id.split('-')[1]));
document.getElementById('pageSelection').value = toPageSelection(selectedPages, pdf.numPages);
document.getElementById('pageSelection').value = toRangeSelection(selectedPages, pdf.numPages);
} else if (which === "background" && backgroundPdf) {
const backgroundContainer = document.getElementById('pages-back');
const selectedBackgroundPages = Array.from(backgroundContainer.querySelectorAll('.page:not(.excluded)')).map(x => parseInt(x.id.split('-')[2]));
document.getElementById('backgroundPageSelection').value = toPageSelection(selectedBackgroundPages, backgroundPdf ? backgroundPdf.numPages : 0);
document.getElementById('backgroundPageSelection').value = toRangeSelection(selectedBackgroundPages, backgroundPdf ? backgroundPdf.numPages : 0);
}
syncQueryParams();
}

const drawGrid = (ctx, countX, countY, width, height, startX, startY, marginX, marginY, cutMargin, mmFactor) => {
Expand Down Expand Up @@ -180,33 +194,8 @@ const drawPage = async (page, scale) => {
}

const refreshPageSelection = async () => {
if (!pdf) {
return;
}

const pageSelection = parsePageSelection(document.getElementById('pageSelection').value, pdf.numPages);
const backgroundPageSelection = parsePageSelection(document.getElementById('backgroundPageSelection').value, backgroundPdf ? backgroundPdf.numPages : 0);

const pagesContainer = document.getElementById('pages');
const backgroundContainer = document.getElementById('pages-back');

for (const page of pagesContainer.querySelectorAll('.page')) {
const p = parseInt(page.id.split('-')[1]);
if (pageSelection.includes(p)) {
page.classList.remove("excluded");
} else {
page.classList.add("excluded");
}
}

for (const page of backgroundContainer.querySelectorAll('.page')) {
const p = parseInt(page.id.split('-')[2]);
if (backgroundPageSelection.includes(p)) {
page.classList.remove("excluded");
} else {
page.classList.add("excluded");
}
}
refreshRangeSelection(document.getElementById('pageSelection').value, document.getElementById('pages'), '.page');
refreshRangeSelection(document.getElementById('backgroundPageSelection').value, document.getElementById('pages-back'), '.page');
}

const refreshGrid = async () => {
Expand Down Expand Up @@ -256,8 +245,8 @@ const refreshPdf = async (changed) => {
_currentScale = scale;

const pagesContainer = document.getElementById('pages');
const pageSelection = parsePageSelection(document.getElementById('pageSelection').value, pdf ? pdf.numPages : 0);
const backgroundPageSelection = parsePageSelection(document.getElementById('backgroundPageSelection').value, backgroundPdf ? backgroundPdf.numPages : 0);
const pageSelection = parseRangeSelection(document.getElementById('pageSelection').value, pdf ? pdf.numPages : 0);
const backgroundPageSelection = parseRangeSelection(document.getElementById('backgroundPageSelection').value, backgroundPdf ? backgroundPdf.numPages : 0);

const coordinateHelp = "Mouse over the pages to see the coordinates of the cursor here";
document.getElementById('coordinates').textContent = coordinateHelp;
Expand Down Expand Up @@ -334,15 +323,15 @@ const refreshPdf = async (changed) => {
const jobs = [];

if (changed.includes("pdf")) {
clearPages(pagesContainer);
clearContainer(pagesContainer);
if (pdf) {
jobs.push(renderPages(pdf, pagesContainer, "page", "Page ", pageSelection));
}
}

if (changed.includes("background")) {
const backgroundPagesContainer = document.getElementById('pages-back');
clearPages(backgroundPagesContainer);
clearContainer(backgroundPagesContainer);
if (backgroundPdf) {
jobs.push(renderPages(backgroundPdf, backgroundPagesContainer, "background-page", "Backs page ", backgroundPageSelection));
}
Expand All @@ -366,6 +355,14 @@ const updateDeckInfo = (count, excluded) => {
document.getElementById('card-output').textContent = `Extracted ${count} cards, ${excluded} of which are excluded, making for a total of ${count - excluded} cards to be included.`;
}

const updateCardSelection = () => {
const cardsContainer = document.getElementById('cards');
const cardCount = cardsContainer.querySelectorAll('.card').length;
const selectedCards = Array.from(cardsContainer.querySelectorAll('.card:not(.excluded)')).map(x => parseInt(x.id.split('-')[1]));
document.getElementById('cardSelection').value = toRangeSelection(selectedCards, cardCount);
syncQueryParams();
}

const rotateImage180 = async (image) => {
const img = new Image();
img.src = image;
Expand All @@ -387,8 +384,8 @@ const rotateImage180 = async (image) => {

const extractCards = async () => {
if (!pdf) return;
const pageSelection = parsePageSelection(document.getElementById('pageSelection').value, pdf.numPages);
const backgroundPageSelection = parsePageSelection(document.getElementById('backgroundPageSelection').value, backgroundPdf ? backgroundPdf.numPages : 0);
const pageSelection = parseRangeSelection(document.getElementById('pageSelection').value, pdf.numPages);
const backgroundPageSelection = parseRangeSelection(document.getElementById('backgroundPageSelection').value, backgroundPdf ? backgroundPdf.numPages : 0);

const countX = parseInt(document.getElementById('countX').value);
const countY = parseInt(document.getElementById('countY').value);
Expand Down Expand Up @@ -419,6 +416,7 @@ const extractCards = async () => {
} else if (backLoc === "duplex" || backLoc === "duplex2") {
expectedTotal = countX * countY * Math.ceil(pageSelection.length / 2);
}
const cardSelection = parseRangeSelection(document.getElementById('cardSelection').value, expectedTotal);

let count = 1;
for (let p = 0; p < (backLoc === "lastpage" ? pageSelection.length - 1 : pageSelection.length); p = p + ((backLoc === "duplex" || backLoc === "duplex2") ? 2 : 1)) {
Expand Down Expand Up @@ -452,9 +450,10 @@ const extractCards = async () => {

const cardElement = document.createElement('div');
cardElement.id = `card-${count}`;
cardElement.classList = `card ${orientationClass}`;
cardElement.classList = `card ${orientationClass}` + (cardSelection === null || cardSelection.includes(count) ? "" : " excluded");
cardElement.addEventListener("click", () => {
cardElement.classList.toggle("excluded");
updateCardSelection();
updateDeckInfo(count - 1, document.querySelectorAll('.card.excluded').length);
});

Expand Down Expand Up @@ -976,16 +975,16 @@ document.getElementById('extractCards').addEventListener('click', async () => {
return;
}
if (backLoc === "fileall") {
const pageSelection = parsePageSelection(document.getElementById('pageSelection').value, pdf.numPages);
const backgroundPageSelection = parsePageSelection(document.getElementById('backgroundPageSelection').value, backgroundPdf.numPages);
const pageSelection = parseRangeSelection(document.getElementById('pageSelection').value, pdf.numPages);
const backgroundPageSelection = parseRangeSelection(document.getElementById('backgroundPageSelection').value, backgroundPdf.numPages);

if (pageSelection.length !== backgroundPageSelection.length) {
alert("The number of (selected) pages in the card file and the card background file must match");
return;
}
}
if ((backLoc === "duplex" || backLoc === "duplex2")) {
const pageSelection = parsePageSelection(document.getElementById('pageSelection').value, pdf.numPages);
const pageSelection = parseRangeSelection(document.getElementById('pageSelection').value, pdf.numPages);

if (pageSelection.length % 2 !== 0) {
alert("The number of pages in the card file must be even to use duplex mode for card backs");
Expand Down
6 changes: 6 additions & 0 deletions src/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,12 @@ <h2>Step 3: Extract Cards</h2>
</select>
</div>

<div class="pure-control-group">
<label for="cardSelection">Card selection:</label>
<input type="text" class="width-xlarge" id="cardSelection" placeholder="all" data-query="cards-selection" />
<span class="pure-form-message-inline">Comma separated list of cards or ranges of all included cards</span>
</div>

<div class="pure-controls">
<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>
Expand Down

0 comments on commit e43a4b2

Please sign in to comment.