add LTO barcode generator App
This commit is contained in:
parent
8a192bedde
commit
4a227b54bf
|
@ -1,2 +1,3 @@
|
|||
/usr/share/doc/proxmox-backup/proxmox-backup.pdf /usr/share/doc/proxmox-backup/html/proxmox-backup.pdf
|
||||
/usr/share/javascript/extjs /usr/share/doc/proxmox-backup/html/prune-simulator/extjs
|
||||
/usr/share/javascript/extjs /usr/share/doc/proxmox-backup/html/lto-barcode/extjs
|
||||
|
|
|
@ -20,6 +20,19 @@ PRUNE_SIMULATOR_FILES := \
|
|||
prune-simulator/clear-trigger.png \
|
||||
prune-simulator/prune-simulator.js
|
||||
|
||||
LTO_BARCODE_FILES := \
|
||||
lto-barcode/index.html \
|
||||
lto-barcode/code39.js \
|
||||
lto-barcode/prefix-field.js \
|
||||
lto-barcode/label-style.js \
|
||||
lto-barcode/tape-type.js \
|
||||
lto-barcode/paper-size.js \
|
||||
lto-barcode/page-layout.js \
|
||||
lto-barcode/page-calibration.js \
|
||||
lto-barcode/label-list.js \
|
||||
lto-barcode/label-setup.js \
|
||||
lto-barcode/lto-barcode.js
|
||||
|
||||
# Sphinx documentation setup
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
|
@ -79,11 +92,13 @@ onlinehelpinfo:
|
|||
@echo "Build finished. OnlineHelpInfo.js is in $(BUILDDIR)/scanrefs."
|
||||
|
||||
.PHONY: html
|
||||
html: ${GENERATED_SYNOPSIS} images/proxmox-logo.svg custom.css conf.py ${PRUNE_SIMULATOR_FILES}
|
||||
html: ${GENERATED_SYNOPSIS} images/proxmox-logo.svg custom.css conf.py ${PRUNE_SIMULATOR_FILES} ${LTO_BARCODE_FILES}
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
install -m 0644 custom.js custom.css images/proxmox-logo.svg $(BUILDDIR)/html/_static/
|
||||
install -dm 0755 $(BUILDDIR)/html/prune-simulator
|
||||
install -m 0644 ${PRUNE_SIMULATOR_FILES} $(BUILDDIR)/html/prune-simulator
|
||||
install -dm 0755 $(BUILDDIR)/html/lto-barcode
|
||||
install -m 0644 ${LTO_BARCODE_FILES} $(BUILDDIR)/html/lto-barcode
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
|
|
|
@ -172,6 +172,7 @@ html_theme_options = {
|
|||
'Proxmox Homepage': 'https://proxmox.com',
|
||||
'PDF': 'proxmox-backup.pdf',
|
||||
'Prune Simulator' : 'prune-simulator/index.html',
|
||||
'LTO Barcode Generator' : 'lto-barcode/index.html',
|
||||
},
|
||||
|
||||
'sidebar_width': '320px',
|
||||
|
|
|
@ -0,0 +1,351 @@
|
|||
// Code39 barcode generator
|
||||
// see https://en.wikipedia.org/wiki/Code_39
|
||||
|
||||
// IBM LTO Ultrium Cartridge Label Specification
|
||||
// http://www-01.ibm.com/support/docview.wss?uid=ssg1S7000429
|
||||
|
||||
let code39_codes = {
|
||||
"1": ['B', 's', 'b', 'S', 'b', 's', 'b', 's', 'B'],
|
||||
"A": ['B', 's', 'b', 's', 'b', 'S', 'b', 's', 'B'],
|
||||
"K": ['B', 's', 'b', 's', 'b', 's', 'b', 'S', 'B'],
|
||||
"U": ['B', 'S', 'b', 's', 'b', 's', 'b', 's', 'B'],
|
||||
|
||||
"2": ['b', 's', 'B', 'S', 'b', 's', 'b', 's', 'B'],
|
||||
"B": ['b', 's', 'B', 's', 'b', 'S', 'b', 's', 'B'],
|
||||
"L": ['b', 's', 'B', 's', 'b', 's', 'b', 'S', 'B'],
|
||||
"V": ['b', 'S', 'B', 's', 'b', 's', 'b', 's', 'B'],
|
||||
|
||||
"3": ['B', 's', 'B', 'S', 'b', 's', 'b', 's', 'b'],
|
||||
"C": ['B', 's', 'B', 's', 'b', 'S', 'b', 's', 'b'],
|
||||
"M": ['B', 's', 'B', 's', 'b', 's', 'b', 'S', 'b'],
|
||||
"W": ['B', 'S', 'B', 's', 'b', 's', 'b', 's', 'b'],
|
||||
|
||||
"4": ['b', 's', 'b', 'S', 'B', 's', 'b', 's', 'B'],
|
||||
"D": ['b', 's', 'b', 's', 'B', 'S', 'b', 's', 'B'],
|
||||
"N": ['b', 's', 'b', 's', 'B', 's', 'b', 'S', 'B'],
|
||||
"X": ['b', 'S', 'b', 's', 'B', 's', 'b', 's', 'B'],
|
||||
|
||||
"5": ['B', 's', 'b', 'S', 'B', 's', 'b', 's', 'b'],
|
||||
"E": ['B', 's', 'b', 's', 'B', 'S', 'b', 's', 'b'],
|
||||
"O": ['B', 's', 'b', 's', 'B', 's', 'b', 'S', 'b'],
|
||||
"Y": ['B', 'S', 'b', 's', 'B', 's', 'b', 's', 'b'],
|
||||
|
||||
"6": ['b', 's', 'B', 'S', 'B', 's', 'b', 's', 'b'],
|
||||
"F": ['b', 's', 'B', 's', 'B', 'S', 'b', 's', 'b'],
|
||||
"P": ['b', 's', 'B', 's', 'B', 's', 'b', 'S', 'b'],
|
||||
"Z": ['b', 'S', 'B', 's', 'B', 's', 'b', 's', 'b'],
|
||||
|
||||
"7": ['b', 's', 'b', 'S', 'b', 's', 'B', 's', 'B'],
|
||||
"G": ['b', 's', 'b', 's', 'b', 'S', 'B', 's', 'B'],
|
||||
"Q": ['b', 's', 'b', 's', 'b', 's', 'B', 'S', 'B'],
|
||||
"-": ['b', 'S', 'b', 's', 'b', 's', 'B', 's', 'B'],
|
||||
|
||||
"8": ['B', 's', 'b', 'S', 'b', 's', 'B', 's', 'b'],
|
||||
"H": ['B', 's', 'b', 's', 'b', 'S', 'B', 's', 'b'],
|
||||
"R": ['B', 's', 'b', 's', 'b', 's', 'B', 'S', 'b'],
|
||||
".": ['B', 'S', 'b', 's', 'b', 's', 'B', 's', 'b'],
|
||||
|
||||
"9": ['b', 's', 'B', 'S', 'b', 's', 'B', 's', 'b'],
|
||||
"I": ['b', 's', 'B', 's', 'b', 'S', 'B', 's', 'b'],
|
||||
"S": ['b', 's', 'B', 's', 'b', 's', 'B', 'S', 'b'],
|
||||
" ": ['b', 'S', 'B', 's', 'b', 's', 'B', 's', 'b'],
|
||||
|
||||
"0": ['b', 's', 'b', 'S', 'B', 's', 'B', 's', 'b'],
|
||||
"J": ['b', 's', 'b', 's', 'B', 'S', 'B', 's', 'b'],
|
||||
"T": ['b', 's', 'b', 's', 'B', 's', 'B', 'S', 'b'],
|
||||
"*": ['b', 'S', 'b', 's', 'B', 's', 'B', 's', 'b']
|
||||
};
|
||||
|
||||
let colors = [
|
||||
'#BB282E',
|
||||
'#FAE54A',
|
||||
'#9AC653',
|
||||
'#01A5E2',
|
||||
'#9EAAB6',
|
||||
'#D97E35',
|
||||
'#E27B99',
|
||||
'#67A945',
|
||||
'#F6B855',
|
||||
'#705A81'
|
||||
];
|
||||
|
||||
let lto_label_width = 70;
|
||||
let lto_label_height = 17;
|
||||
|
||||
function foreach_label(page_layout, callback) {
|
||||
|
||||
let count = 0;
|
||||
let row = 0;
|
||||
let height = page_layout.margin_top;
|
||||
|
||||
while ((height + page_layout.label_height) <= page_layout.page_height) {
|
||||
|
||||
let column = 0;
|
||||
let width = page_layout.margin_left;
|
||||
|
||||
while ((width + page_layout.label_width) <= page_layout.page_width) {
|
||||
|
||||
callback(column, row, count, width, height);
|
||||
count += 1;
|
||||
|
||||
column += 1;
|
||||
width += page_layout.label_width;
|
||||
width += page_layout.column_spacing;
|
||||
}
|
||||
|
||||
row += 1;
|
||||
height += page_layout.label_height;
|
||||
height += page_layout.row_spacing;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function compute_max_labels(page_layout) {
|
||||
|
||||
let max_labels = 0;
|
||||
foreach_label(page_layout, function() { max_labels += 1; });
|
||||
return max_labels;
|
||||
}
|
||||
|
||||
function svg_label(mode, label, label_type, pagex, pagey, label_borders) {
|
||||
let svg = "";
|
||||
|
||||
if (label.length != 6) {
|
||||
throw "wrong label length";
|
||||
}
|
||||
if (label_type.length != 2) {
|
||||
throw "wrong label_type length";
|
||||
}
|
||||
|
||||
let ratio = 2.75;
|
||||
let parts = 3*ratio + 6; // 3*wide + 6*small;
|
||||
let barcode_width = (lto_label_width/12)*10; // 10*code + 2margin
|
||||
let small = barcode_width/(parts*10 + 9);
|
||||
let code_width = small*parts;
|
||||
let wide = small*ratio;
|
||||
let xpos = pagex + code_width;
|
||||
let height = 12;
|
||||
|
||||
if (mode === 'placeholder') {
|
||||
if (label_borders) {
|
||||
svg += `<rect class='unprintable' x='${pagex}' y='${pagey}' width='${lto_label_width}' height='${lto_label_height}' fill='none' style='stroke:black;stroke-width:0.1;'/>`;
|
||||
}
|
||||
return svg;
|
||||
}
|
||||
if (label_borders) {
|
||||
svg += `<rect x='${pagex}' y='${pagey}' width='${lto_label_width}' height='${lto_label_height}' fill='none' style='stroke:black;stroke-width:0.1;'/>`;
|
||||
}
|
||||
|
||||
if (mode === "color" || mode == "frame") {
|
||||
let w = lto_label_width/8;
|
||||
let h = lto_label_height - height;
|
||||
for (var i = 0; i < 7; i++) {
|
||||
let textx = w/2 + pagex + i*w;
|
||||
let texty = pagey;
|
||||
|
||||
let fill = "none";
|
||||
if (mode === "color" && (i < 6)) {
|
||||
let letter = label.charAt(i);
|
||||
if (letter >= '0' && letter <= '9') {
|
||||
fill = colors[parseInt(letter, 10)];
|
||||
}
|
||||
}
|
||||
|
||||
svg += `<rect x='${textx}' y='${texty}' width='${w}' height='${h}' style='stroke:black;stroke-width:0.2;fill:${fill};'/>`;
|
||||
|
||||
if (i == 6) {
|
||||
textx += 3;
|
||||
texty += 3.7;
|
||||
svg += `<text x='${textx}' y='${texty}' style='font-weight:bold;font-size:3px;font-family:sans-serif;'>${label_type}</text>`;
|
||||
} else {
|
||||
let letter = label.charAt(i);
|
||||
textx += 3.5;
|
||||
texty += 4;
|
||||
svg += `<text x='${textx}' y='${texty}' style='font-weight:bold;font-size:4px;font-family:sans-serif;'>${letter}</text>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let raw_label = `*${label}${label_type}*`;
|
||||
|
||||
for (var i = 0; i < raw_label.length; i++) {
|
||||
let letter = raw_label.charAt(i);
|
||||
|
||||
let code = code39_codes[letter];
|
||||
if (code === undefined) {
|
||||
throw `unable to encode letter '${letter}' with code39`;
|
||||
}
|
||||
|
||||
if (mode === "simple") {
|
||||
let textx = xpos + code_width/2;
|
||||
let texty = pagey + 4;
|
||||
|
||||
if (i > 0 && (i+1) < raw_label.length) {
|
||||
svg += `<text x='${textx}' y='${texty}' style='font-weight:bold;font-size:4px;font-family:sans-serif;'>${letter}</text>`;
|
||||
}
|
||||
}
|
||||
|
||||
for (let c of code) {
|
||||
|
||||
if (c === 's') {
|
||||
xpos += small;
|
||||
continue;
|
||||
}
|
||||
if (c === 'S') {
|
||||
xpos += wide;
|
||||
continue;
|
||||
}
|
||||
|
||||
let w = c === 'B' ? wide : small;
|
||||
let ypos = pagey + lto_label_height - height;
|
||||
|
||||
svg += `<rect x='${xpos}' y='${ypos}' width='${w}' height='${height}' style='fill:black'/>`;
|
||||
xpos = xpos + w;
|
||||
}
|
||||
xpos += small;
|
||||
}
|
||||
|
||||
return svg;
|
||||
}
|
||||
|
||||
function html_page_header() {
|
||||
let html = "<html5>";
|
||||
|
||||
html += "<style>";
|
||||
|
||||
/* no page margins */
|
||||
html += "@page{margin-left: 0px;margin-right: 0px;margin-top: 0px;margin-bottom: 0px;}";
|
||||
/* to hide things on printed page */
|
||||
html += "@media print { .unprintable { visibility: hidden; } }";
|
||||
|
||||
html += "</style>";
|
||||
|
||||
//html += "<body onload='window.print()'>";
|
||||
html += "<body style='background-color: white;'>";
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
function svg_page_header(page_width, page_height) {
|
||||
let svg = "<svg version='1.1' xmlns='http://www.w3.org/2000/svg'";
|
||||
svg += ` width='${page_width}mm' height='${page_height}mm' viewBox='0 0 ${page_width} ${page_height}'>`;
|
||||
|
||||
return svg;
|
||||
}
|
||||
|
||||
function printBarcodePage() {
|
||||
let frame = document.getElementById("print_frame");
|
||||
|
||||
let window = frame.contentWindow;
|
||||
window.print();
|
||||
}
|
||||
|
||||
function generate_barcode_page(target_id, page_layout, label_list, calibration) {
|
||||
|
||||
let svg = svg_page_header(page_layout.page_width, page_layout.page_height);
|
||||
|
||||
let c = calibration;
|
||||
|
||||
console.log(calibration);
|
||||
|
||||
svg += "<g id='barcode_page'";
|
||||
if (c !== undefined) {
|
||||
svg += ` transform='scale(${c.scalex}, ${c.scaley}),translate(${c.offsetx}, ${c.offsety})'`;
|
||||
}
|
||||
svg += '>';
|
||||
|
||||
foreach_label(page_layout, function(column, row, count, xpos, ypos) {
|
||||
|
||||
if (count >= label_list.length) { return; }
|
||||
|
||||
let item = label_list[count];
|
||||
|
||||
svg += svg_label(item.mode, item.label, item.tape_type, xpos, ypos, page_layout.label_borders);
|
||||
});
|
||||
|
||||
svg += "</g>";
|
||||
svg += "</svg>";
|
||||
|
||||
let html = html_page_header();
|
||||
html += svg;
|
||||
html += "</body>";
|
||||
html += "</html>";
|
||||
|
||||
let frame = document.getElementById(target_id);
|
||||
|
||||
setupPrintFrame(frame, page_layout.page_width, page_layout.page_height);
|
||||
|
||||
let fwindow = frame.contentWindow;
|
||||
|
||||
fwindow.document.open();
|
||||
fwindow.document.write(html);
|
||||
fwindow.document.close();
|
||||
}
|
||||
|
||||
function setupPrintFrame(frame, page_width, page_height) {
|
||||
let dpi = 98;
|
||||
|
||||
let dpr = window.devicePixelRatio;
|
||||
if (dpr !== undefined) {
|
||||
dpi = dpi*dpr;
|
||||
}
|
||||
|
||||
let ppmm = dpi/25.4;
|
||||
|
||||
frame.width = page_width*ppmm;
|
||||
frame.height = page_height*ppmm;
|
||||
}
|
||||
|
||||
function generate_calibration_page(target_id, page_layout, calibration) {
|
||||
|
||||
let frame = document.getElementById(target_id);
|
||||
|
||||
setupPrintFrame(frame, page_layout.page_width, page_layout.page_height);
|
||||
|
||||
let svg = svg_page_header( page_layout.page_width, page_layout.page_height);
|
||||
|
||||
svg += "<defs>";
|
||||
svg += "<marker id='endarrow' markerWidth='10' markerHeight='7' ";
|
||||
svg += "refX='10' refY='3.5' orient='auto'><polygon points='0 0, 10 3.5, 0 7' />";
|
||||
svg += "</marker>";
|
||||
|
||||
svg += "<marker id='startarrow' markerWidth='10' markerHeight='7' ";
|
||||
svg += "refX='0' refY='3.5' orient='auto'><polygon points='10 0, 10 7, 0 3.5' />";
|
||||
svg += "</marker>";
|
||||
svg += "</defs>";
|
||||
|
||||
svg += "<rect x='50' y='50' width='100' height='100' style='fill:none;stroke-width:0.05;stroke:rgb(0,0,0)'/>";
|
||||
|
||||
let text_style = "style='font-weight:bold;font-size:4;font-family:sans-serif;'";
|
||||
|
||||
svg += `<text x='10' y='99' ${text_style}>Sx = 50mm</text>`;
|
||||
svg += "<line x1='0' y1='100' x2='50' y2='100' stroke='#000' marker-end='url(#endarrow)' stroke-width='.25'/>";
|
||||
|
||||
svg += `<text x='60' y='99' ${text_style}>Dx = 100mm</text>`;
|
||||
svg += "<line x1='50' y1='100' x2='150' y2='100' stroke='#000' marker-start='url(#startarrow)' marker-end='url(#endarrow)' stroke-width='.25'/>";
|
||||
|
||||
svg += `<text x='142' y='10' ${text_style} writing-mode='tb'>Sy = 50mm</text>`;
|
||||
svg += "<line x1='140' y1='0' x2='140' y2='50' stroke='#000' marker-end='url(#endarrow)' stroke-width='.25'/>";
|
||||
|
||||
svg += `<text x='142' y='60' ${text_style} writing-mode='tb'>Dy = 100mm</text>`;
|
||||
svg += "<line x1='140' y1='50' x2='140' y2='150' stroke='#000' marker-start='url(#startarrow)' marker-end='url(#endarrow)' stroke-width='.25'/>";
|
||||
|
||||
let c = calibration;
|
||||
if (c !== undefined) {
|
||||
svg += `<rect x='50' y='50' width='100' height='100' style='fill:none;stroke-width:0.05;stroke:rgb(255,0,0)' `;
|
||||
svg += `transform='scale(${c.scalex}, ${c.scaley}),translate(${c.offsetx}, ${c.offsety})'/>`;
|
||||
}
|
||||
|
||||
svg += "</svg>";
|
||||
|
||||
let html = html_page_header();
|
||||
html += svg;
|
||||
html += "</body>";
|
||||
html += "</html>";
|
||||
|
||||
let fwindow = frame.contentWindow;
|
||||
|
||||
fwindow.document.open();
|
||||
fwindow.document.write(html);
|
||||
fwindow.document.close();
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<title>Proxmox LTO Barcode Label Generator</title>
|
||||
<link rel="stylesheet" type="text/css" href="extjs/theme-crisp/resources/theme-crisp-all.css">
|
||||
<style>
|
||||
/* fix action column icons */
|
||||
.x-action-col-icon {
|
||||
font-size: 13px;
|
||||
height: 13px;
|
||||
}
|
||||
.x-grid-cell-inner-action-col {
|
||||
padding: 6px 10px 5px;
|
||||
}
|
||||
.x-action-col-icon:before {
|
||||
color: #555;
|
||||
}
|
||||
.x-action-col-icon {
|
||||
color: #21BF4B;
|
||||
}
|
||||
.x-action-col-icon {
|
||||
margin: 0 1px;
|
||||
font-size: 14px;
|
||||
}
|
||||
.x-action-col-icon:before, .x-action-col-icon:after {
|
||||
font-size: 14px;
|
||||
}
|
||||
.x-action-col-icon:hover:before, .x-action-col-icon:hover:after {
|
||||
text-shadow: 1px 1px 1px #AAA;
|
||||
font-weight: 800;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="font-awesome/css/font-awesome.css"/>
|
||||
<script type="text/javascript" src="extjs/ext-all.js"></script>
|
||||
|
||||
<script type="text/javascript" src="code39.js"></script>
|
||||
<script type="text/javascript" src="prefix-field.js"></script>
|
||||
<script type="text/javascript" src="label-style.js"></script>
|
||||
<script type="text/javascript" src="tape-type.js"></script>
|
||||
<script type="text/javascript" src="paper-size.js"></script>
|
||||
<script type="text/javascript" src="page-layout.js"></script>
|
||||
<script type="text/javascript" src="page-calibration.js"></script>
|
||||
<script type="text/javascript" src="label-list.js"></script>
|
||||
<script type="text/javascript" src="label-setup.js"></script>
|
||||
<script type="text/javascript" src="lto-barcode.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,140 @@
|
|||
Ext.define('LabelList', {
|
||||
extend: 'Ext.grid.Panel',
|
||||
alias: 'widget.labelList',
|
||||
|
||||
plugins: {
|
||||
ptype: 'cellediting',
|
||||
clicksToEdit: 1
|
||||
},
|
||||
|
||||
selModel: 'cellmodel',
|
||||
|
||||
store: {
|
||||
field: [
|
||||
'prefix',
|
||||
'tape_type',
|
||||
{
|
||||
type: 'integer',
|
||||
name: 'start',
|
||||
},
|
||||
{
|
||||
type: 'integer',
|
||||
name: 'end',
|
||||
},
|
||||
],
|
||||
data: [],
|
||||
},
|
||||
|
||||
listeners: {
|
||||
validateedit: function(editor, context) {
|
||||
console.log(context.field);
|
||||
console.log(context.value);
|
||||
context.record.set(context.field, context.value);
|
||||
context.record.commit();
|
||||
return true;
|
||||
},
|
||||
},
|
||||
|
||||
columns: [
|
||||
{
|
||||
text: 'Prefix',
|
||||
dataIndex: 'prefix',
|
||||
flex: 1,
|
||||
editor: {
|
||||
xtype: 'prefixfield',
|
||||
allowBlank: false,
|
||||
},
|
||||
renderer: function (value, metaData, record) {
|
||||
console.log(record);
|
||||
if (record.data.mode === 'placeholder') {
|
||||
return "-";
|
||||
}
|
||||
return value;
|
||||
},
|
||||
},
|
||||
{
|
||||
text: 'Type',
|
||||
dataIndex: 'tape_type',
|
||||
flex: 1,
|
||||
editor: {
|
||||
xtype: 'ltoTapeType',
|
||||
allowBlank: false,
|
||||
},
|
||||
renderer: function (value, metaData, record) {
|
||||
console.log(record);
|
||||
if (record.data.mode === 'placeholder') {
|
||||
return "-";
|
||||
}
|
||||
return value;
|
||||
},
|
||||
},
|
||||
{
|
||||
text: 'Mode',
|
||||
dataIndex: 'mode',
|
||||
flex: 1,
|
||||
editor: {
|
||||
xtype: 'ltoLabelStyle',
|
||||
allowBlank: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
text: 'Start',
|
||||
dataIndex: 'start',
|
||||
flex: 1,
|
||||
editor: {
|
||||
xtype: 'numberfield',
|
||||
allowBlank: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
text: 'End',
|
||||
dataIndex: 'end',
|
||||
flex: 1,
|
||||
editor: {
|
||||
xtype: 'numberfield',
|
||||
},
|
||||
renderer: function(value) {
|
||||
if (value === null || value === '' || value === undefined) {
|
||||
return "Fill";
|
||||
}
|
||||
return value;
|
||||
},
|
||||
},
|
||||
{
|
||||
xtype: 'actioncolumn',
|
||||
width: 75,
|
||||
items: [
|
||||
{
|
||||
tooltip: 'Move Up',
|
||||
iconCls: 'fa fa-arrow-up',
|
||||
handler: function(grid, rowIndex) {
|
||||
if (rowIndex < 1) { return; }
|
||||
let store = grid.getStore();
|
||||
let record = store.getAt(rowIndex);
|
||||
store.removeAt(rowIndex);
|
||||
store.insert(rowIndex - 1, record);
|
||||
},
|
||||
},
|
||||
{
|
||||
tooltip: 'Move Down',
|
||||
iconCls: 'fa fa-arrow-down',
|
||||
handler: function(grid, rowIndex) {
|
||||
let store = grid.getStore();
|
||||
if (rowIndex >= store.getCount()) { return; }
|
||||
let record = store.getAt(rowIndex);
|
||||
store.removeAt(rowIndex);
|
||||
store.insert(rowIndex + 1, record);
|
||||
},
|
||||
},
|
||||
{
|
||||
tooltip: 'Delete',
|
||||
iconCls: 'fa fa-scissors',
|
||||
//iconCls: 'fa critical fa-trash-o',
|
||||
handler: function(grid, rowIndex) {
|
||||
grid.getStore().removeAt(rowIndex);
|
||||
},
|
||||
}
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
|
@ -0,0 +1,107 @@
|
|||
Ext.define('LabelSetupPanel', {
|
||||
extend: 'Ext.panel.Panel',
|
||||
alias: 'widget.labelSetupPanel',
|
||||
|
||||
layout: {
|
||||
type: 'hbox',
|
||||
align: 'stretch',
|
||||
pack: 'start',
|
||||
},
|
||||
|
||||
getValues: function() {
|
||||
let me = this;
|
||||
|
||||
let values = {};
|
||||
|
||||
Ext.Array.each(me.query('[isFormField]'), function(field) {
|
||||
let data = field.getSubmitData();
|
||||
Ext.Object.each(data, function(name, val) {
|
||||
let parsed = parseInt(val, 10);
|
||||
values[name] = isNaN(parsed) ? val : parsed;
|
||||
});
|
||||
});
|
||||
|
||||
return values;
|
||||
},
|
||||
|
||||
controller: {
|
||||
xclass: 'Ext.app.ViewController',
|
||||
|
||||
init: function() {
|
||||
let me = this;
|
||||
let view = me.getView();
|
||||
let list = view.down("labelList");
|
||||
let store = list.getStore();
|
||||
store.on('datachanged', function(store) {
|
||||
view.fireEvent("listchanged", store);
|
||||
});
|
||||
store.on('update', function(store) {
|
||||
view.fireEvent("listchanged", store);
|
||||
});
|
||||
},
|
||||
|
||||
onAdd: function() {
|
||||
let list = this.lookupReference('label_list');
|
||||
let view = this.getView();
|
||||
let params = view.getValues();
|
||||
list.getStore().add(params);
|
||||
},
|
||||
},
|
||||
|
||||
items: [
|
||||
{
|
||||
border: false,
|
||||
layout: {
|
||||
type: 'vbox',
|
||||
align: 'stretch',
|
||||
pack: 'start',
|
||||
},
|
||||
items: [
|
||||
{
|
||||
xtype: 'prefixfield',
|
||||
name: 'prefix',
|
||||
value: 'TEST',
|
||||
fieldLabel: 'Prefix',
|
||||
},
|
||||
{
|
||||
xtype: 'ltoTapeType',
|
||||
name: 'tape_type',
|
||||
fieldLabel: 'Type',
|
||||
value: 'L8',
|
||||
},
|
||||
{
|
||||
xtype: 'ltoLabelStyle',
|
||||
name: 'mode',
|
||||
fieldLabel: 'Mode',
|
||||
value: 'color',
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
name: 'start',
|
||||
fieldLabel: 'Start',
|
||||
minValue: 0,
|
||||
allowBlank: false,
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
name: 'end',
|
||||
fieldLabel: 'End',
|
||||
minValue: 0,
|
||||
emptyText: 'Fill',
|
||||
},
|
||||
{
|
||||
xtype: 'button',
|
||||
text: 'Add',
|
||||
handler: 'onAdd',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
margin: "0 0 0 10",
|
||||
xtype: 'labelList',
|
||||
reference: 'label_list',
|
||||
flex: 1,
|
||||
},
|
||||
],
|
||||
});
|
|
@ -0,0 +1,20 @@
|
|||
Ext.define('LtoLabelStyle', {
|
||||
extend: 'Ext.form.field.ComboBox',
|
||||
alias: 'widget.ltoLabelStyle',
|
||||
|
||||
editable: false,
|
||||
|
||||
displayField: 'text',
|
||||
valueField: 'value',
|
||||
queryMode: 'local',
|
||||
|
||||
store: {
|
||||
field: ['value', 'text'],
|
||||
data: [
|
||||
{ value: 'simple', text: "Simple" },
|
||||
{ value: 'color', text: 'Color (frames with color)' },
|
||||
{ value: 'frame', text: 'Frame (no color)' },
|
||||
{ value: 'placeholder', text: 'Placeholder (empty)' },
|
||||
],
|
||||
},
|
||||
});
|
|
@ -0,0 +1,214 @@
|
|||
// FIXME: HACK! Makes scrolling in number spinner work again. fixed in ExtJS >= 6.1
|
||||
if (Ext.isFirefox) {
|
||||
Ext.$eventNameMap.DOMMouseScroll = 'DOMMouseScroll';
|
||||
}
|
||||
|
||||
function draw_labels(target_id, label_list, page_layout, calibration) {
|
||||
|
||||
let max_labels = compute_max_labels(page_layout);
|
||||
|
||||
let count_fixed = 0;
|
||||
let count_fill = 0;
|
||||
|
||||
for (i = 0; i < label_list.length; i++) {
|
||||
let item = label_list[i];
|
||||
if (item.end === null || item.end === '' || item.end === undefined) {
|
||||
count_fill += 1;
|
||||
continue;
|
||||
}
|
||||
if (item.end <= item.start) {
|
||||
count_fixed += 1;
|
||||
continue;
|
||||
}
|
||||
count_fixed += (item.end - item.start) + 1;
|
||||
}
|
||||
|
||||
let rest = max_labels - count_fixed;
|
||||
let fill_size = 1;
|
||||
if (rest >= count_fill) {
|
||||
fill_size = Math.floor(rest/count_fill);
|
||||
}
|
||||
|
||||
let list = [];
|
||||
|
||||
let count_fill_2 = 0;
|
||||
|
||||
for (i = 0; i < label_list.length; i++) {
|
||||
let item = label_list[i];
|
||||
let count;
|
||||
if (item.end === null || item.end === '' || item.end === undefined) {
|
||||
count_fill_2 += 1;
|
||||
if (count_fill_2 === count_fill) {
|
||||
count = rest;
|
||||
} else {
|
||||
count = fill_size;
|
||||
}
|
||||
rest -= count;
|
||||
} else {
|
||||
if (item.end <= item.start) {
|
||||
count = 1;
|
||||
} else {
|
||||
count = (item.end - item.start) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < count; j++) {
|
||||
|
||||
let id = item.start + j;
|
||||
|
||||
if (item.prefix.length == 6) {
|
||||
|
||||
list.push({
|
||||
label: item.prefix,
|
||||
tape_type: item.tape_type,
|
||||
mode: item.mode,
|
||||
id: id,
|
||||
});
|
||||
rest += count - j - 1;
|
||||
break;
|
||||
|
||||
} else {
|
||||
|
||||
let pad_len = 6-item.prefix.length;
|
||||
let label = item.prefix + id.toString().padStart(pad_len, 0);
|
||||
|
||||
if (label.length != 6) {
|
||||
rest += count - j;
|
||||
break;
|
||||
}
|
||||
|
||||
list.push({
|
||||
label: label,
|
||||
tape_type: item.tape_type,
|
||||
mode: item.mode,
|
||||
id: id,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
generate_barcode_page(target_id, page_layout, list, calibration);
|
||||
}
|
||||
|
||||
Ext.define('MainView', {
|
||||
extend: 'Ext.container.Viewport',
|
||||
alias: 'widget.mainview',
|
||||
|
||||
layout: {
|
||||
type: 'vbox',
|
||||
align: 'stretch',
|
||||
pack: 'start',
|
||||
},
|
||||
width: 800,
|
||||
|
||||
controller: {
|
||||
xclass: 'Ext.app.ViewController',
|
||||
|
||||
update_barcode_preview: function() {
|
||||
let me = this;
|
||||
let view = me.getView();
|
||||
let list_view = view.down("labelList");
|
||||
|
||||
let store = list_view.getStore();
|
||||
let label_list = [];
|
||||
store.each((record) => {
|
||||
label_list.push(record.data);
|
||||
});
|
||||
|
||||
let page_layout_view = view.down("pageLayoutPanel");
|
||||
let page_layout = page_layout_view.getValues();
|
||||
|
||||
let calibration_view = view.down("pageCalibration");
|
||||
let page_calibration = calibration_view.getValues();
|
||||
|
||||
draw_labels("print_frame", label_list, page_layout, page_calibration);
|
||||
},
|
||||
|
||||
update_calibration_preview: function() {
|
||||
let me = this;
|
||||
let view = me.getView();
|
||||
let page_layout_view = view.down("pageLayoutPanel");
|
||||
let page_layout = page_layout_view.getValues();
|
||||
|
||||
let calibration_view = view.down("pageCalibration");
|
||||
let page_calibration = calibration_view.getValues();
|
||||
console.log(page_calibration);
|
||||
generate_calibration_page('print_frame', page_layout, page_calibration);
|
||||
},
|
||||
|
||||
control: {
|
||||
labelSetupPanel: {
|
||||
listchanged: function(store) {
|
||||
this.update_barcode_preview();
|
||||
},
|
||||
activate: function() {
|
||||
this.update_barcode_preview();
|
||||
},
|
||||
},
|
||||
pageLayoutPanel: {
|
||||
pagechanged: function(layout) {
|
||||
this.update_barcode_preview();
|
||||
},
|
||||
activate: function() {
|
||||
this.update_barcode_preview();
|
||||
},
|
||||
},
|
||||
pageCalibration: {
|
||||
calibrationchanged: function() {
|
||||
this.update_calibration_preview();
|
||||
},
|
||||
activate: function() {
|
||||
this.update_calibration_preview();
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
items: [
|
||||
{
|
||||
xtype: 'tabpanel',
|
||||
items: [
|
||||
{
|
||||
xtype: 'labelSetupPanel',
|
||||
title: 'Proxmox LTO Barcode Label Generator',
|
||||
bodyPadding: 10,
|
||||
},
|
||||
{
|
||||
xtype: 'pageLayoutPanel',
|
||||
title: 'Page Layout',
|
||||
bodyPadding: 10,
|
||||
},
|
||||
{
|
||||
xtype: 'pageCalibration',
|
||||
title: 'Printer Calibration',
|
||||
bodyPadding: 10,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
xtype: 'panel',
|
||||
layout: "center",
|
||||
title: 'Print Preview',
|
||||
bodyStyle: "background-color: grey;",
|
||||
bodyPadding: 10,
|
||||
html: '<center><iframe id="print_frame" frameBorder="0"></iframe></center>',
|
||||
border: false,
|
||||
flex: 1,
|
||||
scrollable: true,
|
||||
tools:[{
|
||||
type: 'print',
|
||||
tooltip: 'Open Print Dialog',
|
||||
handler: function(event, toolEl, panelHeader) {
|
||||
printBarcodePage();
|
||||
}
|
||||
}],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
Ext.onReady(function() {
|
||||
|
||||
Ext.create('MainView', {
|
||||
renderTo: Ext.getBody(),
|
||||
});
|
||||
});
|
|
@ -0,0 +1,142 @@
|
|||
Ext.define('PageCalibration', {
|
||||
extend: 'Ext.panel.Panel',
|
||||
alias: 'widget.pageCalibration',
|
||||
|
||||
layout: {
|
||||
type: 'hbox',
|
||||
align: 'stretch',
|
||||
pack: 'start',
|
||||
},
|
||||
|
||||
getValues: function() {
|
||||
let me = this;
|
||||
|
||||
let values = {};
|
||||
|
||||
Ext.Array.each(me.query('[isFormField]'), function(field) {
|
||||
if (field.isValid()) {
|
||||
let data = field.getSubmitData();
|
||||
Ext.Object.each(data, function(name, val) {
|
||||
let parsed = parseFloat(val, 10);
|
||||
values[name] = isNaN(parsed) ? val : parsed;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (values.d_x === undefined) { return; }
|
||||
if (values.d_y === undefined) { return; }
|
||||
if (values.s_x === undefined) { return; }
|
||||
if (values.s_y === undefined) { return; }
|
||||
|
||||
scalex = 100/values.d_x;
|
||||
scaley = 100/values.d_y;
|
||||
|
||||
let offsetx = ((50*scalex) - values.s_x)/scalex;
|
||||
let offsety = ((50*scaley) - values.s_y)/scaley;
|
||||
|
||||
return {
|
||||
scalex: scalex,
|
||||
scaley: scaley,
|
||||
offsetx: offsetx,
|
||||
offsety: offsety,
|
||||
};
|
||||
},
|
||||
|
||||
controller: {
|
||||
xclass: 'Ext.app.ViewController',
|
||||
|
||||
control: {
|
||||
'field': {
|
||||
change: function() {
|
||||
let view = this.getView();
|
||||
let param = view.getValues();
|
||||
view.fireEvent("calibrationchanged", param);
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
items: [
|
||||
{
|
||||
border: false,
|
||||
layout: {
|
||||
type: 'vbox',
|
||||
align: 'stretch',
|
||||
pack: 'start',
|
||||
},
|
||||
items: [
|
||||
{
|
||||
xtype: 'displayfield',
|
||||
value: 'a4',
|
||||
fieldLabel: 'Start Offset Sx (mm)',
|
||||
labelWidth: 150,
|
||||
value: 50,
|
||||
},
|
||||
{
|
||||
xtype: 'displayfield',
|
||||
value: 'a4',
|
||||
fieldLabel: 'Length Dx (mm)',
|
||||
labelWidth: 150,
|
||||
value: 100,
|
||||
},
|
||||
{
|
||||
xtype: 'displayfield',
|
||||
value: 'a4',
|
||||
fieldLabel: 'Start Offset Sy (mm)',
|
||||
labelWidth: 150,
|
||||
value: 50,
|
||||
},
|
||||
{
|
||||
xtype: 'displayfield',
|
||||
value: 'a4',
|
||||
fieldLabel: 'Length Dy (mm)',
|
||||
labelWidth: 150,
|
||||
value: 100,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
border: false,
|
||||
margin: '0 0 0 20',
|
||||
layout: {
|
||||
type: 'vbox',
|
||||
align: 'stretch',
|
||||
pack: 'start',
|
||||
},
|
||||
items: [
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
value: 'a4',
|
||||
name: 's_x',
|
||||
fieldLabel: 'Meassured Start Offset Sx (mm)',
|
||||
allowBlank: false,
|
||||
labelWidth: 200,
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
value: 'a4',
|
||||
name: 'd_x',
|
||||
fieldLabel: 'Meassured Length Dx (mm)',
|
||||
allowBlank: false,
|
||||
labelWidth: 200,
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
value: 'a4',
|
||||
name: 's_y',
|
||||
fieldLabel: 'Meassured Start Offset Sy (mm)',
|
||||
allowBlank: false,
|
||||
labelWidth: 200,
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
value: 'a4',
|
||||
name: 'd_y',
|
||||
fieldLabel: 'Meassured Length Dy (mm)',
|
||||
allowBlank: false,
|
||||
labelWidth: 200,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
})
|
|
@ -0,0 +1,167 @@
|
|||
Ext.define('PageLayoutPanel', {
|
||||
extend: 'Ext.panel.Panel',
|
||||
alias: 'widget.pageLayoutPanel',
|
||||
|
||||
layout: {
|
||||
type: 'hbox',
|
||||
align: 'stretch',
|
||||
pack: 'start',
|
||||
},
|
||||
|
||||
getValues: function() {
|
||||
let me = this;
|
||||
|
||||
let values = {};
|
||||
|
||||
Ext.Array.each(me.query('[isFormField]'), function(field) {
|
||||
if (field.isValid()) {
|
||||
let data = field.getSubmitData();
|
||||
Ext.Object.each(data, function(name, val) {
|
||||
values[name] = val;
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let paper_size = values.paper_size || 'a4';
|
||||
|
||||
let param = Ext.apply({}, paper_sizes[paper_size]);
|
||||
if (param === undefined) {
|
||||
throw `unknown paper size ${paper_size}`;
|
||||
}
|
||||
|
||||
param.paper_size = paper_size;
|
||||
|
||||
Ext.Object.each(values, function(name, val) {
|
||||
let parsed = parseFloat(val, 10);
|
||||
param[name] = isNaN(parsed) ? val : parsed;
|
||||
});
|
||||
|
||||
return param;
|
||||
},
|
||||
|
||||
controller: {
|
||||
xclass: 'Ext.app.ViewController',
|
||||
|
||||
control: {
|
||||
'paperSize': {
|
||||
change: function(field, paper_size) {
|
||||
let view = this.getView();
|
||||
let defaults = paper_sizes[paper_size];
|
||||
|
||||
let names = [
|
||||
'label_width',
|
||||
'label_height',
|
||||
'margin_left',
|
||||
'margin_top',
|
||||
'column_spacing',
|
||||
'row_spacing',
|
||||
];
|
||||
for (i = 0; i < names.length; i++) {
|
||||
let name = names[i];
|
||||
let f = view.down(`field[name=${name}]`);
|
||||
let v = defaults[name];
|
||||
if (v != undefined) {
|
||||
f.setValue(v);
|
||||
f.setDisabled(defaults.fixed);
|
||||
} else {
|
||||
f.setDisabled(false);
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
'field': {
|
||||
change: function() {
|
||||
let view = this.getView();
|
||||
let param = view.getValues();
|
||||
view.fireEvent("pagechanged", param);
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
items: [
|
||||
{
|
||||
border: false,
|
||||
layout: {
|
||||
type: 'vbox',
|
||||
align: 'stretch',
|
||||
pack: 'start',
|
||||
},
|
||||
items: [
|
||||
{
|
||||
xtype: 'paperSize',
|
||||
name: 'paper_size',
|
||||
value: 'a4',
|
||||
fieldLabel: 'Paper Size',
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
name: 'label_width',
|
||||
fieldLabel: 'Label width',
|
||||
minValue: 70,
|
||||
allowBlank: false,
|
||||
value: 70,
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
name: 'label_height',
|
||||
fieldLabel: 'Label height',
|
||||
minValue: 17,
|
||||
allowBlank: false,
|
||||
value: 17,
|
||||
},
|
||||
{
|
||||
xtype: 'checkbox',
|
||||
name: 'label_borders',
|
||||
fieldLabel: 'Label borders',
|
||||
value: true,
|
||||
inputValue: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
border: false,
|
||||
margin: '0 0 0 10',
|
||||
layout: {
|
||||
type: 'vbox',
|
||||
align: 'stretch',
|
||||
pack: 'start',
|
||||
},
|
||||
items: [
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
name: 'margin_left',
|
||||
fieldLabel: 'Left margin',
|
||||
minValue: 0,
|
||||
allowBlank: false,
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
name: 'margin_top',
|
||||
fieldLabel: 'Top margin',
|
||||
minValue: 0,
|
||||
allowBlank: false,
|
||||
value: 4,
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
name: 'column_spacing',
|
||||
fieldLabel: 'Column spacing',
|
||||
minValue: 0,
|
||||
allowBlank: false,
|
||||
value: 0,
|
||||
},
|
||||
{
|
||||
xtype: 'numberfield',
|
||||
name: 'row_spacing',
|
||||
fieldLabel: 'Row spacing',
|
||||
minValue: 0,
|
||||
allowBlank: false,
|
||||
value: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
});
|
|
@ -0,0 +1,49 @@
|
|||
let paper_sizes = {
|
||||
a4: {
|
||||
comment: 'A4 (plain)',
|
||||
page_width: 210,
|
||||
page_height: 297,
|
||||
},
|
||||
letter: {
|
||||
comment: 'Letter (plain)',
|
||||
page_width: 215.9,
|
||||
page_height: 279.4,
|
||||
},
|
||||
avery3420: {
|
||||
fixed: true,
|
||||
comment: 'Avery Zweckform 3420',
|
||||
page_width: 210,
|
||||
page_height: 297,
|
||||
label_width: 70,
|
||||
label_height: 17,
|
||||
margin_left: 0,
|
||||
margin_top: 4,
|
||||
column_spacing: 0,
|
||||
row_spacing: 0,
|
||||
},
|
||||
}
|
||||
|
||||
function paper_size_combo_data() {
|
||||
let data = [];
|
||||
|
||||
for (let [key, value] of Object.entries(paper_sizes)) {
|
||||
data.push({ value: key, text: value.comment });
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
Ext.define('PaperSize', {
|
||||
extend: 'Ext.form.field.ComboBox',
|
||||
alias: 'widget.paperSize',
|
||||
|
||||
editable: false,
|
||||
|
||||
displayField: 'text',
|
||||
valueField: 'value',
|
||||
queryMode: 'local',
|
||||
|
||||
store: {
|
||||
field: ['value', 'text'],
|
||||
data: paper_size_combo_data(),
|
||||
},
|
||||
});
|
|
@ -0,0 +1,15 @@
|
|||
Ext.define('PrefixField', {
|
||||
extend: 'Ext.form.field.Text',
|
||||
alias: 'widget.prefixfield',
|
||||
|
||||
maxLength: 6,
|
||||
allowBlank: false,
|
||||
|
||||
maskRe: /([A-Za-z]+)$/,
|
||||
|
||||
listeners: {
|
||||
change: function(field) {
|
||||
field.setValue(field.getValue().toUpperCase());
|
||||
},
|
||||
},
|
||||
});
|
|
@ -0,0 +1,23 @@
|
|||
Ext.define('LtoTapeType', {
|
||||
extend: 'Ext.form.field.ComboBox',
|
||||
alias: 'widget.ltoTapeType',
|
||||
|
||||
editable: false,
|
||||
|
||||
displayField: 'text',
|
||||
valueField: 'value',
|
||||
queryMode: 'local',
|
||||
|
||||
store: {
|
||||
field: ['value', 'text'],
|
||||
data: [
|
||||
{ value: 'L8', text: "LTO-8" },
|
||||
{ value: 'L7', text: "LTO-7" },
|
||||
{ value: 'L6', text: "LTO-6" },
|
||||
{ value: 'L5', text: "LTO-5" },
|
||||
{ value: 'L4', text: "LTO-4" },
|
||||
{ value: 'L3', text: "LTO-3" },
|
||||
{ value: 'CU', text: "Cleaning Unit" },
|
||||
],
|
||||
},
|
||||
});
|
Loading…
Reference in New Issue