fix save functionality

This commit is contained in:
gowthaman.b 2023-11-27 13:41:29 +05:30
parent ed2157f250
commit df097c3023
5 changed files with 193 additions and 172 deletions

View File

@ -19,7 +19,7 @@ input:required:invalid, input:focus:invalid { border-color: #d9534f; }
border: 1px solid transparent; border: 1px solid transparent;
border-color: #e7e7e7 !important; border-color: #e7e7e7 !important;
border-radius: 4px; border-radius: 4px;
height: 623px; height: 80vh;
overflow: auto; overflow: auto;
} }
@ -47,4 +47,7 @@ input:required:invalid, input:focus:invalid { border-color: #d9534f; }
.panel-heading-blur { .panel-heading-blur {
background-color: #215480 !important; background-color: #215480 !important;
border-color: #215480 !important; border-color: #215480 !important;
}
table {
width: 100%;
} }

View File

@ -1,16 +1,11 @@
chrome.app.runtime.onLaunched.addListener(function () { chrome.app.runtime.onLaunched.addListener(function () {
chrome.app.window.create('main.html', { chrome.app.window.create('main.html', {
frame: 'none', frame: 'chrome'
bounds: {
width: 535,
height: 768
},
resizable: false,
}); });
}); });
chrome.runtime.onInstalled.addListener(function (details) { chrome.runtime.onInstalled.addListener(function (details) {
if (details.reason == "install" || details.reason == "update") { if (details.reason === "install" || details.reason === "update") {
chrome.storage.local.set({ chrome.storage.local.set({
isOn: true, isOn: true,
density: '8', density: '8',
@ -23,8 +18,8 @@ chrome.runtime.onInstalled.addListener(function (details) {
keepTcpSocket: false, keepTcpSocket: false,
saveLabels: false, saveLabels: false,
filetype: '1', filetype: '1',
path: null, path: "/tmp",
counter: 0 counter: 0
}); });
} }
}); });

View File

@ -1,16 +1,16 @@
// const store = require('./store'); const {app, BrowserWindow, dialog, ipcRenderer} = require('electron')
var $ = require('jquery'); const fs = require('fs');
const $ = require('jquery');
global.$ = $; global.$ = $;
global.jQuery = $; global.jQuery = $;
var net = require('net'); const net = require('net');
var socketId, clientSocketInfo; let socketId, clientSocketInfo;
var server; let server;
var configs = {}; const configs = {};
var retainEntry = null; const pathEntry = null;
var pathEntry = null;
var defaults ={ const defaults = {
isOn: true, isOn: true,
density: '8', density: '8',
width: '4', width: '4',
@ -26,22 +26,24 @@ var defaults ={
counter: 0 counter: 0
}; };
$(function() { $(function () {
$(window).bind('focus blur', function() { $(window).bind('focus blur', function () {
$('#panel-head').toggleClass('panel-heading-blur'); $('#panel-head').toggleClass('panel-heading-blur');
}); });
// todo only on first run // todo only on first run
if (!global.localStorage.getItem('isOn')) { if (!global.localStorage.getItem('isOn')) {
Object.entries(defaults).forEach(function([k,v]) { Object.entries(defaults).forEach(function ([k, v]) {
global.localStorage.setItem(k,v); if (global.localStorage.getItem(k)) {
global.localStorage.setItem(k, v);
}
}); });
} }
}); });
$(document).ready(function() { $(document).ready(function () {
Object.keys(defaults).forEach(function(k) { Object.keys(defaults).forEach(function (k) {
configs[k] = global.localStorage.getItem(k); configs[k] = global.localStorage.getItem(k);
}); });
@ -49,51 +51,52 @@ $(document).ready(function() {
initEvents(); initEvents();
}); });
function getSize (width, height) { function getSize(width, height) {
var defaultWidth = 386; const defaultWidth = 386;
var factor = width / height; const factor = width / height;
return { return {
width: defaultWidth, width: defaultWidth,
height: defaultWidth / factor height: defaultWidth / factor
}; };
} }
function saveLabel (blob, ext) { async function saveLabel(blob, ext) {
items = global.localStorage.getItem('counter'); let items = global.localStorage.getItem('counter');
let counter = parseInt(items.counter);
const fileName = `LBL${pad(counter, 6)}.${ext}`;
chrome.fileSystem.getWritableEntry(pathEntry, function(entry) { global.localStorage.setItem('counter', ++counter);
var counter = parseInt(items.counter);
var fileName = 'LBL' + pad(counter, 6) + '.' + ext;
global.localStorage.setItem('counter', ++counter); // Creating and Writing to the sample.txt file
fs.writeFile(fileName,
entry.getFile(fileName, { create: true }, function(entry) { new Uint8Array(await blob.arrayBuffer()),
entry.createWriter(function(writer) { function (err) {
writer.write(blob); if (err) throw err;
notify('Label <b>{0}</b> saved in folder <b>{1}</b>'.format(fileName, $('#txt-path').val()), 'floppy-saved', 'info', 1000); notify('Label <b>{0}</b> saved in folder <b>{1}</b>'.format(fileName, $('#txt-path').val()), 'floppy-saved', 'info', 1000);
});
}); });
});
} }
function savePdf (zpl, density, width, height) { async function 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(density, width, height), true); let r1 = await fetch(api_url, {
xhr.setRequestHeader('Accept', 'application/pdf'); method: "POST",
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); body: zpl,
xhr.responseType = 'blob'; headers: {
xhr.onload = function(e) { 'Content-Type': 'application/x-www-form-urlencoded',
if (this.status == 200) { 'Accept': 'application/pdf'
saveLabel(this.response, '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'; z = z || '0';
n = n + ''; n = n + '';
return n.length >= width ? n : new Array(width - n.length + 1).join(z) + 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 {Number} glyphicon Notification icon
// @param {String} type Notification type // @param {String} type Notification type
// @param {Number} delay Notification fade out delay in ms // @param {Number} delay Notification fade out delay in ms
function notify (text, glyphicon, type, delay) { function notify(text, glyphicon, type, delay) {
var log = $('<p>' + text + '</p>').text(); const log = $('<p>' + text + '</p>').text();
if (type == 'danger') { if (type === 'danger') {
console.error(log); console.error(log);
} else { } else {
console.info(log); console.info(log);
} }
$('.bottom-left').notify({ $('.bottom-left').notify({
message: { html: text }, message: {html: text},
glyphicon: glyphicon, glyphicon: glyphicon,
type: type, type: type,
fadeOut: { fadeOut: {
@ -122,8 +125,44 @@ function notify (text, glyphicon, type, delay) {
}).show(); }).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 // Start tcp server and listen on configuret host/port
function startTcpServer () { function startTcpServer() {
if (server != undefined) { if (server != undefined) {
return; return;
} }
@ -137,7 +176,7 @@ function startTcpServer () {
// if (result == 0) { // if (result == 0) {
notify('Printer started on Host: <b>{0}</b> Port: <b>{1}</b>'.format(configs.host, configs.port)); notify('Printer started on Host: <b>{0}</b> Port: <b>{1}</b>'.format(configs.host, configs.port));
// chrome.sockets.tcpServer.onAccept.addListener(function (clientInfo) { // chrome.sockets.tcpServer.onAccept.addListener(function (clientInfo) {
server.on('connection', function(sock) { server.on('connection', function (sock) {
// socketId = sock; // socketId = sock;
console.log('CONNECTED: ' + sock.remoteAddress + ':' + sock.remotePort); console.log('CONNECTED: ' + sock.remoteAddress + ':' + sock.remotePort);
clientSocketInfo = { clientSocketInfo = {
@ -145,79 +184,43 @@ function startTcpServer () {
peerPort: sock.remotePort peerPort: sock.remotePort
}; };
sock.on('data', function(data) { sock.on('data', async function (data) {
// chrome.sockets.tcp.onReceive.addListener(function (info) { // chrome.sockets.tcp.onReceive.addListener(function (info) {
notify('{0} bytes received from Client: <b>{1}</b> Port: <b>{2}</b>'.format(data.length, clientSocketInfo.peerAddress, clientSocketInfo.peerPort), 'print', 'info', 1000); notify('{0} bytes received from Client: <b>{1}</b> Port: <b>{2}</b>'.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) { if (!configs.keepTcpSocket) {
server.close(); server.close();
} }
var factor = (configs.unit == '1') ? 1 : (configs.unit == '2') ? 2.54 : 25.4; const factor = (configs.unit === '1') ? 1 : (configs.unit === '2') ? 2.54 : 25.4;
var width = parseFloat(configs.width) / factor; const width = parseFloat(configs.width) / factor;
var height = parseFloat(configs.height) / factor; const height = parseFloat(configs.height) / factor;
for (var i in zpls) { for (let zpl of zpls) {
var zpl = zpls[i];
if (!(!zpl || !zpl.length)) { if (!(!zpl || !zpl.length)) {
zpl += '^XZ'; zpl += '^XZ';
} else {
console.warn(`zpl = ${zpl}, seems invalid`)
continue
} }
// if (configs['saveLabels']) { let api_url = `https://api.labelary.com/v1/printers/${configs.density}dpmm/labels/${width}x${height}/0`;
// if (configs['filetype'] == '2') { console.warn("configs", configs["saveLabels"], "fileType", configs["fileType"])
// savePdf(zpl, configs.density, width, height); 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(); await displayAndSaveImage(api_url, zpl, width, height, savePng);
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);
};
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: <b>{0}</b> Port: <b>{1}</b>'.format(configs.host, configs.port), 'exclamation-sign', 'danger', 4000);
// }
}); });
// });
} }
// Stop tcp server // Stop tcp server
function stopTcpServer () { function stopTcpServer() {
if (server == undefined) { if (server == undefined) {
return; return;
} }
@ -231,8 +234,8 @@ function stopTcpServer () {
} }
// Init ui events // Init ui events
function initEvents () { function initEvents() {
$('.btn-toggle').click(function() { $('.btn-toggle').click(function () {
toggleSwitch(this); toggleSwitch(this);
if ($('#btn-on').hasClass('active')) { if ($('#btn-on').hasClass('active')) {
@ -242,12 +245,12 @@ function initEvents () {
} }
}); });
$('#btn-remove').click(function() { $('#btn-remove').click(function () {
var size = $('.thumbnail').length; const size = $('.thumbnail').length;
if (size > 0) { if (size > 0) {
var label = size == 1 ? 'label' : 'labels'; const label = size === 1 ? 'label' : 'labels';
bootbox.confirm('Are you sure to remove {0} {1}?'.format(size, label), function(result) { bootbox.confirm('Are you sure to remove {0} {1}?'.format(size, label), function (result) {
if (result) { if (result) {
$('.thumbnail').remove(); $('.thumbnail').remove();
notify('{0} {1} successfully removed.'.format(size, label), 'trash', 'info'); 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')); global.localStorage.setItem('isOn', $('#btn-on').hasClass('active'));
window.close(); window.close();
stopTcpServer(); stopTcpServer();
}); });
$('#density li > a').click(function() { $('#density li > a').click(function () {
var btn = $('#btn-density'); const btn = $('#btn-density');
btn.attr('aria-valuenow', $(this).parent().attr('aria-valuenow')); btn.attr('aria-valuenow', $(this).parent().attr('aria-valuenow'));
btn.html($(this).text() + ' <span class="caret"></span>'); btn.html($(this).text() + ' <span class="caret"></span>');
}); });
$('#unit li > a').click(function() { $('#unit li > a').click(function () {
var btn = $('#btn-unit'); const btn = $('#btn-unit');
btn.attr('aria-valuenow', $(this).parent().attr('aria-valuenow')); btn.attr('aria-valuenow', $(this).parent().attr('aria-valuenow'));
btn.html($(this).text() + ' <span class="caret"></span>'); btn.html($(this).text() + ' <span class="caret"></span>');
}); });
$('#filetype li > a').click(function() { $('#filetype li > a').click(function () {
var btn = $('#btn-filetype'); const btn = $('#btn-filetype');
btn.attr('aria-valuenow', $(this).parent().attr('aria-valuenow')); btn.attr('aria-valuenow', $(this).parent().attr('aria-valuenow'));
btn.html($(this).text() + ' <span class="caret"></span>'); btn.html($(this).text() + ' <span class="caret"></span>');
}); });
$('#txt-path').keydown(function(e) { $('#txt-path').keydown(function (e) {
e.preventDefault(); e.preventDefault();
}); });
$('#configsForm').submit(function(e) { $('#configsForm').submit(function (e) {
e.preventDefault(); e.preventDefault();
saveConfigs(); saveConfigs();
}); });
$('#settings-window').on('shown.bs.modal', function() { $('#settings-window').on('shown.bs.modal', function () {
if ($('#btn-on').hasClass('active')) { if ($('#btn-on').hasClass('active')) {
toggleSwitch('.btn-toggle'); toggleSwitch('.btn-toggle');
stopTcpServer(); stopTcpServer();
} }
}); });
$('#ckb-saveLabels').change(function() { $('#ckb-saveLabels').change(function () {
var disabled = !$(this).is(':checked'); const disabled = !$(this).is(':checked');
$('#btn-filetype').prop('disabled', disabled); $('#btn-filetype').prop('disabled', disabled);
$('#btn-path').prop('disabled', disabled); $('#btn-path').prop('disabled', disabled);
$('#txt-path').prop('disabled', disabled); $('#txt-path').prop('disabled', disabled);
}); });
$('#btn-path').click(function() { $('#btn-path').click(function (e) {
// chrome.fileSystem.chooseEntry({ // chrome.fileSystem.chooseEntry({
// type: 'openDirectory', // type: 'openDirectory',
// }, function (entry) { // }, function (entry) {
@ -316,13 +327,20 @@ function initEvents () {
// retainEntry = chrome.fileSystem.retainEntry(entry); // 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 // Toggle on/off switch
// @param {Dom Object} btn Button group to toggle // @param {Dom Object} btn Button group to toggle
function toggleSwitch (btn) { function toggleSwitch(btn) {
$(btn).find('.btn').toggleClass('active'); $(btn).find('.btn').toggleClass('active');
if ($(btn).find('.btn-primary').length > 0) { if ($(btn).find('.btn-primary').length > 0) {
@ -333,8 +351,8 @@ function toggleSwitch (btn) {
} }
// Svae configs in local storage // Svae configs in local storage
function saveConfigs () { function saveConfigs() {
for (var key in configs) { for (let key in configs) {
if (key == 'density') { if (key == 'density') {
configs[key] = $('#btn-density').attr('aria-valuenow'); configs[key] = $('#btn-density').attr('aria-valuenow');
} else if (key == 'unit') { } else if (key == 'unit') {
@ -346,14 +364,14 @@ function saveConfigs () {
} else if (key == 'keepTcpSocket') { } else if (key == 'keepTcpSocket') {
configs[key] = $('#ckb-keep-tcp-socket').is(':checked'); configs[key] = $('#ckb-keep-tcp-socket').is(':checked');
} else if (key == 'path') { } else if (key == 'path') {
configs[key] = retainEntry; configs[key] = document.getElementById('txt-path').value;
} else { } else {
configs[key] = $('#' + key).val(); configs[key] = $('#' + key).val();
} }
} }
Object.entries(configs).forEach(function([k,v]) { Object.entries(configs).forEach(function ([k, v]) {
global.localStorage.setItem(k,v); global.localStorage.setItem(k, v);
}); });
$('#settings-window').modal('hide'); $('#settings-window').modal('hide');
@ -361,53 +379,45 @@ function saveConfigs () {
} }
// Init/load configs from local storage // Init/load configs from local storage
function initConfigs () { function initConfigs() {
for (var key in configs) { console.log('init', configs)
if (key == 'density') { for (let key in configs) {
if (key === 'density') {
initDropDown('density', configs[key]); initDropDown('density', configs[key]);
} else if (key == 'unit') { } else if (key === 'unit') {
initDropDown('unit', configs[key]); initDropDown('unit', configs[key]);
} else if (key == 'filetype') { } else if (key === 'filetype') {
initDropDown('filetype', configs[key]); initDropDown('filetype', configs[key]);
} else if (key == 'saveLabels') { } else if (key === 'saveLabels') {
$('#ckb-saveLabels').prop('checked', configs[key]); $('#ckb-saveLabels').prop('checked', configs[key]);
var disabled = !configs[key]; const disabled = !configs[key];
$('#btn-filetype').prop('disabled', disabled); $('#btn-filetype').prop('disabled', disabled);
$('#btn-path').prop('disabled', disabled); $('#btn-path').prop('disabled', disabled);
$('#txt-path').prop('disabled', disabled); $('#txt-path').prop('disabled', disabled);
} else if (key == 'isOn' && configs[key]) { } else if (key === 'isOn' && configs[key]) {
toggleSwitch('.btn-toggle'); toggleSwitch('.btn-toggle');
startTcpServer(); startTcpServer();
} else if (key == 'keepTcpSocket') { } else if (key === 'keepTcpSocket') {
$('#ckb-keep-tcp-socket').prop('checked', configs[key]); $('#ckb-keep-tcp-socket').prop('checked', configs[key]);
} else if (key == 'path' && configs[key]) { } else if (key === 'path' && configs[key]) {
retainEntry = configs[key]; document.getElementById('txt-path').value = configs[key]
// chrome.fileSystem.restoreEntry(configs[key], function (entry) {
// pathEntry = entry;
// initPath(entry);
// });
} else { } else {
$('#' + key).val(configs[key]); $('#' + key).val(configs[key]);
} }
} }
} }
function initPath (entry) {
// chrome.fileSystem.getDisplayPath(entry, function (path) {
// $('#txt-path').val(path);
// });
}
function initDropDown (btnId, value) { function initDropDown(btnId, value) {
var btn = $('#btn-' + btnId); const btn = $('#btn-' + btnId);
var text = $('#' + btnId).find('li[aria-valuenow=' + value + '] > a').html(); const text = $('#' + btnId).find('li[aria-valuenow=' + value + '] > a').html();
btn.attr('aria-valuenow', value); btn.attr('aria-valuenow', value);
btn.html(text + ' <span class="caret"></span>'); btn.html(text + ' <span class="caret"></span>');
} }
// Prototype for string.format method // Prototype for string.format method
String.prototype.format = function() { String.prototype.format = function () {
var s = this, let s = this,
i = arguments.length; i = arguments.length;
while (i--) { while (i--) {

View File

@ -188,11 +188,11 @@
<td> <td>
<div class="input-group" style="padding-right: 10px;"> <div class="input-group" style="padding-right: 10px;">
<span class="input-group-addon">Path</span> <span class="input-group-addon">Path</span>
<input id="txt-path" name="path" class="form-control" type="text" required disabled> <input id="txt-path" name="path" class="form-control" type="text" disabled required>
</div> </div>
</td> </td>
<td> <td>
<button id="btn-path" type="button" class="btn btn-default" disabled>Choose</button> <button id="btn-path" type="button" class="btn btn-default">Choose</button>
</td> </td>
</tr> </tr>
</table> </table>

21
main.js
View File

@ -1,25 +1,38 @@
require('update-electron-app')() 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(); if (require('electron-squirrel-startup')) return app.quit();
let win
const createWindow = () => { const createWindow = () => {
const win = new BrowserWindow({ win = new BrowserWindow({
width: 535, width: 535,
height: 768, height: 768,
frame: false, frame: false,
resizable: false, resizable: true,
icon: __dirname + '/icons/512x512.png', icon: __dirname + '/icons/512x512.png',
webPreferences: { webPreferences: {
nodeIntegration: true, nodeIntegration: true,
contextIsolation: false, contextIsolation: false,
enableRemoteModule: true,
} }
}) })
win.loadFile('ZplPrinter/main.html') 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(() => { app.whenReady().then(() => {
createWindow() createWindow()
}) })