diff --git a/ZplPrinter/css/style.css b/ZplPrinter/css/style.css index 20f7780..d18f82f 100644 --- a/ZplPrinter/css/style.css +++ b/ZplPrinter/css/style.css @@ -19,7 +19,7 @@ input:required:invalid, input:focus:invalid { border-color: #d9534f; } border: 1px solid transparent; border-color: #e7e7e7 !important; border-radius: 4px; - height: 623px; + height: 80vh; overflow: auto; } @@ -47,4 +47,7 @@ input:required:invalid, input:focus:invalid { border-color: #d9534f; } .panel-heading-blur { background-color: #215480 !important; border-color: #215480 !important; +} +table { + width: 100%; } \ No newline at end of file diff --git a/ZplPrinter/js/background.js b/ZplPrinter/js/background.js index b8583e6..4a59f16 100644 --- a/ZplPrinter/js/background.js +++ b/ZplPrinter/js/background.js @@ -1,16 +1,11 @@ chrome.app.runtime.onLaunched.addListener(function () { chrome.app.window.create('main.html', { - frame: 'none', - bounds: { - width: 535, - height: 768 - }, - resizable: false, + frame: 'chrome' }); }); chrome.runtime.onInstalled.addListener(function (details) { - if (details.reason == "install" || details.reason == "update") { + if (details.reason === "install" || details.reason === "update") { chrome.storage.local.set({ isOn: true, density: '8', @@ -23,8 +18,8 @@ chrome.runtime.onInstalled.addListener(function (details) { keepTcpSocket: false, saveLabels: false, filetype: '1', - path: null, - counter: 0 + path: "/tmp", + counter: 0 }); } }); \ No newline at end of file diff --git a/ZplPrinter/js/main.js b/ZplPrinter/js/main.js index f2d97c9..0b275b0 100644 --- a/ZplPrinter/js/main.js +++ b/ZplPrinter/js/main.js @@ -1,16 +1,16 @@ -// const store = require('./store'); -var $ = require('jquery'); +const {app, BrowserWindow, dialog, ipcRenderer} = require('electron') +const fs = require('fs'); +const $ = require('jquery'); global.$ = $; global.jQuery = $; -var net = require('net'); +const net = require('net'); -var socketId, clientSocketInfo; -var server; -var configs = {}; -var retainEntry = null; -var pathEntry = null; +let socketId, clientSocketInfo; +let server; +const configs = {}; +const pathEntry = null; -var defaults ={ +const defaults = { isOn: true, density: '8', width: '4', @@ -26,22 +26,24 @@ var defaults ={ counter: 0 }; -$(function() { - $(window).bind('focus blur', function() { +$(function () { + $(window).bind('focus blur', function () { $('#panel-head').toggleClass('panel-heading-blur'); }); // todo only on first run if (!global.localStorage.getItem('isOn')) { - Object.entries(defaults).forEach(function([k,v]) { - global.localStorage.setItem(k,v); + Object.entries(defaults).forEach(function ([k, v]) { + if (global.localStorage.getItem(k)) { + global.localStorage.setItem(k, v); + } }); } }); -$(document).ready(function() { - Object.keys(defaults).forEach(function(k) { +$(document).ready(function () { + Object.keys(defaults).forEach(function (k) { configs[k] = global.localStorage.getItem(k); }); @@ -49,51 +51,52 @@ $(document).ready(function() { initEvents(); }); -function getSize (width, height) { - var defaultWidth = 386; +function getSize(width, height) { + const defaultWidth = 386; - var factor = width / height; + const factor = width / height; return { width: defaultWidth, height: defaultWidth / factor }; } -function saveLabel (blob, ext) { - items = global.localStorage.getItem('counter'); +async function saveLabel(blob, ext) { + let items = global.localStorage.getItem('counter'); + let counter = parseInt(items.counter); + const fileName = `LBL${pad(counter, 6)}.${ext}`; - chrome.fileSystem.getWritableEntry(pathEntry, function(entry) { - var counter = parseInt(items.counter); - var fileName = 'LBL' + pad(counter, 6) + '.' + ext; + global.localStorage.setItem('counter', ++counter); - global.localStorage.setItem('counter', ++counter); - - entry.getFile(fileName, { create: true }, function(entry) { - entry.createWriter(function(writer) { - writer.write(blob); - notify('Label {0} saved in folder {1}'.format(fileName, $('#txt-path').val()), 'floppy-saved', 'info', 1000); - - }); + // Creating and Writing to the sample.txt file + fs.writeFile(fileName, + new Uint8Array(await blob.arrayBuffer()), + function (err) { + if (err) throw err; + notify('Label {0} saved in folder {1}'.format(fileName, $('#txt-path').val()), 'floppy-saved', 'info', 1000); }); - }); } -function savePdf (zpl, density, width, height) { - var xhr = new XMLHttpRequest(); - xhr.open('POST', 'http://api.labelary.com/v1/printers/{0}dpmm/labels/{1}x{2}/0/'.format(density, width, height), true); - xhr.setRequestHeader('Accept', 'application/pdf'); - xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); - xhr.responseType = 'blob'; - xhr.onload = function(e) { - if (this.status == 200) { - saveLabel(this.response, 'pdf'); +async function fetchAndSavePDF(api_url, zpl) { + + let r1 = await fetch(api_url, { + method: "POST", + body: zpl, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Accept': 'application/pdf' } - }; + }) - xhr.send(zpl); + if (r1.ok && r1.status === 200) { + let blob = await r1.blob() + await saveLabel(blob, 'pdf'); + } else { + console.log('error in fetching pdf', `status = ${r1.status}`, await r1.text(), `zpl=${zpl}`) + } } -function pad (n, width, z) { +function pad(n, width, z) { z = z || '0'; n = n + ''; return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n; @@ -104,16 +107,16 @@ function pad (n, width, z) { // @param {Number} glyphicon Notification icon // @param {String} type Notification type // @param {Number} delay Notification fade out delay in ms -function notify (text, glyphicon, type, delay) { - var log = $('

' + text + '

').text(); - if (type == 'danger') { +function notify(text, glyphicon, type, delay) { + const log = $('

' + text + '

').text(); + if (type === 'danger') { console.error(log); } else { console.info(log); } $('.bottom-left').notify({ - message: { html: text }, + message: {html: text}, glyphicon: glyphicon, type: type, fadeOut: { @@ -122,8 +125,44 @@ function notify (text, glyphicon, type, delay) { }).show(); } +async function displayAndSaveImage(api_url, zpl, width, height, savePng) { + let r1 = await fetch(api_url, { + method: "POST", + body: zpl, + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + } + }) + + if (r1.ok && r1.status === 200) { + const blob = await r1.blob() + const size = getSize(width, height); + const img = document.createElement('img'); + img.setAttribute('height', size.height); + img.setAttribute('width', size.width); + img.setAttribute('class', 'thumbnail'); + img.onload = function (e) { + window.URL.revokeObjectURL(img.src); + }; + + img.src = window.URL.createObjectURL(blob); + + $('#label').prepend(img); + const offset = size.height + 20; + $('#label').css({'top': `-${offset}px`}); + $('#label').animate({'top': '0px'}, 1500); + + if (savePng) { + await saveLabel(blob, "png") + } + + } else { + console.log('error in fetching image', `status = ${r1.status}`, await r1.text(), `zpl = ${zpl}`) + } +} + // Start tcp server and listen on configuret host/port -function startTcpServer () { +function startTcpServer() { if (server != undefined) { return; } @@ -137,7 +176,7 @@ function startTcpServer () { // if (result == 0) { notify('Printer started on Host: {0} Port: {1}'.format(configs.host, configs.port)); // chrome.sockets.tcpServer.onAccept.addListener(function (clientInfo) { - server.on('connection', function(sock) { + server.on('connection', function (sock) { // socketId = sock; console.log('CONNECTED: ' + sock.remoteAddress + ':' + sock.remotePort); clientSocketInfo = { @@ -145,79 +184,43 @@ function startTcpServer () { peerPort: sock.remotePort }; - sock.on('data', function(data) { + sock.on('data', async function (data) { // chrome.sockets.tcp.onReceive.addListener(function (info) { notify('{0} bytes received from Client: {1} Port: {2}'.format(data.length, clientSocketInfo.peerAddress, clientSocketInfo.peerPort), 'print', 'info', 1000); - var zpls = String.fromCharCode.apply(null, data).split(/\^XZ/); + const zpls = String.fromCharCode.apply(null, data).split(/\^XZ/); if (!configs.keepTcpSocket) { server.close(); } - var factor = (configs.unit == '1') ? 1 : (configs.unit == '2') ? 2.54 : 25.4; - var width = parseFloat(configs.width) / factor; - var height = parseFloat(configs.height) / factor; + const factor = (configs.unit === '1') ? 1 : (configs.unit === '2') ? 2.54 : 25.4; + const width = parseFloat(configs.width) / factor; + const height = parseFloat(configs.height) / factor; - for (var i in zpls) { - var zpl = zpls[i]; + for (let zpl of zpls) { if (!(!zpl || !zpl.length)) { zpl += '^XZ'; + } else { + console.warn(`zpl = ${zpl}, seems invalid`) + continue } - // if (configs['saveLabels']) { - // if (configs['filetype'] == '2') { - // savePdf(zpl, configs.density, width, height); - // } - // } + let api_url = `https://api.labelary.com/v1/printers/${configs.density}dpmm/labels/${width}x${height}/0`; + console.warn("configs", configs["saveLabels"], "fileType", configs["fileType"]) + let savePdf = configs['saveLabels'] && configs['filetype'] === '2'; + let savePng = configs['saveLabels'] && configs['filetype'] === '1'; + if (savePdf) { + await fetchAndSavePDF(api_url, zpl); + } - var xhr = new XMLHttpRequest(); - xhr.open('POST', 'http://api.labelary.com/v1/printers/{0}dpmm/labels/{1}x{2}/0/'.format(configs.density, width, height), true); - xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); - xhr.responseType = 'blob'; - xhr.onload = function(e) { - if (this.status == 200) { - var blob = this.response; - // if (configs['saveLabels']) { - // if (configs['filetype'] == '1') { - // saveLabel(blob, 'png'); - // } - // } - var size = getSize(width, height); - var img = document.createElement('img'); - img.setAttribute('height', size.height); - img.setAttribute('width', size.width); - img.setAttribute('class', 'thumbnail'); - img.onload = function(e) { - window.URL.revokeObjectURL(img.src); - }; + await displayAndSaveImage(api_url, zpl, width, height, savePng); - img.src = window.URL.createObjectURL(blob); - - $('#label').prepend(img); - var offset = size.height + 20; - $('#label').css({ 'top': '-' + offset + 'px' }); - $('#label').animate({ 'top': '0px' }, 1500); - } - }; - xhr.send(zpl); } }); - // chrome.sockets.tcp.getInfo(clientInfo.clientSocketId, function (socketInfo) { - // clientSocketInfo = socketInfo; - // chrome.sockets.tcp.update(clientInfo.clientSocketId,{bufferSize: parseInt(configs.bufferSize) }, function(){ - // chrome.sockets.tcp.setPaused(clientInfo.clientSocketId, false); - // }); - // }); - // }); - // } else { - // socketId = undefined; - // toggleSwitch('.btn-toggle'); - // notify('Error occurs while creating Printer on Host: {0} Port: {1}'.format(configs.host, configs.port), 'exclamation-sign', 'danger', 4000); - // } + }); - // }); } // Stop tcp server -function stopTcpServer () { +function stopTcpServer() { if (server == undefined) { return; } @@ -231,8 +234,8 @@ function stopTcpServer () { } // Init ui events -function initEvents () { - $('.btn-toggle').click(function() { +function initEvents() { + $('.btn-toggle').click(function () { toggleSwitch(this); if ($('#btn-on').hasClass('active')) { @@ -242,12 +245,12 @@ function initEvents () { } }); - $('#btn-remove').click(function() { - var size = $('.thumbnail').length; + $('#btn-remove').click(function () { + const size = $('.thumbnail').length; if (size > 0) { - var label = size == 1 ? 'label' : 'labels'; - bootbox.confirm('Are you sure to remove {0} {1}?'.format(size, label), function(result) { + const label = size === 1 ? 'label' : 'labels'; + bootbox.confirm('Are you sure to remove {0} {1}?'.format(size, label), function (result) { if (result) { $('.thumbnail').remove(); notify('{0} {1} successfully removed.'.format(size, label), 'trash', 'info'); @@ -255,56 +258,64 @@ function initEvents () { }); } }); + $('#btn-save-label').click(function () { + const size = $('.thumbnail').length; - $('#btn-close').click(function() { + if (size > 0) { + const label = size === 1 ? 'label' : 'labels'; + + } + }); + + $('#btn-close').click(function () { global.localStorage.setItem('isOn', $('#btn-on').hasClass('active')); window.close(); stopTcpServer(); }); - $('#density li > a').click(function() { - var btn = $('#btn-density'); + $('#density li > a').click(function () { + const btn = $('#btn-density'); btn.attr('aria-valuenow', $(this).parent().attr('aria-valuenow')); btn.html($(this).text() + ' '); }); - $('#unit li > a').click(function() { - var btn = $('#btn-unit'); + $('#unit li > a').click(function () { + const btn = $('#btn-unit'); btn.attr('aria-valuenow', $(this).parent().attr('aria-valuenow')); btn.html($(this).text() + ' '); }); - $('#filetype li > a').click(function() { - var btn = $('#btn-filetype'); + $('#filetype li > a').click(function () { + const btn = $('#btn-filetype'); btn.attr('aria-valuenow', $(this).parent().attr('aria-valuenow')); btn.html($(this).text() + ' '); }); - $('#txt-path').keydown(function(e) { + $('#txt-path').keydown(function (e) { e.preventDefault(); }); - $('#configsForm').submit(function(e) { + $('#configsForm').submit(function (e) { e.preventDefault(); saveConfigs(); }); - $('#settings-window').on('shown.bs.modal', function() { + $('#settings-window').on('shown.bs.modal', function () { if ($('#btn-on').hasClass('active')) { toggleSwitch('.btn-toggle'); stopTcpServer(); } }); - $('#ckb-saveLabels').change(function() { - var disabled = !$(this).is(':checked'); + $('#ckb-saveLabels').change(function () { + const disabled = !$(this).is(':checked'); $('#btn-filetype').prop('disabled', disabled); $('#btn-path').prop('disabled', disabled); $('#txt-path').prop('disabled', disabled); }); - $('#btn-path').click(function() { + $('#btn-path').click(function (e) { // chrome.fileSystem.chooseEntry({ // type: 'openDirectory', // }, function (entry) { @@ -316,13 +327,20 @@ function initEvents () { // retainEntry = chrome.fileSystem.retainEntry(entry); // } // }); - }); + e.preventDefault() + ipcRenderer.send('select-dirs') + ipcRenderer.on('selected-dirs', (event, response) => { + if (response && typeof Array.isArray(response)) { + document.getElementById('txt-path').value = response[0] + } + }) + }); } // Toggle on/off switch // @param {Dom Object} btn Button group to toggle -function toggleSwitch (btn) { +function toggleSwitch(btn) { $(btn).find('.btn').toggleClass('active'); if ($(btn).find('.btn-primary').length > 0) { @@ -333,8 +351,8 @@ function toggleSwitch (btn) { } // Svae configs in local storage -function saveConfigs () { - for (var key in configs) { +function saveConfigs() { + for (let key in configs) { if (key == 'density') { configs[key] = $('#btn-density').attr('aria-valuenow'); } else if (key == 'unit') { @@ -346,14 +364,14 @@ function saveConfigs () { } else if (key == 'keepTcpSocket') { configs[key] = $('#ckb-keep-tcp-socket').is(':checked'); } else if (key == 'path') { - configs[key] = retainEntry; + configs[key] = document.getElementById('txt-path').value; } else { configs[key] = $('#' + key).val(); } } - Object.entries(configs).forEach(function([k,v]) { - global.localStorage.setItem(k,v); + Object.entries(configs).forEach(function ([k, v]) { + global.localStorage.setItem(k, v); }); $('#settings-window').modal('hide'); @@ -361,53 +379,45 @@ function saveConfigs () { } // Init/load configs from local storage -function initConfigs () { - for (var key in configs) { - if (key == 'density') { +function initConfigs() { + console.log('init', configs) + for (let key in configs) { + if (key === 'density') { initDropDown('density', configs[key]); - } else if (key == 'unit') { + } else if (key === 'unit') { initDropDown('unit', configs[key]); - } else if (key == 'filetype') { + } else if (key === 'filetype') { initDropDown('filetype', configs[key]); - } else if (key == 'saveLabels') { + } else if (key === 'saveLabels') { $('#ckb-saveLabels').prop('checked', configs[key]); - var disabled = !configs[key]; + const disabled = !configs[key]; $('#btn-filetype').prop('disabled', disabled); $('#btn-path').prop('disabled', disabled); $('#txt-path').prop('disabled', disabled); - } else if (key == 'isOn' && configs[key]) { + } else if (key === 'isOn' && configs[key]) { toggleSwitch('.btn-toggle'); startTcpServer(); - } else if (key == 'keepTcpSocket') { + } else if (key === 'keepTcpSocket') { $('#ckb-keep-tcp-socket').prop('checked', configs[key]); - } else if (key == 'path' && configs[key]) { - retainEntry = configs[key]; - // chrome.fileSystem.restoreEntry(configs[key], function (entry) { - // pathEntry = entry; - // initPath(entry); - // }); + } else if (key === 'path' && configs[key]) { + document.getElementById('txt-path').value = configs[key] } else { $('#' + key).val(configs[key]); } } } -function initPath (entry) { - // chrome.fileSystem.getDisplayPath(entry, function (path) { - // $('#txt-path').val(path); - // }); -} -function initDropDown (btnId, value) { - var btn = $('#btn-' + btnId); - var text = $('#' + btnId).find('li[aria-valuenow=' + value + '] > a').html(); +function initDropDown(btnId, value) { + const btn = $('#btn-' + btnId); + const text = $('#' + btnId).find('li[aria-valuenow=' + value + '] > a').html(); btn.attr('aria-valuenow', value); btn.html(text + ' '); } // Prototype for string.format method -String.prototype.format = function() { - var s = this, +String.prototype.format = function () { + let s = this, i = arguments.length; while (i--) { diff --git a/ZplPrinter/main.html b/ZplPrinter/main.html index 0e1d76e..f5121e3 100644 --- a/ZplPrinter/main.html +++ b/ZplPrinter/main.html @@ -188,11 +188,11 @@
Path - +
- + diff --git a/main.js b/main.js index aac7b64..6d8cd95 100644 --- a/main.js +++ b/main.js @@ -1,25 +1,38 @@ require('update-electron-app')() -const { app, BrowserWindow } = require('electron') +const { app, BrowserWindow, dialog, ipcMain } = require('electron') +const path = require("path") if (require('electron-squirrel-startup')) return app.quit(); - +let win const createWindow = () => { - const win = new BrowserWindow({ + win = new BrowserWindow({ width: 535, height: 768, frame: false, - resizable: false, + resizable: true, icon: __dirname + '/icons/512x512.png', webPreferences: { nodeIntegration: true, contextIsolation: false, + enableRemoteModule: true, } }) win.loadFile('ZplPrinter/main.html') + if(process.env.NODE_ENV === "development"){ + win.webContents.openDevTools() + } } +ipcMain.on('select-dirs', async (event, arg) => { + const result = await dialog.showOpenDialog(win, { + properties: ['openDirectory'] + }) + event.sender.send('selected-dirs', result.filePaths) + +}) + app.whenReady().then(() => { createWindow() })