mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-10-05 12:05:38 +00:00
* build: move frontend assets to Bootstrap 5.3 and Tom Select * feat: migrate templates and scripts to Bootstrap 5, dropping jQuery Templates - Rename Bootstrap 4 classes and data attributes (data-bs-*, ms-/me-/ps-/pe-, text-start/end, form-group -> mb-3, input-group wrappers removed, badges, custom controls -> form-check/form-select, media -> d-flex, btn-close, ...) - Dark mode now uses Bootstrap 5.3 colour modes (data-bs-theme on <html>), set from <head> to avoid a flash of the light theme - Remove the Bootstrap 4 /bootstrap/ demo page - Contextual table classes (table-success etc.) still work as plain backgrounds for the rigboard key JavaScript - Remove jQuery: src.js/interaction.js and every inline template script are rewritten in plain JS on top of small helpers (helpers.js, bundled with Bootstrap into jpop.js so inline scripts can use them) - Replace bootstrap-select/ajax-bootstrap-select with Tom Select. The remote search now sends the `q` parameter and reads `text`, which is what the API actually uses (the old picker sent `term` and read `label`) - HTML fragments are fetched with an X-Requested-With header so views keep rendering their modal variants, and fetched scripts are re-executed - Remove the Bootstrap 4 plugin script includes * fix: stop rigboard header buttons stretching to full width under Bootstrap 5 * fix: restore dark-mode brand colours and contextual table colours under Bootstrap 5 * fix: brighten dark-mode links and make coloured card outlines visible * fix: calendar layout and grid borders, navbar search button width, guard missing modal links * fix: readable text in dark-mode Tom Select inputs and placeholders, restore form-control column widths * build: split the Dockerfile into cached stages with prod and dev targets * deploy: make compose.yml development-only with live reload, and document it * fix: keep badge text colour for links inside badges * fix: restore table-bordered grid lines in dark mode * fix: include Bootstrap's progress styles and keep progress labels readable
162 lines
5.4 KiB
JavaScript
162 lines
5.4 KiB
JavaScript
function setupItemTable(items_json) {
|
|
objectitems = JSON.parse(items_json)
|
|
Object.keys(objectitems).forEach(function (key) {
|
|
objectitems[key] = JSON.parse(objectitems[key]);
|
|
});
|
|
newitem = -1;
|
|
}
|
|
|
|
function escapeHtml(str) {
|
|
var div = document.createElement('div');
|
|
div.textContent = str;
|
|
return div.innerHTML;
|
|
}
|
|
|
|
function updatePrices() {
|
|
// individual rows
|
|
var sum = 0;
|
|
for (var pk in objectitems) {
|
|
var fields = objectitems[pk].fields;
|
|
var sub = fields.cost * fields.quantity;
|
|
var subTotal = document.querySelector('#item-' + pk + ' .sub-total');
|
|
if (subTotal) {
|
|
subTotal.textContent = parseFloat(sub).toFixed(2);
|
|
subTotal.dataset.subtotal = sub;
|
|
}
|
|
|
|
sum += Number(sub);
|
|
}
|
|
|
|
document.getElementById('sumtotal').textContent = parseFloat(sum).toFixed(2);
|
|
var vat = sum * Number(document.getElementById('vat-rate').dataset.rate);
|
|
document.getElementById('vat').textContent = parseFloat(vat).toFixed(2);
|
|
document.getElementById('total').textContent = parseFloat(sum + vat).toFixed(2);
|
|
}
|
|
|
|
function setupMDE(selector) {
|
|
var element = document.querySelector(selector);
|
|
editor = new EasyMDE({
|
|
autoDownloadFontAwesome: false,
|
|
element: element,
|
|
forceSync: true,
|
|
toolbar: ["bold", "italic", "strikethrough", "|", "unordered-list", "ordered-list", "|", "link", "|", "preview", "guide"],
|
|
status: true,
|
|
});
|
|
element.mde_editor = editor;
|
|
}
|
|
|
|
(function () {
|
|
var itemTable = document.getElementById('item-table');
|
|
var itemForm = document.getElementById('item-form');
|
|
|
|
function field(id) {
|
|
return document.getElementById(id);
|
|
}
|
|
|
|
if (itemTable) {
|
|
on(itemTable, 'click', '.item-delete', function () {
|
|
delete objectitems[this.dataset.pk];
|
|
var row = document.getElementById('item-' + this.dataset.pk);
|
|
if (row) {
|
|
row.remove();
|
|
}
|
|
updatePrices();
|
|
});
|
|
|
|
on(itemTable, 'click', '.item-add', function () {
|
|
itemForm.dataset.pk = newitem;
|
|
|
|
// Set the form values
|
|
field('item_name').value = '';
|
|
field('item_description').value = '';
|
|
field('item_quantity').value = '';
|
|
field('item_cost').value = '';
|
|
|
|
showModal(this.dataset.modalTarget);
|
|
});
|
|
|
|
on(itemTable, 'click', '.item-edit', function () {
|
|
// set the pk as we will need this later
|
|
var pk = this.dataset.pk;
|
|
itemForm.dataset.pk = pk;
|
|
|
|
// Set the form values
|
|
var fields = objectitems[pk].fields;
|
|
field('item_name').value = fields.name;
|
|
field('item_description').value = fields.description;
|
|
field('item_quantity').value = fields.quantity;
|
|
field('item_cost').value = fields.cost;
|
|
|
|
showModal(this.dataset.modalTarget);
|
|
});
|
|
}
|
|
|
|
on(document, 'submit', '#item-form', function (e) {
|
|
e.preventDefault();
|
|
var pk = this.dataset.pk;
|
|
hideModal('#itemModal');
|
|
|
|
var fields;
|
|
if (pk == newitem--) {
|
|
// Create the new data structure and add it on.
|
|
fields = new Object();
|
|
fields['name'] = field('item_name').value;
|
|
fields['description'] = field('item_description').value;
|
|
fields['cost'] = field('item_cost').value;
|
|
fields['quantity'] = field('item_quantity').value;
|
|
|
|
var order = 0;
|
|
for (var item in objectitems) {
|
|
order++;
|
|
}
|
|
|
|
fields['order'] = order;
|
|
|
|
objectitems[pk] = new Object();
|
|
objectitems[pk]['fields'] = fields;
|
|
|
|
// Add the new table row
|
|
var row = field('new-item-row').cloneNode(true);
|
|
row.id = 'item-' + pk;
|
|
row.dataset.pk = pk;
|
|
field('item-table-body').appendChild(row);
|
|
row.querySelectorAll('.item-delete, .item-edit').forEach(function (button) {
|
|
button.dataset.pk = pk;
|
|
});
|
|
} else {
|
|
// Existing item
|
|
// update data structure
|
|
fields = objectitems[pk].fields;
|
|
fields.name = field('item_name').value;
|
|
fields.description = field('item_description').value;
|
|
fields.cost = field('item_cost').value;
|
|
fields.quantity = field('item_quantity').value;
|
|
objectitems[pk].fields = fields;
|
|
}
|
|
// update the table
|
|
var tableRow = field('item-' + pk);
|
|
tableRow.querySelector('.name').innerHTML = escapeHtml(fields.name);
|
|
tableRow.querySelector('.description').innerHTML = fields.description;
|
|
tableRow.querySelector('.cost').innerHTML = parseFloat(fields.cost).toFixed(2);
|
|
tableRow.querySelector('.quantity').innerHTML = fields.quantity;
|
|
|
|
updatePrices();
|
|
});
|
|
|
|
on(document, 'submit', '.itemised_form', function () {
|
|
field('id_items_json').value = JSON.stringify(objectitems);
|
|
});
|
|
|
|
if (itemTable && typeof sortable === 'function') {
|
|
var sortables = sortable("#item-table tbody");
|
|
if (sortables.length) {
|
|
sortables[0].addEventListener('sortupdate', function (e) {
|
|
var items = e.detail.destination.items;
|
|
for (var i in items) {
|
|
objectitems[items[i].dataset.pk].fields.order = i;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
})();
|