mirror of
https://github.com/Investigamer/cardconjurer.git
synced 2025-09-18 10:23:18 -05:00
feat+fix: added ui for select number of copies in printing tool and fixed images not found when cutting aids where added in local server (black.png and cuttingGuides.svg)
This commit is contained in:
373
print/index.html
373
print/index.html
@@ -1,74 +1,307 @@
|
|||||||
<!-- START OF CONTENT -->
|
<!-- START OF CONTENT -->
|
||||||
<h2 class='readable-background header-extension title center margin-bottom-large'>Printing Tool</h2>
|
<h2
|
||||||
<div class='readable-background padding layer margin-bottom-large'>
|
class="readable-background header-extension title center margin-bottom-large"
|
||||||
<h4 class='collapsible collapsed center padding margin-bottom' onclick='toggleCollapse(event);'>Configure Page Settings</h4>
|
>
|
||||||
<div>
|
Printing Tool
|
||||||
<h5 class='margin-bottom padding input-description'>Select your paper size</h5>
|
</h2>
|
||||||
<select onchange='setPageSize(this.value.split(","));' class='input margin-bottom'>
|
<div class="readable-background padding layer margin-bottom-large">
|
||||||
<option value='8.5,11'>Letter (8.5 by 11)</option>
|
<h4
|
||||||
<option value='8.2667,11.6934'>A4</option>
|
class="collapsible collapsed center padding margin-bottom"
|
||||||
</select>
|
onclick="toggleCollapse(event);"
|
||||||
<h5 class='margin-bottom padding input-description'>Toggle the paper orientation (Portrait / Landscape)</h5>
|
>
|
||||||
<button onclick='changeOrientation();' class='input margin-bottom'>Toggle orientation</button>
|
Configure Page Settings
|
||||||
<h5 class='margin-bottom padding input-description'>Select a default card size</h5>
|
</h4>
|
||||||
<select onchange='setCardSize(this.value.split(","));' class='input margin-bottom'>
|
<div>
|
||||||
<option value='2.5,3.5'>2.5 x 3.5 Inches</option>
|
<h5 class="margin-bottom padding input-description">
|
||||||
<option value='2.48031,3.46457'>63 x 88 mm</option>
|
Select your paper size
|
||||||
</select>
|
</h5>
|
||||||
<h5 class='margin-bottom padding input-description'>Or enter your own card size</h5>
|
<select
|
||||||
<div class='margin-bottom split-grid'>
|
onchange='setPageSize(this.value.split(","));'
|
||||||
<input type='number' id='cardWidth' class='input' value='1500' onchange='setCardSize();'>
|
class="input margin-bottom"
|
||||||
<input type='number' id='cardHeight' class='input' value='2100' onchange='setCardSize();'>
|
>
|
||||||
</div>
|
<option value="8.5,11">Letter (8.5 by 11)</option>
|
||||||
<h5 class='margin-bottom padding input-description'>Enter your bleed edge thickness (in pixels)</h5>
|
<option value="8.2667,11.6934">A4</option>
|
||||||
<input type='number' id='cardPadding' class='input margin-bottom' value='0' min='0' onchange='setPaddingSize(this.value);'>
|
</select>
|
||||||
<h5 class='margin-bottom padding input-description'>Enter the distance between cards (in pixels)</h5>
|
<h5 class="margin-bottom padding input-description">
|
||||||
<input type='number' id='cardMargin' class='input margin-bottom' value='30' min='0' onchange='setMarginSize(this.value);'>
|
Toggle the paper orientation (Portrait / Landscape)
|
||||||
<h5 class='margin-bottom padding input-description'>Set PPI (pixels per inch)</h5>
|
</h5>
|
||||||
<input type='number' id='cardPPI' class='input margin-bottom' value='600' min='1' max='2400' onchange='setPPI(this.value);'>
|
<button onclick="changeOrientation();" class="input margin-bottom">
|
||||||
<h5 class='margin-bottom padding input-description'>Include cutting aids (colored marks to help guide cuts; may not be visible in preview)</h5>
|
Toggle orientation
|
||||||
<label class='checkbox-container input margin-bottom'>Cutting aids
|
</button>
|
||||||
<input id='cuttingAidsCheckbox' type='checkbox' onchange='setCuttingAids(this.checked);'>
|
<h5 class="margin-bottom padding input-description">
|
||||||
<span class='checkmark'></span>
|
Select a default card size
|
||||||
</label>
|
</h5>
|
||||||
<h5 class='margin-bottom padding input-description'>Images already include bleed edge</h5>
|
<select
|
||||||
<label class='checkbox-container input margin-bottom'>Bleed edge included
|
onchange='setCardSize(this.value.split(","));'
|
||||||
<input id='bleedEdgeCheckbox' type='checkbox' onchange='setBleedEdge(this.checked);' checked>
|
class="input margin-bottom"
|
||||||
<span class='checkmark'></span>
|
>
|
||||||
</label>
|
<option value="2.5,3.5">2.5 x 3.5 Inches</option>
|
||||||
<h5 class='margin-bottom padding input-description'>Bleed Edge Color</h5>
|
<option value="2.48031,3.46457">63 x 88 mm</option>
|
||||||
<input id='bleedEdgeColor' type='color' class='input margin-bottom' onchange='setBleedEdgeColor(this.value);'>
|
</select>
|
||||||
<h5 class='margin-bottom padding input-description'>Save your current configurations as default</h5>
|
<h5 class="margin-bottom padding input-description">
|
||||||
<button onclick='saveDefaults();' class='input margin-bottom'>Save configuration</button>
|
Or enter your own card size
|
||||||
</div>
|
</h5>
|
||||||
</div>
|
<div class="margin-bottom split-grid">
|
||||||
<div class="layer margin-bottom-large">
|
<input
|
||||||
<div class="drop-area" style="padding: 1rem">
|
type="number"
|
||||||
<div class='padding margin-bottom-large readable-background'>
|
id="cardWidth"
|
||||||
<h5 class='margin-bottom padding input-description'>Upload the images that you'd like to print, or drag-and-drop them</h5>
|
class="input"
|
||||||
<input type='file' multiple accept='.png, .svg, .jpg, .jpeg, .bmp' placeholder='File Upload' class='input' oninput='uploadFiles(event.target.files, uploadCard, "filename");' data-dropFunction='uploadCard' data-otherParams='filename'>
|
value="1500"
|
||||||
</div>
|
onchange="setCardSize();"
|
||||||
<div class="center">
|
/>
|
||||||
<canvas style='height: auto; max-width:850px; width: 100%; background: #fff;'></canvas>
|
<input
|
||||||
</div>
|
type="number"
|
||||||
</div>
|
id="cardHeight"
|
||||||
|
class="input"
|
||||||
|
value="2100"
|
||||||
|
onchange="setCardSize();"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class='readable-background padding layer margin-bottom-large'>
|
<h5 class="margin-bottom padding input-description">
|
||||||
<h3 class='download padding' onclick='downloadCanvas();'>Download your Sheet (PNG)</h3>
|
Enter your bleed edge thickness (in pixels)
|
||||||
<h4 class='padding center'>(Can take a few seconds)</h4>
|
</h5>
|
||||||
</div>
|
<input
|
||||||
<div class='readable-background padding layer margin-bottom-large'>
|
type="number"
|
||||||
<h3 class='download padding' onclick='downloadPDF();'>Download your Sheet (PDF)</h3>
|
id="cardPadding"
|
||||||
<h4 class='padding center'>(WARNING: This can take around 15 seconds...)</h4>
|
class="input margin-bottom"
|
||||||
</div>
|
value="0"
|
||||||
<div class="readable-background layer margin-bottom-large">
|
min="0"
|
||||||
<h3 class='padding margin-bottom center'>
|
onchange="setPaddingSize(this.value);"
|
||||||
Want to see your custom cards on the kitchen table?
|
/>
|
||||||
</h3>
|
<h5 class="margin-bottom padding input-description">
|
||||||
<h4 class='padding'>
|
Enter the distance between cards (in pixels)
|
||||||
Upload up to nine images, and they will automatically arrange themselves on an 8.5" by 11" sheet, so you can print them at home at up to 600PPI.
|
</h5>
|
||||||
</h4>
|
<input
|
||||||
|
type="number"
|
||||||
|
id="cardMargin"
|
||||||
|
class="input margin-bottom"
|
||||||
|
value="30"
|
||||||
|
min="0"
|
||||||
|
onchange="setMarginSize(this.value);"
|
||||||
|
/>
|
||||||
|
<h5 class="margin-bottom padding input-description">
|
||||||
|
Set PPI (pixels per inch)
|
||||||
|
</h5>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
id="cardPPI"
|
||||||
|
class="input margin-bottom"
|
||||||
|
value="600"
|
||||||
|
min="1"
|
||||||
|
max="2400"
|
||||||
|
onchange="setPPI(this.value);"
|
||||||
|
/>
|
||||||
|
<h5 class="margin-bottom padding input-description">
|
||||||
|
Include cutting aids (colored marks to help guide cuts; may not be visible
|
||||||
|
in preview)
|
||||||
|
</h5>
|
||||||
|
<label class="checkbox-container input margin-bottom"
|
||||||
|
>Cutting aids
|
||||||
|
<input
|
||||||
|
id="cuttingAidsCheckbox"
|
||||||
|
type="checkbox"
|
||||||
|
onchange="setCuttingAids(this.checked);"
|
||||||
|
/>
|
||||||
|
<span class="checkmark"></span>
|
||||||
|
</label>
|
||||||
|
<h5 class="margin-bottom padding input-description">
|
||||||
|
Images already include bleed edge
|
||||||
|
</h5>
|
||||||
|
<label class="checkbox-container input margin-bottom"
|
||||||
|
>Bleed edge included
|
||||||
|
<input
|
||||||
|
id="bleedEdgeCheckbox"
|
||||||
|
type="checkbox"
|
||||||
|
onchange="setBleedEdge(this.checked);"
|
||||||
|
checked
|
||||||
|
/>
|
||||||
|
<span class="checkmark"></span>
|
||||||
|
</label>
|
||||||
|
<h5 class="margin-bottom padding input-description">Bleed Edge Color</h5>
|
||||||
|
<input
|
||||||
|
id="bleedEdgeColor"
|
||||||
|
type="color"
|
||||||
|
class="input margin-bottom"
|
||||||
|
onchange="setBleedEdgeColor(this.value);"
|
||||||
|
/>
|
||||||
|
<h5 class="margin-bottom padding input-description">
|
||||||
|
Save your current configurations as default
|
||||||
|
</h5>
|
||||||
|
<button onclick="saveDefaults();" class="input margin-bottom">
|
||||||
|
Save configuration
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="layer margin-bottom-large">
|
||||||
|
<div class="drop-area" style="padding: 1rem">
|
||||||
|
<div class="padding margin-bottom-large readable-background">
|
||||||
|
<h5 class="margin-bottom padding input-description">
|
||||||
|
Upload the images that you'd like to print, or drag-and-drop them
|
||||||
|
</h5>
|
||||||
|
<div
|
||||||
|
class="upload-box"
|
||||||
|
style="
|
||||||
|
border: 2px dashed #ccc;
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 20px;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
position: relative;
|
||||||
|
"
|
||||||
|
onclick="document.getElementById('file-upload').click()"
|
||||||
|
ondragover="event.preventDefault()"
|
||||||
|
ondrop="handleDrop(event)"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
id="file-upload"
|
||||||
|
type="file"
|
||||||
|
multiple
|
||||||
|
accept=".png, .svg, .jpg, .jpeg, .bmp"
|
||||||
|
style="display: none"
|
||||||
|
onchange="handleFiles(this.files)"
|
||||||
|
/>
|
||||||
|
<div style="font-size: 2rem; color: #ccc">
|
||||||
|
<svg
|
||||||
|
fill="gray"
|
||||||
|
height="30px"
|
||||||
|
width="30px"
|
||||||
|
version="1.1"
|
||||||
|
id="Capa_1"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
viewBox="0 0 374.116 374.116"
|
||||||
|
xml:space="preserve"
|
||||||
|
>
|
||||||
|
<g id="SVGRepo_bgCarrier" stroke-width="0"></g>
|
||||||
|
<g
|
||||||
|
id="SVGRepo_tracerCarrier"
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
></g>
|
||||||
|
<g id="SVGRepo_iconCarrier">
|
||||||
|
<g>
|
||||||
|
<path
|
||||||
|
d="M344.058,207.506c-16.568,0-30,13.432-30,30v76.609h-254v-76.609c0-16.568-13.432-30-30-30c-16.568,0-30,13.432-30,30 v106.609c0,16.568,13.432,30,30,30h314c16.568,0,30-13.432,30-30V237.506C374.058,220.938,360.626,207.506,344.058,207.506z"
|
||||||
|
></path>
|
||||||
|
<path
|
||||||
|
d="M123.57,135.915l33.488-33.488v111.775c0,16.568,13.432,30,30,30c16.568,0,30-13.432,30-30V102.426l33.488,33.488 c5.857,5.858,13.535,8.787,21.213,8.787c7.678,0,15.355-2.929,21.213-8.787c11.716-11.716,11.716-30.71,0-42.426L208.271,8.788 c-11.715-11.717-30.711-11.717-42.426,0L81.144,93.489c-11.716,11.716-11.716,30.71,0,42.426 C92.859,147.631,111.855,147.631,123.57,135.915z"
|
||||||
|
></path>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
<!-- Ícone de upload de arquivo -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
id="thumbnails"
|
||||||
|
style="display: flex; flex-wrap: wrap; gap: 10px"
|
||||||
|
></div>
|
||||||
|
<h5 class="margin-bottom padding input-description">
|
||||||
|
Choose the number of copies you'd like to print
|
||||||
|
</h5>
|
||||||
|
<div class="input-grid margin-bottom">
|
||||||
|
<input
|
||||||
|
id="repeat-count"
|
||||||
|
type="number"
|
||||||
|
min="1"
|
||||||
|
value="1"
|
||||||
|
class="input"
|
||||||
|
placeholder="Number of repetitions"
|
||||||
|
style="text-align: center"
|
||||||
|
/>
|
||||||
|
<button onclick="repeatImage();" class="input">Add Images</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script defer src='https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.5/jspdf.debug.js'></script>
|
<div class="center">
|
||||||
<script defer src="/print/print.js"></script>
|
<canvas
|
||||||
|
style="height: auto; max-width: 850px; width: 100%; background: #fff"
|
||||||
|
></canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="readable-background padding layer margin-bottom-large">
|
||||||
|
<h3 class="download padding" onclick="downloadCanvas();">
|
||||||
|
Download your Sheet (PNG)
|
||||||
|
</h3>
|
||||||
|
<h4 class="padding center">(Can take a few seconds)</h4>
|
||||||
|
</div>
|
||||||
|
<div class="readable-background padding layer margin-bottom-large">
|
||||||
|
<h3 class="download padding" onclick="downloadPDF();">
|
||||||
|
Download your Sheet (PDF)
|
||||||
|
</h3>
|
||||||
|
<h4 class="padding center">(WARNING: This can take around 15 seconds...)</h4>
|
||||||
|
</div>
|
||||||
|
<div class="readable-background layer margin-bottom-large">
|
||||||
|
<h3 class="padding margin-bottom center">
|
||||||
|
Want to see your custom cards on the kitchen table?
|
||||||
|
</h3>
|
||||||
|
<h4 class="padding">
|
||||||
|
Upload up to nine images, and they will automatically arrange themselves on
|
||||||
|
an 8.5" by 11" sheet, so you can print them at home at up to 600PPI.
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
let selectedFiles = [];
|
||||||
|
|
||||||
|
function repeatImage() {
|
||||||
|
const repeatCount = document.getElementById("repeat-count").value;
|
||||||
|
|
||||||
|
if (selectedFiles.length > 0) {
|
||||||
|
for (let i = 0; i < repeatCount; i++) {
|
||||||
|
console.log(`Uploading file ${i + 1} of ${repeatCount}`);
|
||||||
|
uploadFiles(selectedFiles, uploadCard, "filename");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear selected files
|
||||||
|
selectedFiles = [];
|
||||||
|
|
||||||
|
// clear the input
|
||||||
|
document.querySelector("input[type='file']").value = "";
|
||||||
|
|
||||||
|
// clear the repeat count
|
||||||
|
document.getElementById("repeat-count").value = 1;
|
||||||
|
|
||||||
|
// clear the thumbnails
|
||||||
|
document.getElementById("thumbnails").innerHTML = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleDrop(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
const files = event.dataTransfer.files;
|
||||||
|
handleFiles(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleFiles(files) {
|
||||||
|
selectedFiles.push(...files);
|
||||||
|
|
||||||
|
const thumbnails = document.getElementById("thumbnails");
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = function (e) {
|
||||||
|
const thumbnail = document.createElement("div");
|
||||||
|
thumbnail.style.position = "relative";
|
||||||
|
thumbnail.innerHTML = `
|
||||||
|
<img src="${e.target.result}" style="width: 100px; height: 100px; object-fit: cover; border-radius: 5px;" />
|
||||||
|
<button onclick="removeFile(this, '${file.name}')" style="position: absolute; top: 0; right: 0; background: #880808; color: white; border: none; border-radius: 50%; cursor: pointer;">×</button>
|
||||||
|
`;
|
||||||
|
thumbnails.appendChild(thumbnail);
|
||||||
|
};
|
||||||
|
reader.readAsDataURL(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeFile(button, fileName) {
|
||||||
|
const thumbnail = button.parentElement;
|
||||||
|
thumbnail.remove();
|
||||||
|
selectedFiles = selectedFiles.filter((file) => file.name !== fileName);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script
|
||||||
|
defer
|
||||||
|
src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.3.5/jspdf.debug.js"
|
||||||
|
></script>
|
||||||
|
<script defer src="/print/print.js"></script>
|
||||||
<!-- END OF CONTENT -->
|
<!-- END OF CONTENT -->
|
510
print/print.js
510
print/print.js
@@ -11,7 +11,7 @@ var cardHeight = parseInt(document.querySelector("#cardHeight").value);
|
|||||||
var cardPaddingX = parseInt(document.querySelector("#cardPadding").value);
|
var cardPaddingX = parseInt(document.querySelector("#cardPadding").value);
|
||||||
var cardPaddingY = cardPaddingX;
|
var cardPaddingY = cardPaddingX;
|
||||||
//whitespace
|
//whitespace
|
||||||
var cardMarginX = parseInt(document.querySelector("#cardMargin").value);
|
var cardMarginX = parseInt(document.querySelector("#cardMargin").value);
|
||||||
var cardMarginY = cardMarginX;
|
var cardMarginY = cardMarginX;
|
||||||
//booleans
|
//booleans
|
||||||
var imgIncludesBleedEdge = true;
|
var imgIncludesBleedEdge = true;
|
||||||
@@ -19,251 +19,367 @@ var bleedEdgeColor = "black";
|
|||||||
var useCuttingAids = false;
|
var useCuttingAids = false;
|
||||||
//Prepare variables/canvas/context
|
//Prepare variables/canvas/context
|
||||||
var imageList = [];
|
var imageList = [];
|
||||||
var canvas = document.querySelector('canvas');
|
var canvas = document.querySelector("canvas");
|
||||||
var context = canvas.getContext('2d');
|
var context = canvas.getContext("2d");
|
||||||
drawSheet();
|
drawSheet();
|
||||||
//svgs
|
//svgs
|
||||||
var cuttingGuides = new Image();
|
const blackPixel = getImage("black.png");
|
||||||
cuttingGuides.src = 'cuttingGuides.svg';
|
const cuttingGuides = getImage("cuttingGuides.svg");
|
||||||
var blackPixel = new Image();
|
|
||||||
blackPixel.src = 'black.png';
|
function getImage(imageSrc) {
|
||||||
|
const image = new Image();
|
||||||
|
|
||||||
|
image.onload = function () {
|
||||||
|
console.log(`Image '${image.src}' loaded`);
|
||||||
|
};
|
||||||
|
|
||||||
|
image.onerror = function () {
|
||||||
|
console.log(`Image '${image.src}' failed to load`);
|
||||||
|
|
||||||
|
if (!image.src.includes("print/")) {
|
||||||
|
console.log(`Trying to change src address to 'print/${imageSrc}'`);
|
||||||
|
|
||||||
|
image.src = `print/${imageSrc}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
image.src = imageSrc;
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
function uploadFrameOption(imageSource) {
|
||||||
|
const uploadedFrame = {
|
||||||
|
name: `Uploaded Image (${customCount})`,
|
||||||
|
src: imageSource,
|
||||||
|
noThumb: true,
|
||||||
|
};
|
||||||
|
customCount++;
|
||||||
|
availableFrames.push(uploadedFrame);
|
||||||
|
loadFramePack();
|
||||||
|
}
|
||||||
|
|
||||||
function uploadCard(card, filename) {
|
function uploadCard(card, filename) {
|
||||||
var img = new Image();
|
var img = new Image();
|
||||||
img.crossOrigin = 'anonymous';
|
img.crossOrigin = "anonymous";
|
||||||
img.onload = function() {imageList.push(this); drawSheet();}
|
img.onload = function () {
|
||||||
img.filename = filename.replace('filename=', '');
|
imageList.push(this);
|
||||||
img.src = card;
|
drawSheet();
|
||||||
|
};
|
||||||
|
img.filename = filename.replace("filename=", "");
|
||||||
|
img.src = card;
|
||||||
}
|
}
|
||||||
//buffer to avoid drawing the sheet *too* many times when uploading multiple images at the same time
|
//buffer to avoid drawing the sheet *too* many times when uploading multiple images at the same time
|
||||||
var drawingSheet;
|
var drawingSheet;
|
||||||
function drawSheet() {
|
function drawSheet() {
|
||||||
clearTimeout(drawingSheet);
|
clearTimeout(drawingSheet);
|
||||||
drawingSheet = setTimeout(drawSheetReal, 500);
|
drawingSheet = setTimeout(drawSheetReal, 500);
|
||||||
}
|
}
|
||||||
function drawSheetReal() {
|
function drawSheetReal() {
|
||||||
//Prepare canvases
|
//Prepare canvases
|
||||||
canvas.width = page[0] * ppi;
|
canvas.width = page[0] * ppi;
|
||||||
canvas.height = page[1] * ppi;
|
canvas.height = page[1] * ppi;
|
||||||
context.clearRect(0, 0, page[0] * ppi, page[1] * ppi);
|
context.clearRect(0, 0, page[0] * ppi, page[1] * ppi);
|
||||||
//Calc actual card size
|
//Calc actual card size
|
||||||
const cw = cardWidth + 2 * cardPaddingX + cardMarginX;
|
const cw = cardWidth + 2 * cardPaddingX + cardMarginX;
|
||||||
const ch = cardHeight + 2 * cardPaddingY + cardMarginY;
|
const ch = cardHeight + 2 * cardPaddingY + cardMarginY;
|
||||||
//Calc number of cards that fit on the sheet
|
//Calc number of cards that fit on the sheet
|
||||||
const cardsX = Math.floor(page[0] / (cw / ppi));
|
const cardsX = Math.floor(page[0] / (cw / ppi));
|
||||||
const cardsY = Math.floor(page[1] / (ch / ppi));
|
const cardsY = Math.floor(page[1] / (ch / ppi));
|
||||||
//Calc page margins
|
//Calc page margins
|
||||||
const pageMarginX = Math.floor((page[0] * ppi - cardsX * cw) / 2);
|
const pageMarginX = Math.floor((page[0] * ppi - cardsX * cw) / 2);
|
||||||
const pageMarginY = Math.floor((page[1] * ppi - cardsY * ch) / 2);
|
const pageMarginY = Math.floor((page[1] * ppi - cardsY * ch) / 2);
|
||||||
//Draw cutting guides that cover the page
|
//Draw cutting guides that cover the page
|
||||||
var count = 0;
|
var count = 0;
|
||||||
if (useCuttingAids) {
|
if (useCuttingAids) {
|
||||||
for (var i = 0; i < cardsX; i++) {
|
for (var i = 0; i < cardsX; i++) {
|
||||||
var x = pageMarginX + i * cw + Math.floor(cardMarginX / 2) + cardPaddingX - aidOffset;
|
var x =
|
||||||
context.fillRect(x, 0, aidWidth, page[1] * ppi);
|
pageMarginX +
|
||||||
context.fillRect(x + cardWidth, 0, aidWidth, page[1] * ppi);
|
i * cw +
|
||||||
}
|
Math.floor(cardMarginX / 2) +
|
||||||
for (var j = 0; j < cardsY; j++) {
|
cardPaddingX -
|
||||||
var y = pageMarginY + j * ch + Math.floor(cardMarginY / 2) + cardPaddingY - aidOffset;
|
aidOffset;
|
||||||
context.fillRect(0, y, page[0] * ppi, aidWidth);
|
context.fillRect(x, 0, aidWidth, page[1] * ppi);
|
||||||
context.fillRect(0, y + cardHeight, page[0] * ppi, aidWidth);
|
context.fillRect(x + cardWidth, 0, aidWidth, page[1] * ppi);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//Iterate through every viable space and draw the card there
|
for (var j = 0; j < cardsY; j++) {
|
||||||
count = 0;
|
var y =
|
||||||
for (var i = imageList.length - 1; i >= 0 && count < cardsX * cardsY; i--) {
|
pageMarginY +
|
||||||
if (imageList[i].width > 1) {
|
j * ch +
|
||||||
try {
|
Math.floor(cardMarginY / 2) +
|
||||||
//Calc upper-left corner of card *image* (accounts for bleed edge and margins)
|
cardPaddingY -
|
||||||
var x = pageMarginX + (count % cardsX) * (cw) + Math.floor(cardMarginX / 2) + cardPaddingX;
|
aidOffset;
|
||||||
var y = pageMarginY + (Math.floor(count / cardsX) % cardsY) * (ch) + Math.floor(cardMarginY / 2) + cardPaddingY;
|
context.fillRect(0, y, page[0] * ppi, aidWidth);
|
||||||
var w = cardWidth;
|
context.fillRect(0, y + cardHeight, page[0] * ppi, aidWidth);
|
||||||
var h = cardHeight;
|
|
||||||
if (imgIncludesBleedEdge) {
|
|
||||||
context.drawImage(imageList[i], x - cardPaddingX, y - cardPaddingY, w + 2 * cardPaddingX, h + 2 * cardPaddingY);
|
|
||||||
} else {
|
|
||||||
context.fillStyle = bleedEdgeColor;
|
|
||||||
context.fillRect(x - cardPaddingX, y - cardPaddingY, w + 2 * cardPaddingX, h + 2 * cardPaddingY);
|
|
||||||
context.drawImage(imageList[i], x, y, w, h);
|
|
||||||
}
|
|
||||||
if (useCuttingAids) {
|
|
||||||
context.drawImage(cuttingGuides, x, y, w, h);
|
|
||||||
}
|
|
||||||
count ++;
|
|
||||||
} catch {
|
|
||||||
console.log('image failed.');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
//Iterate through every viable space and draw the card there
|
||||||
|
count = 0;
|
||||||
|
for (var i = imageList.length - 1; i >= 0 && count < cardsX * cardsY; i--) {
|
||||||
|
if (imageList[i].width > 1) {
|
||||||
|
try {
|
||||||
|
//Calc upper-left corner of card *image* (accounts for bleed edge and margins)
|
||||||
|
var x =
|
||||||
|
pageMarginX +
|
||||||
|
(count % cardsX) * cw +
|
||||||
|
Math.floor(cardMarginX / 2) +
|
||||||
|
cardPaddingX;
|
||||||
|
var y =
|
||||||
|
pageMarginY +
|
||||||
|
(Math.floor(count / cardsX) % cardsY) * ch +
|
||||||
|
Math.floor(cardMarginY / 2) +
|
||||||
|
cardPaddingY;
|
||||||
|
var w = cardWidth;
|
||||||
|
var h = cardHeight;
|
||||||
|
if (imgIncludesBleedEdge) {
|
||||||
|
context.drawImage(
|
||||||
|
imageList[i],
|
||||||
|
x - cardPaddingX,
|
||||||
|
y - cardPaddingY,
|
||||||
|
w + 2 * cardPaddingX,
|
||||||
|
h + 2 * cardPaddingY
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
context.fillStyle = bleedEdgeColor;
|
||||||
|
context.fillRect(
|
||||||
|
x - cardPaddingX,
|
||||||
|
y - cardPaddingY,
|
||||||
|
w + 2 * cardPaddingX,
|
||||||
|
h + 2 * cardPaddingY
|
||||||
|
);
|
||||||
|
context.drawImage(imageList[i], x, y, w, h);
|
||||||
|
}
|
||||||
|
if (useCuttingAids) {
|
||||||
|
context.drawImage(cuttingGuides, x, y, w, h);
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
} catch {
|
||||||
|
console.log("image failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadCanvas() {
|
function downloadCanvas() {
|
||||||
var download = document.createElement('a');
|
var download = document.createElement("a");
|
||||||
download.download = 'print.png';
|
download.download = "print.png";
|
||||||
download.href = canvas.toDataURL();
|
download.href = canvas.toDataURL();
|
||||||
document.body.appendChild(download);
|
document.body.appendChild(download);
|
||||||
download.click();
|
download.click();
|
||||||
download.remove();
|
download.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadPDF() {
|
function downloadPDF() {
|
||||||
var pageOrientation = 'portrait';
|
var pageOrientation = "portrait";
|
||||||
if (page[0] > page[1]) {
|
if (page[0] > page[1]) {
|
||||||
pageOrientation = 'landscape';
|
pageOrientation = "landscape";
|
||||||
|
}
|
||||||
|
var doc = new jsPDF({
|
||||||
|
orientation: pageOrientation,
|
||||||
|
unit: "in",
|
||||||
|
format: [page[0], page[1]],
|
||||||
|
});
|
||||||
|
//create a single black pixel for default padding
|
||||||
|
var defaultPadding = document.createElement("canvas");
|
||||||
|
defaultPadding.width = 1;
|
||||||
|
defaultPadding.height = 1;
|
||||||
|
var defaultPaddingContext = defaultPadding.getContext("2d");
|
||||||
|
defaultPaddingContext.fillStyle = bleedEdgeColor;
|
||||||
|
defaultPaddingContext.fillRect(0, 0, 1, 1);
|
||||||
|
//Calc actual card size
|
||||||
|
const cw = cardWidth + 2 * cardPaddingX + cardMarginX;
|
||||||
|
const ch = cardHeight + 2 * cardPaddingY + cardMarginY;
|
||||||
|
//Calc number of cards that fit on the sheet
|
||||||
|
const cardsX = Math.floor(page[0] / (cw / ppi));
|
||||||
|
const cardsY = Math.floor(page[1] / (ch / ppi));
|
||||||
|
//Calc page margins
|
||||||
|
const pageMarginX = Math.floor((page[0] * ppi - cardsX * cw) / 2);
|
||||||
|
const pageMarginY = Math.floor((page[1] * ppi - cardsY * ch) / 2);
|
||||||
|
//Draw cutting guides that cover the page
|
||||||
|
var count = 0;
|
||||||
|
if (useCuttingAids) {
|
||||||
|
for (var i = 0; i < cardsX; i++) {
|
||||||
|
var x =
|
||||||
|
pageMarginX +
|
||||||
|
i * cw +
|
||||||
|
Math.floor(cardMarginX / 2) +
|
||||||
|
cardPaddingX -
|
||||||
|
aidOffset;
|
||||||
|
doc.addImage(blackPixel, "PNG", x / ppi, 0, aidWidth / ppi, page[1]);
|
||||||
|
doc.addImage(
|
||||||
|
blackPixel,
|
||||||
|
"PNG",
|
||||||
|
(x + cardWidth) / ppi,
|
||||||
|
0,
|
||||||
|
aidWidth / ppi,
|
||||||
|
page[1]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
var doc = new jsPDF({
|
for (var j = 0; j < cardsY; j++) {
|
||||||
orientation: pageOrientation,
|
var y =
|
||||||
unit: 'in',
|
pageMarginY +
|
||||||
format: [page[0], page[1]]
|
j * ch +
|
||||||
});
|
Math.floor(cardMarginY / 2) +
|
||||||
//create a single black pixel for default padding
|
cardPaddingY -
|
||||||
var defaultPadding = document.createElement("canvas");
|
aidOffset;
|
||||||
defaultPadding.width = 1;
|
doc.addImage(blackPixel, "PNG", 0, y / ppi, page[0], aidWidth / ppi);
|
||||||
defaultPadding.height = 1;
|
doc.addImage(
|
||||||
var defaultPaddingContext = defaultPadding.getContext("2d");
|
blackPixel,
|
||||||
defaultPaddingContext.fillStyle = bleedEdgeColor;
|
"PNG",
|
||||||
defaultPaddingContext.fillRect(0, 0, 1, 1);
|
0,
|
||||||
//Calc actual card size
|
(y + cardHeight) / ppi,
|
||||||
const cw = cardWidth + 2 * cardPaddingX + cardMarginX;
|
page[0],
|
||||||
const ch = cardHeight + 2 * cardPaddingY + cardMarginY;
|
aidWidth / ppi
|
||||||
//Calc number of cards that fit on the sheet
|
);
|
||||||
const cardsX = Math.floor(page[0] / (cw / ppi));
|
|
||||||
const cardsY = Math.floor(page[1] / (ch / ppi));
|
|
||||||
//Calc page margins
|
|
||||||
const pageMarginX = Math.floor((page[0] * ppi - cardsX * cw) / 2);
|
|
||||||
const pageMarginY = Math.floor((page[1] * ppi - cardsY * ch) / 2);
|
|
||||||
//Draw cutting guides that cover the page
|
|
||||||
var count = 0;
|
|
||||||
if (useCuttingAids) {
|
|
||||||
for (var i = 0; i < cardsX; i++) {
|
|
||||||
var x = pageMarginX + i * cw + Math.floor(cardMarginX / 2) + cardPaddingX - aidOffset;
|
|
||||||
doc.addImage(blackPixel, "PNG", x / ppi, 0, aidWidth / ppi, page[1]);
|
|
||||||
doc.addImage(blackPixel, "PNG", (x + cardWidth) / ppi, 0, aidWidth / ppi, page[1]);
|
|
||||||
}
|
|
||||||
for (var j = 0; j < cardsY; j++) {
|
|
||||||
var y = pageMarginY + j * ch + Math.floor(cardMarginY / 2) + cardPaddingY - aidOffset;
|
|
||||||
doc.addImage(blackPixel, "PNG", 0, y / ppi, page[0], aidWidth / ppi);
|
|
||||||
doc.addImage(blackPixel, "PNG", 0, (y + cardHeight) / ppi, page[0], aidWidth / ppi);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//Iterate through every viable space and draw the card there
|
}
|
||||||
count = 0;
|
//Iterate through every viable space and draw the card there
|
||||||
for (var i = imageList.length - 1; i >= 0 && count < cardsX * cardsY; i--) {
|
count = 0;
|
||||||
if (imageList[i].width > 1) {
|
for (var i = imageList.length - 1; i >= 0 && count < cardsX * cardsY; i--) {
|
||||||
try {
|
if (imageList[i].width > 1) {
|
||||||
//Calc upper-left corner of card *image* (accounts for bleed edge and margins)
|
try {
|
||||||
var x = pageMarginX + (count % cardsX) * (cw) + Math.floor(cardMarginX / 2) + cardPaddingX;
|
//Calc upper-left corner of card *image* (accounts for bleed edge and margins)
|
||||||
var y = pageMarginY + (Math.floor(count / cardsX) % cardsY) * (ch) + Math.floor(cardMarginY / 2) + cardPaddingY;
|
var x =
|
||||||
var w = cardWidth;
|
pageMarginX +
|
||||||
var h = cardHeight;
|
(count % cardsX) * cw +
|
||||||
if (imgIncludesBleedEdge) {
|
Math.floor(cardMarginX / 2) +
|
||||||
doc.addImage(imageList[i], "PNG", (x - cardPaddingX) / ppi, (y - cardPaddingY) / ppi, (w + 2 * cardPaddingX) / ppi, (h + 2 * cardPaddingY) / ppi);
|
cardPaddingX;
|
||||||
} else {
|
var y =
|
||||||
doc.addImage(defaultPadding, "PNG", (x - cardPaddingX) / ppi, (y - cardPaddingY) / ppi, (w + 2 * cardPaddingX) / ppi, (h + 2 * cardPaddingY) / ppi);
|
pageMarginY +
|
||||||
doc.addImage(imageList[i], "PNG", x / ppi, y / ppi, w / ppi, h / ppi);
|
(Math.floor(count / cardsX) % cardsY) * ch +
|
||||||
}
|
Math.floor(cardMarginY / 2) +
|
||||||
if (useCuttingAids) {
|
cardPaddingY;
|
||||||
doc.addImage(cuttingGuides, "PNG", x / ppi, y / ppi, w / ppi, h / ppi);
|
var w = cardWidth;
|
||||||
}
|
var h = cardHeight;
|
||||||
count ++;
|
if (imgIncludesBleedEdge) {
|
||||||
} catch {
|
doc.addImage(
|
||||||
console.log('image failed.');
|
imageList[i],
|
||||||
}
|
"PNG",
|
||||||
|
(x - cardPaddingX) / ppi,
|
||||||
|
(y - cardPaddingY) / ppi,
|
||||||
|
(w + 2 * cardPaddingX) / ppi,
|
||||||
|
(h + 2 * cardPaddingY) / ppi
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
doc.addImage(
|
||||||
|
defaultPadding,
|
||||||
|
"PNG",
|
||||||
|
(x - cardPaddingX) / ppi,
|
||||||
|
(y - cardPaddingY) / ppi,
|
||||||
|
(w + 2 * cardPaddingX) / ppi,
|
||||||
|
(h + 2 * cardPaddingY) / ppi
|
||||||
|
);
|
||||||
|
doc.addImage(imageList[i], "PNG", x / ppi, y / ppi, w / ppi, h / ppi);
|
||||||
}
|
}
|
||||||
|
if (useCuttingAids) {
|
||||||
|
doc.addImage(
|
||||||
|
cuttingGuides,
|
||||||
|
"PNG",
|
||||||
|
x / ppi,
|
||||||
|
y / ppi,
|
||||||
|
w / ppi,
|
||||||
|
h / ppi
|
||||||
|
);
|
||||||
|
}
|
||||||
|
count++;
|
||||||
|
} catch {
|
||||||
|
console.log("image failed.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
doc.save('print.pdf');
|
}
|
||||||
|
doc.save("print.pdf");
|
||||||
}
|
}
|
||||||
//Manages page
|
//Manages page
|
||||||
function setPageSize(size = [8.5, 11]) {
|
function setPageSize(size = [8.5, 11]) {
|
||||||
page[0] = parseFloat(size[0]);
|
page[0] = parseFloat(size[0]);
|
||||||
page[1] = parseFloat(size[1]);
|
page[1] = parseFloat(size[1]);
|
||||||
drawSheet();
|
drawSheet();
|
||||||
}
|
}
|
||||||
function changeOrientation() {
|
function changeOrientation() {
|
||||||
setPageSize([page[1], page[0]]);
|
setPageSize([page[1], page[0]]);
|
||||||
}
|
}
|
||||||
//Sets PPI, recalculates card measurements
|
//Sets PPI, recalculates card measurements
|
||||||
function setPPI(inputPPI) {
|
function setPPI(inputPPI) {
|
||||||
var oldPPI = ppi;
|
var oldPPI = ppi;
|
||||||
ppi = parseInt(inputPPI);
|
ppi = parseInt(inputPPI);
|
||||||
var scale = ppi / oldPPI;
|
var scale = ppi / oldPPI;
|
||||||
cardWidth *= scale;
|
cardWidth *= scale;
|
||||||
cardHeight *= scale;
|
cardHeight *= scale;
|
||||||
drawSheet();
|
drawSheet();
|
||||||
}
|
}
|
||||||
//Sets specific card dimensions
|
//Sets specific card dimensions
|
||||||
function setCardSize(size) {
|
function setCardSize(size) {
|
||||||
if (size) {
|
if (size) {
|
||||||
document.querySelector("#cardWidth").value = Math.round(size[0] * ppi);
|
document.querySelector("#cardWidth").value = Math.round(size[0] * ppi);
|
||||||
document.querySelector("#cardHeight").value = Math.round(size[1] * ppi);
|
document.querySelector("#cardHeight").value = Math.round(size[1] * ppi);
|
||||||
}
|
}
|
||||||
cardWidth = parseInt(document.querySelector("#cardWidth").value);
|
cardWidth = parseInt(document.querySelector("#cardWidth").value);
|
||||||
cardHeight = parseInt(document.querySelector("#cardHeight").value);
|
cardHeight = parseInt(document.querySelector("#cardHeight").value);
|
||||||
drawSheet();
|
drawSheet();
|
||||||
}
|
}
|
||||||
function setPaddingSize(size) {
|
function setPaddingSize(size) {
|
||||||
cardPaddingX = parseInt(size);
|
cardPaddingX = parseInt(size);
|
||||||
cardPaddingY = cardPaddingX;
|
cardPaddingY = cardPaddingX;
|
||||||
drawSheet();
|
drawSheet();
|
||||||
}
|
}
|
||||||
function setMarginSize(size) {
|
function setMarginSize(size) {
|
||||||
cardMarginX = parseInt(size);
|
cardMarginX = parseInt(size);
|
||||||
cardMarginY = cardMarginX;
|
cardMarginY = cardMarginX;
|
||||||
drawSheet();
|
drawSheet();
|
||||||
}
|
}
|
||||||
//Sets booleans
|
//Sets booleans
|
||||||
function setBleedEdge(bool) {
|
function setBleedEdge(bool) {
|
||||||
imgIncludesBleedEdge = bool;
|
imgIncludesBleedEdge = bool;
|
||||||
drawSheet();
|
drawSheet();
|
||||||
}
|
}
|
||||||
function setBleedEdgeColor(color) {
|
function setBleedEdgeColor(color) {
|
||||||
bleedEdgeColor = color;
|
bleedEdgeColor = color;
|
||||||
drawSheet();
|
drawSheet();
|
||||||
}
|
}
|
||||||
function setCuttingAids(bool) {
|
function setCuttingAids(bool) {
|
||||||
useCuttingAids = bool;
|
useCuttingAids = bool;
|
||||||
drawSheet();
|
drawSheet();
|
||||||
}
|
}
|
||||||
//Default print configurations
|
//Default print configurations
|
||||||
function saveDefaults() {
|
function saveDefaults() {
|
||||||
var cardObject = {
|
var cardObject = {
|
||||||
ppi:ppi,
|
ppi: ppi,
|
||||||
page:page,
|
page: page,
|
||||||
cardWidth:cardWidth,
|
cardWidth: cardWidth,
|
||||||
cardHeight:cardHeight,
|
cardHeight: cardHeight,
|
||||||
cardMarginX:cardMarginX,
|
cardMarginX: cardMarginX,
|
||||||
cardMarginY:cardMarginY,
|
cardMarginY: cardMarginY,
|
||||||
cardPaddingX:cardPaddingX,
|
cardPaddingX: cardPaddingX,
|
||||||
cardPaddingY:cardPaddingY,
|
cardPaddingY: cardPaddingY,
|
||||||
bleedEdge:imgIncludesBleedEdge,
|
bleedEdge: imgIncludesBleedEdge,
|
||||||
bleedEdgeColor:bleedEdgeColor,
|
bleedEdgeColor: bleedEdgeColor,
|
||||||
cuttingAids:useCuttingAids
|
cuttingAids: useCuttingAids,
|
||||||
}
|
};
|
||||||
localStorage.setItem("cardPrintConfig", JSON.stringify(cardObject));
|
localStorage.setItem("cardPrintConfig", JSON.stringify(cardObject));
|
||||||
}
|
}
|
||||||
function loadDefaults() {
|
function loadDefaults() {
|
||||||
var cardObject = JSON.parse(localStorage.getItem("cardPrintConfig"))
|
var cardObject = JSON.parse(localStorage.getItem("cardPrintConfig"));
|
||||||
if (cardObject && cardObject != {}) {
|
if (cardObject && cardObject != {}) {
|
||||||
ppi = cardObject.ppi;
|
ppi = cardObject.ppi;
|
||||||
document.querySelector("#cardPPI").value = ppi;
|
document.querySelector("#cardPPI").value = ppi;
|
||||||
page = cardObject.page;
|
page = cardObject.page;
|
||||||
cardWidth = cardObject.cardWidth;
|
cardWidth = cardObject.cardWidth;
|
||||||
document.querySelector("#cardWidth").value = cardWidth;
|
document.querySelector("#cardWidth").value = cardWidth;
|
||||||
cardHeight = cardObject.cardHeight;
|
cardHeight = cardObject.cardHeight;
|
||||||
document.querySelector("#cardHeight").value = cardHeight;
|
document.querySelector("#cardHeight").value = cardHeight;
|
||||||
cardMarginX = cardObject.cardMarginX;
|
cardMarginX = cardObject.cardMarginX;
|
||||||
cardMarginY = cardObject.cardMarginY;
|
cardMarginY = cardObject.cardMarginY;
|
||||||
document.querySelector("#cardMargin").value = cardMarginX;
|
document.querySelector("#cardMargin").value = cardMarginX;
|
||||||
cardPaddingX = cardObject.cardPaddingX;
|
cardPaddingX = cardObject.cardPaddingX;
|
||||||
cardPaddingY = cardObject.cardPaddingY;
|
cardPaddingY = cardObject.cardPaddingY;
|
||||||
document.querySelector("#cardPadding").value = cardPaddingX;
|
document.querySelector("#cardPadding").value = cardPaddingX;
|
||||||
imgIncludesBleedEdge = cardObject.bleedEdge;
|
imgIncludesBleedEdge = cardObject.bleedEdge;
|
||||||
document.querySelector("#bleedEdgeCheckbox").checked = imgIncludesBleedEdge;
|
document.querySelector("#bleedEdgeCheckbox").checked = imgIncludesBleedEdge;
|
||||||
bleedEdgeColor = cardObject.bleedEdgeColor || bleedEdgeColor;
|
bleedEdgeColor = cardObject.bleedEdgeColor || bleedEdgeColor;
|
||||||
document.querySelector("#bleedEdgeColor").value = bleedEdgeColor;
|
document.querySelector("#bleedEdgeColor").value = bleedEdgeColor;
|
||||||
useCuttingAids = cardObject.cuttingAids;
|
useCuttingAids = cardObject.cuttingAids;
|
||||||
document.querySelector("#cuttingAidsCheckbox").checked = useCuttingAids;
|
document.querySelector("#cuttingAidsCheckbox").checked = useCuttingAids;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadDefaults();
|
loadDefaults();
|
Reference in New Issue
Block a user