Справица:DiagramGenerator.js
Пређи на навигацију
Пређи на претрагу
/* eslint {"max-statements": ["error", 100]} */
(function() {
'use strict';
var fileContents = {};
var signals = [
'MOST1_2',
'MOST1_3',
'MOST2_1',
'MOST3_2',
'rdCPU',
'wrCPU',
'ldMDR',
'mxMDR',
'MDRout1',
'eMDR',
'ldMAR',
'incMAR',
'eMAR',
'ldDWL',
'ldDWH',
'DWout2',
'wrGPR',
'GPRout1',
'ldGPRAR',
'incGPRAR',
'ldSP',
'SPout2',
'incSP',
'DECSP',
'ldCW',
'CWout3',
'ADDout2',
'ldPC',
'incPC',
'PCHout3',
'PCLout3',
'PCout1',
'ldIR0',
'ldIR1',
'ldIR2',
'ldIR3',
'IRPOMout3',
'IRJAout2',
'IRDAout3',
'IRBRout3',
'add',
'sub',
'inc',
'dec',
'and',
'or',
'xor',
'not',
'ALUout1',
'ldAB',
'ABout3',
'shr',
'shl',
'ldBB',
'BBout2',
'ldAW',
'AWout3',
'AWHout3',
'ldBW',
'BWout2',
'ldPSWH',
'ldPSWL',
'ldN',
'ldZ',
'ldC',
'ldV',
'ldL',
'stPSWI',
'clPSWI',
'stPSWT',
'clPSWT',
'PSWHout3',
'PSWLout3',
'clSTART',
'ldIMR',
'IMRout2',
'ldBR',
'IVTDSPout3',
'ldIVTP',
'IVTPout1',
'UINTout3',
'UEXTout3',
'stPRCOD',
'stPRADR',
'stPRINS',
'clPRCOD',
'clPRADR',
'clPRINS',
'clPRINM',
'clINTR',
'stPSWR',
'clPSWR'
];
var BranchType = {
NONE: 'none',
CONDITIONAL: 'conditional',
UNCONDITIONAL: 'unconditional',
BRADR: 'bradr',
BROPR: 'bropr'
};
var CONDITIONAL_BRANCH = /^br\s*\(\s*if\s+(\S+)\s+then\s+(\S+)\s*\)$/;
var UNCONDITIONAL_BRANCH = /^br\s+(\S+)$/;
var MAX_LINE_LENGTH = 22;
var FIELDS = [
['Ime i prezime', 'Indeks', 'Potpis'],
['Naziv', 'Datum', 'Strana']
];
function updateSubmitEnabled() {
if (fileContents.microcode && fileContents.configuration) {
$('#diagram-generator-submit').removeAttr('disabled');
} else {
$('#diagram-generator-submit').attr('disabled', '');
}
}
function fileLoaded(id) {
fileContents[id] = this.result;
updateSubmitEnabled();
}
function updateFile(event) {
var input = event.target;
delete fileContents[input.id];
var files = input.files;
if (files.length === 0) {
return;
}
var reader = new FileReader();
reader.addEventListener('load', fileLoaded.bind(reader, input.id));
reader.readAsText(files[0]);
updateSubmitEnabled();
}
function parseConfig(config) {
try {
return config.split('\n').map(function(line) {
return line.replace(/\/\/.*/g, '').trim();
}).filter(Boolean).map(function(line) {
return JSON.parse('[' + line + ']');
});
} catch (error) {
console.error(error);
return null;
}
}
function findConfig(config, prefix) {
return config.filter(function(line) {
return !line.slice(0, prefix.length).some(function(value, index) {
return value !== prefix[index];
});
}).map(function(line) {
return line.slice(prefix.length);
});
}
function prepareLine(line) {
return line
.toLowerCase()
.replace(/\(/g, ' ( ')
.replace(/\)/g, ' ) ')
.replace(/\s+/g, ' ')
.replace(/if !/g, 'if #')
.replace(/(.*?)!.*/g, '$1')
.replace(/(.*?);.*/, '$1')
.replace(/\t/g, ' ')
.replace(/\s+:/g, ': ')
.replace(/\s+/g, ' ')
.trim();
}
function parseAddress(line) {
if (line === '') {
return -1;
}
var addressLine = line.split(' ')[0];
if (addressLine.endsWith(':') || !addressLine.startsWith('madr')) {
return -1;
}
var address = parseInt(addressLine.substring(4), 16);
if (isNaN(address)) {
return -1;
}
return address;
}
function parseLabels(line) {
var labels = [];
var splitLine = line.split(' ');
for (var i = 0, l = splitLine.length; i < l; ++i) {
if (!splitLine[i].endsWith(':')) {
break;
}
var label = splitLine[i].slice(0, -1);
if (!labels.includes(label)) {
labels.push(label);
}
}
return labels;
}
function parseConditions(config) {
return findConfig(config, ['CONTRODC']).filter(function(option) {
return option[1];
}).map(function(option) {
var segments = option[1].split('.');
return option[2] + segments[segments.length - 1].toLowerCase();
});
}
function parseLine(comment, line, config) {
var preparedLine = prepareLine(line);
var instruction = {
address: parseAddress(preparedLine),
comment: comment,
line: line
};
var unparsedLine = preparedLine;
if (instruction.address >= 0) {
unparsedLine = unparsedLine.split(' ').slice(1).join(' ');
}
instruction.labels = parseLabels(unparsedLine);
instruction.signals = [];
instruction.branchType = BranchType.NONE;
unparsedLine = unparsedLine.split(' ').slice(instruction.labels.length).join(' ');
var hadBranch = false;
var conditions = parseConditions(config);
unparsedLine.split(',').map(function(segment) {
return segment.trim();
}).forEach(function(arg) {
var isBropr = arg === 'bropr';
var isBradr = arg === 'bradr';
var isAddressBranch = arg.includes('br ');
var isConditional = arg.includes('if ');
var isBranch = isBropr || isBradr || isAddressBranch;
var isSignal = signals.find(function(signal) {
return signal.toLowerCase() === arg;
});
// Check for multiple branches.
if (isBranch && hadBranch) {
instruction.error = 'More than one branch';
} else if (isBranch) {
hadBranch = true;
}
// Set relevant instruction fields.
var res;
if (isSignal) {
if (!instruction.signals.includes(arg)) {
instruction.signals.push(arg);
}
} else if (isBropr) {
instruction.branchType = BranchType.BROPR;
} else if (isBradr) {
instruction.branchType = BranchType.BRADR;
} else if (isBranch && isConditional) {
res = CONDITIONAL_BRANCH.exec(arg);
if (!res) {
instruction.error = 'Invalid conditional branch format';
return;
}
instruction.branchType = BranchType.CONDITIONAL;
var splitCondition = res[1].split('.');
var complement = res[1].startsWith('#') && splitCondition.length > 1 ? '#' : '';
instruction.condition = complement + splitCondition[splitCondition.length - 1];
if (!conditions.includes(instruction.condition)) {
instruction.error = 'Unknown condition code ' + instruction.condition;
return;
}
instruction.destination = res[2];
// TODO: Destination validation
} else if (isBranch && !isConditional) {
res = UNCONDITIONAL_BRANCH.exec(arg);
if (!res) {
instruction.error = 'Invalid unconditional branch format';
return;
}
instruction.branchType = BranchType.UNCONDITIONAL;
instruction.destination = res[1];
// TODO: Destination validation
} else {
instruction.error = 'Unknown operation ' + arg;
}
});
return instruction;
}
function createRect(startX, startY, width, height) {
var rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
rect.setAttributeNS('http://www.w3.org/2000/svg', 'x', startX);
rect.setAttributeNS('http://www.w3.org/2000/svg', 'y', startY);
rect.setAttributeNS('http://www.w3.org/2000/svg', 'width', width);
rect.setAttributeNS('http://www.w3.org/2000/svg', 'height', height);
rect.setAttributeNS('http://www.w3.org/2000/svg', 'stroke-width', '1');
rect.setAttributeNS('http://www.w3.org/2000/svg', 'fill-opacity', '0');
rect.style.stroke = 'black';
return rect;
}
function createConditionRect(startX, startY, width, height) {
var rect = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
var points = [
[startX, startY + height / 2],
[startX + width * 1 / 20, startY],
[startX + width * 19 / 20, startY],
[startX + width, startY + height / 2],
[startX + width * 19 / 20, startY + height],
[startX + width * 1 / 20, startY + height]
];
rect.setAttributeNS('http://www.w3.org/2000/svg', 'points', points.map(function(point) {
return point.join(',');
}).join(' '));
rect.style.fill = 'transparent';
rect.style.stroke = 'black';
return rect;
}
function createTextLine(x, y, text) {
var line = document.createElementNS('http://www.w3.org/2000/svg', 'tspan');
line.textContent = text;
line.setAttributeNS('http://www.w3.org/2000/svg', 'x', x);
line.setAttributeNS('http://www.w3.org/2000/svg', 'y', y);
return line;
}
function wrapText(textSegments, maxLineLength) {
var lines = [];
var currentLine = '';
textSegments.forEach(function(segment, index) {
var segmentWithComma = segment.trim();
if (index !== textSegments.length - 1) {
segmentWithComma += ', ';
}
if (segmentWithComma.length + currentLine.length > maxLineLength && currentLine.length > 0) {
lines.push(currentLine);
currentLine = '';
}
currentLine += segmentWithComma;
});
lines.push(currentLine);
return lines;
}
function createText(startX, startY, line) {
var lines = typeof line === 'string' ? [line] : line;
var text = document.createElementNS('http://www.w3.org/2000/svg', 'text');
text.setAttributeNS('http://www.w3.org/2000/svg', 'x', startX);
text.setAttributeNS('http://www.w3.org/2000/svg', 'y', startY);
text.setAttributeNS('http://www.w3.org/2000/svg', 'alignment-baseline', 'middle');
text.setAttributeNS('http://www.w3.org/2000/svg', 'font-family', 'monospace');
text.setAttributeNS('http://www.w3.org/2000/svg', 'text-anchor', 'middle');
lines.forEach(function(currentLine, index) {
text.appendChild(createTextLine(startX, startY + index * 15, currentLine));
});
return text;
}
function createTextNotCentered(startX, startY, text) {
var textNode = createText(startX, startY, text);
textNode.removeAttribute('text-anchor');
return textNode;
}
function createLine(startX, startY, endX, endY) {
var line = document.createElementNS('http://www.w3.org/2000/svg', 'line');
line.setAttributeNS('http://www.w3.org/2000/svg', 'x1', startX);
line.setAttributeNS('http://www.w3.org/2000/svg', 'y1', startY);
line.setAttributeNS('http://www.w3.org/2000/svg', 'x2', endX);
line.setAttributeNS('http://www.w3.org/2000/svg', 'y2', endY);
line.style.stroke = 'black';
return line;
}
function createArrow(startX, startY, endX, endY) {
var arrow = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
var points = [[endX, endY], [endX, endY], [endX, endY]];
if (startX === endX) {
// Vertical
points[0][0] -= 2.5;
points[1][0] += 2.5;
if (endY > startY) {
// Down
points[0][1] -= 2.5;
points[1][1] -= 2.5;
} else {
// Up
points[0][1] += 2.5;
points[1][1] += 2.5;
}
} else {
// Horizontal
points[0][1] -= 2.5;
points[1][1] += 2.5;
if (endX > startX) {
// Right
points[0][0] -= 2.5;
points[1][0] -= 2.5;
} else {
// Left
points[0][0] += 2.5;
points[1][0] += 2.5;
}
}
arrow.setAttributeNS('http://www.w3.org/2000/svg', 'points', points.map(function(point) {
return point.join(',');
}).join(' '));
arrow.style.fill = 'black';
var group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
group.appendChild(createLine(startX, startY, endX, endY));
group.appendChild(arrow);
return group;
}
function hasSelfBranch(instruction) {
if (instruction.destination.startsWith('madr')) {
return parseInt(instruction.destination.substring(4), 16) === instruction.address;
}
return instruction.labels.includes(instruction.destination);
}
function generateInstructionDiagram(parameters, instruction, currentY) {
var y = currentY;
var arrowHeight = parameters.arrowHeight;
var group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
var columnWidth = (parameters.width - 2 * parameters.margin) / 3;
var columnOffset = (columnWidth - 200 - 100 - 20) / 2;
var offL = parameters.margin + columnOffset;
var offM = offL + columnWidth;
var offR = offM + columnWidth;
// Label
if (instruction.labels.length > 0) {
// TODO: Support more than one label and also label wrapping
group.appendChild(createRect(offM + 220, y, 100, 27.5));
group.appendChild(createRect(offL + 220, y, 100, 27.5));
group.appendChild(createText(offM + 270, y + 17.5, instruction.labels[0]));
group.appendChild(createText(offL + 270, y + 17.5, instruction.labels[0]));
group.appendChild(createArrow(offM + 220, y + 13.75, offM + 200, y + 13.75));
group.appendChild(createArrow(offL + 220, y + 13.75, offL + 200, y + 13.75));
}
// Signals
var wrappedTextMiddle = wrapText(instruction.signals, MAX_LINE_LENGTH);
// TODO: Translate signals
var wrappedTextLeft = wrapText(instruction.signals, MAX_LINE_LENGTH);
var wrappedTextRight = wrapText(instruction.line.split(','), columnWidth / 10);
var yDiffLeft = (wrappedTextLeft.length - 1) * 15 + 17.5;
var yDiffMiddle = (wrappedTextMiddle.length - 1) * 15 + 17.5;
var yDiff = Math.max(yDiffLeft, yDiffMiddle);
group.appendChild(createText(offM + 100, y + 17.5, wrappedTextMiddle));
group.appendChild(createText(offL + 100, y + 17.5, wrappedTextLeft));
group.appendChild(createTextNotCentered(offR, y + 17.5, wrappedTextRight));
var rectHeight = yDiff + 10;
group.appendChild(createRect(offM, y, 200, rectHeight));
group.appendChild(createRect(offL, y, 200, rectHeight));
group.appendChild(createArrow(offM + 100, y + rectHeight, offM + 100, y + rectHeight + arrowHeight));
group.appendChild(createArrow(offL + 100, y + rectHeight, offL + 100, y + rectHeight + arrowHeight));
y += rectHeight + arrowHeight;
// Condition
switch (instruction.branchType) {
case BranchType.BRADR:
case BranchType.BROPR:
group.appendChild(createText(offM + 100, y + 17.5, instruction.branchType));
group.appendChild(createText(offL + 100, y + 17.5, instruction.branchType));
group.appendChild(createConditionRect(offM, y, 200, 27.5));
group.appendChild(createConditionRect(offL, y, 200, 27.5));
y += 50;
break;
case BranchType.CONDITIONAL:
group.appendChild(createText(offM + 100, y + 17.5, instruction.condition));
group.appendChild(createText(offL + 100, y + 17.5, instruction.condition));
group.appendChild(createConditionRect(offM, y, 200, 27.5));
group.appendChild(createConditionRect(offL, y, 200, 27.5));
group.appendChild(createArrow(offM + 100, y + 27.5, offM + 100, y + 27.5 + arrowHeight));
group.appendChild(createArrow(offL + 100, y + 27.5, offL + 100, y + 27.5 + arrowHeight));
group.appendChild(createText(offM + 90, y + 27.5 + arrowHeight * 3 / 4, '0'));
group.appendChild(createText(offL + 90, y + 27.5 + arrowHeight * 3 / 4, '0'));
group.appendChild(createText(offM + 203, y + 10, '1'));
group.appendChild(createText(offL + 203, y + 10, '1'));
if (hasSelfBranch(instruction)) {
group.appendChild(createLine(offM + 200, y + 13.75, offM + 210, y + 13.75));
group.appendChild(createLine(offL + 200, y + 13.75, offL + 210, y + 13.75));
group.appendChild(createLine(offM + 210, y + 13.75, offM + 210, y - 20));
group.appendChild(createLine(offL + 210, y + 13.75, offL + 210, y - 20));
group.appendChild(createLine(offM + 210, y + 13.75, offM + 210, y - 20));
group.appendChild(createLine(offL + 210, y + 13.75, offL + 210, y - 20));
group.appendChild(createArrow(offM + 210, y - 20, offM + 200, y - 20));
group.appendChild(createArrow(offL + 210, y - 20, offL + 200, y - 20));
} else {
group.appendChild(createArrow(offM + 200, y + 13.75, offM + 220, y + 13.75));
group.appendChild(createArrow(offL + 200, y + 13.75, offL + 220, y + 13.75));
group.appendChild(createRect(offM + 220, y, 100, 27.5));
group.appendChild(createRect(offL + 220, y, 100, 27.5));
group.appendChild(createText(offM + 270, y + 17.5, instruction.destination));
group.appendChild(createText(offL + 270, y + 17.5, instruction.destination));
}
y += 27.5 + arrowHeight;
break;
case BranchType.UNCONDITIONAL:
// TODO: Support label wrapping
group.appendChild(createRect(offM + 50, y, 100, 27.5));
group.appendChild(createRect(offL + 50, y, 100, 27.5));
group.appendChild(createText(offM + 100, y + 17.5, instruction.destination));
group.appendChild(createText(offL + 100, y + 17.5, instruction.destination));
y += 40;
break;
default:
// Do nothing.
break;
}
var separator = createLine(parameters.margin, y, parameters.width - parameters.margin, y);
separator.setAttributeNS('http://www.w3.org/2000/svg', 'stroke-dasharray', '10,10');
group.appendChild(separator);
return [group, y];
}
function createPage(parameters, instructions) {
var group = document.createElementNS('http://www.w3.org/2000/svg', 'g');
var width = parameters.width;
var height = parameters.height;
var margin = parameters.margin;
var headerHeight = parameters.headerHeight;
var footerRowHeight = parameters.footerRowHeight;
var pageWidth = width - 2 * margin;
var columnWidth = pageWidth / 3;
var columnHalfWidth = columnWidth / 2;
group.append(createLine(margin, margin, width - margin, margin));
group.append(createLine(margin, margin, margin, height - margin));
group.append(createLine(width - margin, margin, width - margin, height - margin));
group.append(createLine(margin, height - margin, width - margin, height - margin));
group.append(createLine(margin, margin + headerHeight, width - margin, margin + headerHeight));
group.append(createLine(margin, margin + headerHeight, width - margin, margin + headerHeight));
group.append(createLine(margin + columnWidth, margin, margin + columnWidth, height - margin));
group.append(createLine(margin + columnWidth * 2, margin, margin + columnWidth * 2, height - margin));
group.append(createText(margin + columnHalfWidth, margin + 15, 'Dijagram toka mikrooperacija'));
group.append(createText(margin + columnHalfWidth * 3, margin + 15, 'Dijagram toka upravljačkih signala'));
group.append(createText(margin + columnHalfWidth * 5, margin + 15, 'Sekvenca upravljačkih signala'));
var lowerRowMargin = height - margin - footerRowHeight;
var upperRowMargin = lowerRowMargin - footerRowHeight;
group.append(createLine(margin, lowerRowMargin, width - margin, lowerRowMargin));
group.append(createLine(margin, upperRowMargin, width - margin, upperRowMargin));
var pageHeight = height - 2 * margin - FIELDS.length * footerRowHeight;
var currentY = margin + headerHeight;
pageHeight -= currentY;
while (pageHeight > 0 && instructions.length > 0) {
var instruction = instructions.shift();
var generationResult = generateInstructionDiagram(parameters, instruction, currentY);
var heightDiff = generationResult[1] - currentY;
currentY = generationResult[1];
pageHeight -= heightDiff;
if (pageHeight >= 0) {
group.appendChild(generationResult[0]);
} else {
instructions.unshift(instruction);
}
}
FIELDS.forEach(function(row, rowIndex) {
row.forEach(function(cell, columnIndex) {
var textX = margin + columnIndex * columnWidth + 10;
var textY = height - margin - (FIELDS.length - rowIndex - 0.5) * footerRowHeight;
group.append(createTextNotCentered(textX, textY, cell + ':'));
});
});
return group;
}
function generate(event) {
event.preventDefault();
$('#diagram-generator-error').text('');
var newPage = $('#diagram-generator-new-page').prop('checked');
var instructions = [];
var comment = '';
var config = parseConfig(fileContents.configuration);
if (!config) {
$('#diagram-generator-error').text('Error while parsing configuration.');
return;
}
var lines = fileContents.microcode.split('\n');
var labels = {};
for (var i = 0, l = lines.length; i < l; ++i) {
var line = lines[i].trim();
if (!line) {
continue;
}
if (line.startsWith('!')) {
comment = line;
} else {
var instruction = parseLine(comment, line, config);
comment = '';
for (var j = 0, l2 = instruction.labels.length; j < l2; ++j) {
var label = instruction.labels[j];
if (labels[label]) {
instruction.error = 'Duplicate label ' + label;
break;
}
labels[label] = instruction.address;
}
if (instruction.error) {
$('#diagram-generator-error').text('Microcode error: ' + instruction.error + ' at line ' + (i + 1));
return;
}
instructions.push(instruction);
}
}
var svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
var parameters = {
arrowHeight: 15,
headerHeight: 20,
height: 1680,
indexNum: $('#diagram-generator-student-index').val(),
footerRowHeight: 50,
margin: 50,
nameSurname: $('#diagram-generator-student-name').val(),
subjectName: 'Osnovi računarske tehnike 2',
width: 1200
};
var height = parameters.height;
svg.setAttributeNS('http://www.w3.org/2000/svg', 'width', parameters.width);
var numPages = 0;
while (instructions.length > 0) {
var page = createPage(parameters, instructions);
page.setAttributeNS('http://www.w3.org/2000/svg', 'transform', 'translate(0, ' + numPages * height + ')');
svg.appendChild(page);
++numPages;
}
var pageNodes = svg.children;
var numFieldRows = FIELDS.length;
var numFieldColumns = FIELDS[0].length;
var numFields = numFieldRows * numFieldColumns;
for (var pageIndex = 0; pageIndex < numPages; ++pageIndex) {
var fieldNodes = Array.prototype.slice.call(pageNodes[pageIndex].children, -numFields);
var fields = [];
for (var rowIndex = 0; rowIndex < numFieldRows; ++rowIndex) {
var fieldRow = [];
for (var columnIndex = 0; columnIndex < numFieldColumns; ++columnIndex) {
fieldRow.push(fieldNodes[rowIndex * numFieldColumns + columnIndex]);
}
fields.push(fieldRow);
}
var today = new Date();
var formattedDate = today.getDate() + '. ' + (today.getMonth() + 1) + '. ' + today.getFullYear() + '.';
fields[0][0].textContent += ' ' + parameters.nameSurname;
fields[0][1].textContent += ' ' + parameters.indexNum;
fields[1][0].textContent += ' ' + parameters.subjectName;
fields[1][1].textContent += ' ' + formattedDate;
fields[1][2].textContent += ' ' + (pageIndex + 1) + '/' + numPages;
}
var totalHeight = numPages * height;
svg.setAttributeNS('http://www.w3.org/2000/svg', 'height', totalHeight);
svg.setAttributeNS('http://www.w3.org/2000/svg', 'viewBox', '0 0 ' + parameters.width + ' ' + totalHeight);
svg.setAttributeNS('http://www.w3.org/2000/svg', 'version', '1.1');
svg.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
svg.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
if (newPage) {
var imageWindow = window.open('');
imageWindow.document.write(svg.outerHTML);
} else {
$('#diagram-generator-result').html(svg.outerHTML);
}
}
function init() {
$('#diagram-generator').append(
$('<form>', {
html: [
$('<p>', {
html: [
$('<label>', {
'for': 'microcode',
'text': 'Microcode:'
}),
$('<input>', {
change: updateFile,
name: 'microcode',
id: 'microcode',
type: 'file'
})
]
}),
$('<p>', {
html: [
$('<label>', {
'for': 'configuration',
'text': 'Configuration:'
}),
$('<input>', {
change: updateFile,
name: 'configuration',
id: 'configuration',
type: 'file'
})
]
}),
$('<p>', {
html: [
$('<label>', {
'for': 'diagram-generator-student-name',
'text': 'Student name:'
}),
$('<input>', {
name: 'diagram-generator-student-name',
id: 'diagram-generator-student-name',
placeholder: 'Pera Pisar',
type: 'text'
})
]
}),
$('<p>', {
html: [
$('<label>', {
'for': 'diagram-generator-student-index',
'text': 'Student index:'
}),
$('<input>', {
name: 'diagram-generator-student-index',
id: 'diagram-generator-student-index',
placeholder: '2021/0000',
type: 'text'
})
]
}),
$('<p>', {
html: [
$('<input>', {
id: 'diagram-generator-submit',
type: 'submit',
value: 'Generate'
}),
$('<label>', {
'for': 'diagram-generator-new-page',
'text': 'Generate on new page'
}),
$('<input>', {
id: 'diagram-generator-new-page',
name: 'diagram-generator-new-page',
type: 'checkbox'
})
]
}),
$('<p>', {
id: 'diagram-generator-error'
})
],
submit: generate
}),
$('<div>', {
id: 'diagram-generator-result'
})
);
updateSubmitEnabled();
}
$(init);
})();