aboutsummaryrefslogtreecommitdiff
path: root/src_js/common.js
diff options
context:
space:
mode:
Diffstat (limited to 'src_js/common.js')
-rw-r--r--src_js/common.js227
1 files changed, 227 insertions, 0 deletions
diff --git a/src_js/common.js b/src_js/common.js
new file mode 100644
index 0000000..6e164f9
--- /dev/null
+++ b/src_js/common.js
@@ -0,0 +1,227 @@
+import * as URI from 'uri-js';
+import FileSaver from 'file-saver';
+import iziToast from 'izitoast';
+import Papa from 'papaparse';
+
+import r from '@hat-open/renderer';
+import * as u from '@hat-open/util';
+
+import * as states from './states';
+
+
+const calculateUrl = URI.resolve(window.location.href, './calculate');
+const generateOutputUrl = URI.resolve(window.location.href, './generate_output');
+
+let panelCounter = 0;
+let itemCounter = 0;
+
+
+export async function calculate() {
+ try {
+ const method = r.get('form', 'method');
+ const params = createCalculateParams();
+ const res = await fetch(`${calculateUrl}?method=${method}`, {
+ method: 'POST',
+ headers: {'Content-Type': 'application/json'},
+ body: JSON.stringify(params)
+ });
+ const result = await res.json();
+ r.change(u.pipe(
+ u.set('result', result),
+ u.set('selected', states.main.selected)
+ ));
+ if (!result)
+ throw 'Could not resolve calculation';
+ showNotification('success', 'New calculation available');
+ } catch (e) {
+ showNotification('error', e);
+ }
+}
+
+
+export async function generateOutput() {
+ try {
+ const result = r.get('result');
+ const res = await fetch(`${generateOutputUrl}?output_type=pdf`, {
+ method: 'POST',
+ headers: {'Content-Type': 'application/json'},
+ body: JSON.stringify(result)
+ });
+ const blob = await res.blob();
+ FileSaver.saveAs(blob, 'output.pdf');
+ } catch (e) {
+ showNotification('error', e);
+ }
+}
+
+
+export async function csvImportPanels() {
+ const panels = await csvImport({
+ name: String,
+ quantity: u.strictParseInt,
+ width: u.strictParseFloat,
+ height: u.strictParseFloat
+ });
+ r.change(['form', 'panels'], x => x.concat(panels));
+}
+
+
+export function csvExportPanels() {
+ const panels = r.get('form', 'panels');
+ const csvData = Papa.unparse(panels);
+ const blob = new Blob([csvData], {type: 'text/csv'});
+ FileSaver.saveAs(blob, 'panels.csv');
+}
+
+
+export async function csvImportItems() {
+ const items = await csvImport({
+ name: String,
+ quantity: u.strictParseInt,
+ width: u.strictParseFloat,
+ height: u.strictParseFloat,
+ can_rotate: u.equals('true')
+ });
+ r.change(['form', 'items'], x => x.concat(items));
+}
+
+
+export function csvExportItems() {
+ const items = r.get('form', 'items');
+ const csvData = Papa.unparse(items);
+ const blob = new Blob([csvData], {type: 'text/csv'});
+ FileSaver.saveAs(blob, 'items.csv');
+}
+
+
+export function addPanel() {
+ panelCounter += 1;
+ const panel = u.set('name', `Panel${panelCounter}`, states.panel);
+ r.change(['form', 'panels'], u.append(panel));
+}
+
+
+export function addItem() {
+ itemCounter += 1;
+ const item = u.set('name', `Item${itemCounter}`, states.item);
+ r.change(['form', 'items'], u.append(item));
+}
+
+
+function createCalculateParams() {
+ const cutWidth = u.strictParseFloat(r.get('form', 'cut_width'));
+ if (cutWidth < 0)
+ throw 'Invalid cut width';
+
+ const panels = {};
+ for (const panel of r.get('form', 'panels')) {
+ if (!panel.name)
+ throw 'Invalid panel name';
+ if (panel.quantity < 1)
+ throw 'Invalid quantity for panel ' + panel.name;
+ if (panel.width <= 0)
+ throw 'Invalid width for panel ' + panel.name;
+ if (panel.height <= 0)
+ throw 'Invalid height for panel ' + panel.name;
+ for (let i = 1; i <= panel.quantity; ++i) {
+ const name = panel.name + ' ' + String(i);
+ if (name in panels)
+ throw 'Duplicate panel name ' + name;
+ panels[name] = {width: panel.width, height: panel.height};
+ }
+ }
+ if (u.equals(panels, {}))
+ throw 'No panels defined';
+
+ const items = {};
+ for (const item of r.get('form', 'items')) {
+ if (!item.name)
+ throw 'Invalid item name';
+ if (item.quantity < 1)
+ throw 'Invalid quantity for item ' + item.name;
+ if (item.width <= 0)
+ throw 'Invalid width for item ' + item.name;
+ if (item.height <= 0)
+ throw 'Invalid height for item ' + item.name;
+ for (let i = 1; i <= item.quantity; ++i) {
+ const name = item.name + ' ' + String(i);
+ if (name in items) {
+ throw 'Duplicate item name ' + name;
+ }
+ items[name] = {
+ width: item.width,
+ height: item.width,
+ can_rotate: item.can_rotate
+ };
+ }
+ }
+ if (u.equals(items, {}))
+ throw 'No items defined';
+
+ return {
+ cut_width: cutWidth,
+ panels: panels,
+ items: items
+ };
+}
+
+
+function showNotification(type, message) {
+ iziToast[type]({message: message});
+}
+
+
+async function csvImport(header) {
+ const file = await loadFile('.csv');
+ if (!file)
+ return [];
+
+ const data = await new Promise(resolve => {
+ Papa.parse(file, {
+ header: true,
+ complete: result => resolve(result.data)
+ });
+ });
+
+ const result = [];
+ for (const i of data) {
+ let element = {};
+ for (const [k, v] of Object.entries(header)) {
+ if (!(k in i)) {
+ element = null;
+ break;
+ }
+ element[k] = v(i[k]);
+ }
+ if (element)
+ result.push(element);
+ }
+ return result;
+}
+
+
+async function loadFile(ext) {
+ const el = document.createElement('input');
+ el.style = 'display: none';
+ el.type = 'file';
+ el.accept = ext;
+ document.body.appendChild(el);
+
+ const promise = new Promise(resolve => {
+ const listener = evt => {
+ resolve(u.get(['files', 0], evt.target));
+ };
+ el.addEventListener('change', listener);
+
+ // TODO blur not fired on close???
+ el.addEventListener('blur', listener);
+
+ el.click();
+ });
+
+ try {
+ return await promise;
+ } finally {
+ document.body.removeChild(el);
+ }
+}