Skip to content

Commit

Permalink
Merge pull request #63 from cass-kazumori/cass_uri_storage
Browse files Browse the repository at this point in the history
Centralize configuration and store all inputs in local storage and the uri
  • Loading branch information
cass-kazumori authored Jan 21, 2024
2 parents d18bb7c + 6235716 commit e96de61
Show file tree
Hide file tree
Showing 13 changed files with 406 additions and 185 deletions.
7 changes: 7 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ <h1>Bookbinder JS</h1>
<center style="font-family:monospace;
padding-top: 0.75em;font-variant-caps: small-caps;">current version: %PACKAGE_VERSION%</center>
</div>
<div class="section" id="settings">
<h2>Settings</h2>
<span class="row">
<button type="button" name="reset_settings" id="reset_settings">Reset</button>
<span data-balloon-length="medium" aria-label="The imposer is able to save and load your current settings via the site URL. Clicking this button will reset those to the default settings." data-balloon-pos="up">ℹ️</span>
</span>
</div>
<form id="bookbinder" name="bookbinder">
<div class="section" id="input">
<h2>File Info</h2>
Expand Down
15 changes: 12 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bookbinder",
"version": "1.2.0",
"version": "1.3.0",
"description": "An app to rearrange PDF pages for printing for bookbinding",
"type": "module",
"scripts": {
Expand All @@ -19,6 +19,7 @@
"file-saver": "^2.0.5",
"jszip": "^3.7.1",
"pdf-lib": "^1.16.0",
"zod": "^3.22.4",
"vite-plugin-package-version": "^1.1.0"
}
}
4 changes: 4 additions & 0 deletions public/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,7 @@ body, .wrapper, #bookbinder {
display: inline-block;
vertical-align: top;
}

#reset_settings {
margin-top: 1em;
}
118 changes: 49 additions & 69 deletions src/book.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,21 @@ import { Signatures } from './signatures.js';
import { PerfectBound } from './perfectbound.js';
import { WackyImposition } from './wacky_imposition.js';
import { PAGE_LAYOUTS, PAGE_SIZES, LINE_LEN } from './constants.js';
import { updatePaperSelectOptionsUnits, updateAddOrRemoveCustomPaperOption, updatePageLayoutInfo} from './utils/renderUtils.js';
import { updatePageLayoutInfo} from './utils/renderUtils.js';
import JSZip from 'jszip';
import { loadConfiguration } from './utils/formUtils.js';

export class Book {
constructor() {
/** @param { import("./models/configuration.js").Configuration } configuration */
constructor(configuration) {
this.inputpdf = null; // string with pdf filepath
this.password = null; // if necessary

this.duplex = false; //FIXME
this.duplexrotate = true;
this.papersize = PAGE_SIZES.A4; // default for europe
this.paper_rotation_90 = false; // make the printed page landscape [for landscaped layouts, results in portait]

this.print_file = 'both'; //valid options: [aggregated, both, signatures]
// valid rotation options: [none, 90cw, 90ccw, out_binding, in_binding]
this.source_rotation = 'none'; // new feature to rotate pages on the sheets 2023/3/09
this.managedDoc = null; // original PDF with the pages rotated per source_rotation - use THIS for laying out pages

this.signatureconfig = [];

this.page_scaling = 'lockratio';
this.page_positioning = 'centered';
this.flyleaf = false;
this.spineoffset = false;
this.format = 'standardsig';
this.sigsize = 4; // preferred signature size
this.customsig = null;
this.signatureconfig = []; // signature configuration

this.input = null; // opened pdf file
this.currentdoc = null; // uploaded PDF [Itext PDFReader object] untouched by source_rotation - use managedDoc for layout
Expand All @@ -43,68 +33,49 @@ export class Book {
this.rearrangedpages = []; // reordered list of page numbers (signatures etc.)
this.filelist = []; // list of ouput filenames and path
this.zip = null;
this.page_layout = PAGE_LAYOUTS.folio;
this.per_sheet = 8; //number of pages to print per sheet.
this.cropmarks = false;
this.cutmarks = false;

this.fore_edge_padding_pt = 0; // (wacky only atm) -- to track buffer space on non-binding edge
this.pack_pages = true; // (wacky only atm) - to track if the white space should be distributed
this.padding_pt = {'top': 0, 'bottom': 0, 'binding': 0, 'fore_edge': 0};

this.update(configuration);
}

update(form) {
this.duplex = form.get('printer_type') == 'duplex';
this.duplexrotate = form.has('rotate_page');
this.paper_rotation_90 = form.has('paper_rotation_90');
this.papersize = PAGE_SIZES[form.get('paper_size')];
if (this.paper_rotation_90) {
this.papersize = [this.papersize[1], this.papersize[0]];
/** @param { import("./models/configuration.js").Configuration } configuration */
update(configuration) {
this.duplex = configuration.printerType === 'duplex';
this.duplexrotate = configuration.rotatePage;
this.paper_rotation_90 = configuration.paperRotation90;
this.papersize = PAGE_SIZES[configuration.paperSize];
if (configuration.paperRotation90) {
this.papersize = [this.papersize[1], this.papersize[0]]
}

this.source_rotation = form.get("source_rotation");

this.print_file = form.get("print_file");
this.page_scaling = form.get("page_scaling");
this.page_positioning = form.get("page_positioning");
this.flyleaf = form.has('flyleaf');
this.cropmarks = form.has('cropmarks');
this.cutmarks = form.has('cutmarks');
this.format = form.get('sig_format');
let siglength = parseInt(form.get('sig_length'), 10);
if (!isNaN(siglength)) {
this.sigsize = siglength;
this.source_rotation = configuration.sourceRotation;
this.print_file = configuration.printFile;
this.page_scaling = configuration.pageScaling;
this.page_positioning = configuration.pagePositioning;
this.flyleaf = configuration.flyleaf;
this.cropmarks = configuration.cropMarks;
this.cutmarks = configuration.cutMarks;
this.format = configuration.sigFormat;
if (configuration.sigFormat === "standardsig") {
this.sigsize = configuration.sigLength;
}
this.customsig = this.format == 'customsig';
this.customsig = this.format === 'customsig';
if (this.customsig) {
this.signatureconfig = [];
let format = form.get('custom_sig');
format.split(/, */).forEach(number => {
let num = parseInt(number, 10);
if (!isNaN(num)) {
this.signatureconfig.push(num);
}
});
this.signatureconfig = configuration.customSigLength;
}

this.page_layout = form.get('pagelayout') == null ? 'folio' : PAGE_LAYOUTS[form.get('pagelayout')];
this.per_sheet = this.page_layout.per_sheet;
this.pack_pages = form.get('wacky_spacing') == 'wacky_pack';
this.fore_edge_padding_pt = this.extractIntFromForm(form, 'fore_edge_padding_pt');
const pageLayout = PAGE_LAYOUTS[configuration.pageLayout]

this.page_layout = pageLayout;
this.per_sheet = pageLayout.per_sheet;
this.pack_pages = configuration.wackySpacing === 'wacky_pack';
this.fore_edge_padding_pt = configuration.foreEdgePaddingPt

this.padding_pt = {
'top' : this.extractIntFromForm(form, 'top_edge_padding_pt'),
'bottom': this.extractIntFromForm(form, 'bottom_edge_padding_pt'),
'binding': this.extractIntFromForm(form, 'binding_edge_padding_pt'),
'fore_edge': this.extractIntFromForm(form, 'main_fore_edge_padding_pt')
'top' : configuration.topEdgePaddingPt,
'bottom': configuration.bottomEdgePaddingPt,
'binding': configuration.bindingEdgePaddingPt,
'fore_edge': configuration.mainForeEdgePaddingPt,
};
updateAddOrRemoveCustomPaperOption();
updatePaperSelectOptionsUnits(); // make sure this goes AFTER the Custom update!
}

extractIntFromForm(form, fieldName) {
let num = parseInt(form.get(fieldName));
return (isNaN(num)) ? 0 : num;
}

/**
Expand Down Expand Up @@ -847,8 +818,17 @@ export class Book {
console.log("After creating signatures, our filelist looks like: ",this.filelist);
}

bundleSettings() {
const currentConfig = loadConfiguration();
const settings = `Imposer settings: ${JSON.stringify(currentConfig, null, 2)}`
+ '\n\n'
+ `Link to the imposer with these settings: ${window.location.href}`
this.zip?.file("settings.txt", settings);
}

saveZip() {
console.log("Saving zip... ");
console.log("Saving zip... ")
this.bundleSettings();
return this.zip.generateAsync({ type: "blob" })
.then(blob => {
console.log(" calling saveAs on ", this.filename);
Expand Down
34 changes: 18 additions & 16 deletions src/book.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,22 @@
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
import { expect, describe, it } from 'vitest';
import { Book } from './book';
import { Book } from "./book";
import { schema } from "./models/configuration";

describe('Book model', () => {
describe("Book model", () => {
// TODO confirm that this is what a newly created book (that is, without any settings changed) should look like; I've copied the result from how it currently works assuming it's working as-intended
const defaultBook = {
inputpdf: null,
password: null,
duplex: false,
duplexrotate: true,
duplex: true,
duplexrotate: false,
papersize: [595, 842],
flyleaf: false,
spineoffset: false,
format: 'standardsig',
format: "standardsig",
sigsize: 4,
customsig: null,
signatureconfig: [],
customsig: false,
input: null,
currentdoc: null,
pagecount: null,
Expand All @@ -33,28 +33,30 @@ describe('Book model', () => {
cols: 1,
per_sheet: 4,
},
per_sheet: 8,
per_sheet: 4,
cropmarks: false,
cutmarks: false,
fore_edge_padding_pt: 0,
managedDoc: null,
pack_pages: true,
padding_pt: {
binding: 0,
bottom: 0,
fore_edge: 0,
top: 0
top: 0,
},
page_positioning: 'centered',
page_scaling: 'lockratio',
managedDoc: null,
page_positioning: "centered",
page_scaling: "lockratio",
paper_rotation_90: false,
source_rotation: "none",
print_file: "both",
source_rotation: "none"

signatureconfig: [],
};
it('returns a new Book', () => {

it("returns a new Book", () => {
const defaultConfiguration = schema.parse({});
const expected = defaultBook;
const actual = new Book();
const actual = new Book(defaultConfiguration);
expect(actual).toEqual(expected);
});
// TODO test update
Expand Down
12 changes: 8 additions & 4 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,24 @@
import { Book } from './book.js';
import { loadForm } from './utils/formUtils.js';
import { handleFileChange, handleInputChange } from './utils/changeHandlers.js';
import { handleGenerateClick, handlePreviewClick } from './utils/clickHandlers.js';
import { handleGenerateClick, handlePreviewClick, handleResetSettingsClick } from './utils/clickHandlers.js';
import { renderPaperSelectOptions } from './utils/renderUtils.js';

window.addEventListener('DOMContentLoaded', () => {
// render dynamic content
renderPaperSelectOptions();
loadForm();
const configuration = loadForm();

// grab DOM elements
const generate = document.getElementById('generate');
const preview = document.getElementById('preview');
const resetSettings = document.getElementById('reset_settings');
const bookbinderForm = document.getElementById('bookbinder');
const fileInput = document.getElementById('input_file');
const inputs = document.querySelectorAll('input, select');

// spin up a book to pass to listeners
const book = new Book();
const book = new Book(configuration);

// add event listeners to grabbed elements
inputs.forEach((input) => {
Expand All @@ -40,5 +41,8 @@ window.addEventListener('DOMContentLoaded', () => {
preview.addEventListener('click', () =>
handlePreviewClick(preview, book)
);

resetSettings.addEventListener('click', () => {
console.log('Resetting settings...');
handleResetSettingsClick(book);
});
});
Loading

0 comments on commit e96de61

Please sign in to comment.