Initial commit
This commit is contained in:
14
wwwroot/scripts/js/dredgepos.authenticate.js
Normal file
14
wwwroot/scripts/js/dredgepos.authenticate.js
Normal file
@@ -0,0 +1,14 @@
|
||||
let showLoginBox = () => {
|
||||
showVirtualNumpad('Enter Login Code', 6, true, false, false, authenticate);
|
||||
};
|
||||
let authenticate = (input) => {
|
||||
let login = ajaxSync('/ajax/authenticateClerk', input);
|
||||
if (login === 'success')
|
||||
redirect('/floorplan');
|
||||
else
|
||||
showLoginBox();
|
||||
};
|
||||
$(() => {
|
||||
showLoginBox();
|
||||
});
|
||||
//# sourceMappingURL=dredgepos.authenticate.js.map
|
||||
1
wwwroot/scripts/js/dredgepos.authenticate.js.map
Normal file
1
wwwroot/scripts/js/dredgepos.authenticate.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"dredgepos.authenticate.js","sourceRoot":"","sources":["../ts/dredgepos.authenticate.ts"],"names":[],"mappings":"AAAA,IAAI,YAAY,GAAG,GAAG,EAAE;IACpB,iBAAiB,CAAC,kBAAkB,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC,CAAA;AAC9E,CAAC,CAAA;AAED,IAAK,YAAY,GAAG,CAAC,KAAc,EAAE,EAAE;IACnC,IAAI,KAAK,GAAG,QAAQ,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAA;IACtD,IAAG,KAAK,KAAK,SAAS;QAClB,QAAQ,CAAC,YAAY,CAAC,CAAA;;QAEtB,YAAY,EAAE,CAAA;AACtB,CAAC,CAAA;AAED,CAAC,CAAC,GAAG,EAAE;IACH,YAAY,EAAE,CAAA;AAClB,CAAC,CAAC,CAAA"}
|
||||
96
wwwroot/scripts/js/dredgepos.core.js
Normal file
96
wwwroot/scripts/js/dredgepos.core.js
Normal file
@@ -0,0 +1,96 @@
|
||||
let Application = {
|
||||
keyboard: null,
|
||||
mode: "default",
|
||||
languageVars: {}
|
||||
};
|
||||
/** Parses a language variable. */
|
||||
let lang = (key, replacements) => {
|
||||
let finalValue = Application.languageVars[key];
|
||||
if (!replacements)
|
||||
return finalValue;
|
||||
if (typeof replacements === 'string')
|
||||
replacements = [replacements];
|
||||
replacements.forEach((replacement, index) => {
|
||||
let correctIndex = index + 1;
|
||||
finalValue = finalValue.replace(`[${correctIndex}]`, replacement);
|
||||
});
|
||||
return finalValue;
|
||||
};
|
||||
/** Check if a variable is defined */
|
||||
let defined = (variable) => {
|
||||
return typeof variable !== 'undefined';
|
||||
};
|
||||
/** Call an Ajax function asynchronously */
|
||||
let ajax = (endpoint, data, method = 'POST', successFunction, errorFunction, beforeFunction) => {
|
||||
data = (data == null) ? data : JSON.stringify(data);
|
||||
return $.ajax({
|
||||
url: endpoint,
|
||||
method: method,
|
||||
data: data,
|
||||
success: (response) => {
|
||||
if (successFunction)
|
||||
successFunction(JSON.parse(response.data));
|
||||
},
|
||||
error: errorFunction,
|
||||
beforeSend: beforeFunction
|
||||
});
|
||||
};
|
||||
/*
|
||||
For the flow of the app, synchronous is commonly preferred
|
||||
though trying to keep it's usage as low as possible.
|
||||
*/
|
||||
let ajaxSync = (endpoint, data, method = 'POST') => {
|
||||
let response = JSON.parse($.ajax({
|
||||
url: endpoint,
|
||||
method: method,
|
||||
data: JSON.stringify(data),
|
||||
async: false,
|
||||
}).responseText);
|
||||
if (response.data) {
|
||||
response.data = JSON.parse(response.data);
|
||||
return response.data;
|
||||
}
|
||||
return response;
|
||||
};
|
||||
/* Redirect to a specific URL */
|
||||
let redirect = (url) => {
|
||||
window.location.href = url;
|
||||
};
|
||||
let setLanguageVariables = () => {
|
||||
Application.languageVars = ajaxSync('/ajax/languageVars', null, 'GET');
|
||||
};
|
||||
// @ts-ignore
|
||||
let alert = (message, title = 'Message') => {
|
||||
let alertBox = $('#alert');
|
||||
alertBox.css('display', 'flex');
|
||||
alertBox.data('value', '');
|
||||
$('#alertHeading').text(title);
|
||||
$('#alertMessage').text(message);
|
||||
$('#alertOk').css('display', 'flex');
|
||||
$('#alertYes').css('display', 'none');
|
||||
$('#alertNo').css('display', 'none');
|
||||
};
|
||||
// @ts-ignore
|
||||
let confirm = (message, data, title = 'Confirm', submitFunction = (data) => { hideAlerts(); }) => {
|
||||
let alert = $('#alert');
|
||||
$(document).on('click', '#alert #alertYes', () => {
|
||||
submitFunction(data);
|
||||
hideAlerts();
|
||||
$(document).off('click', '#alert #alertYes');
|
||||
});
|
||||
alert.css('display', 'flex');
|
||||
$('#alertHeading').html(title);
|
||||
$('#alertMessage').html(message);
|
||||
$('#alertOk').css('display', 'none');
|
||||
$('#alertYes').css('display', 'flex');
|
||||
$('#alertNo').css('display', 'flex');
|
||||
};
|
||||
let hideAlerts = () => {
|
||||
$('#alert').hide();
|
||||
};
|
||||
$(() => {
|
||||
let doc = $(document);
|
||||
setLanguageVariables();
|
||||
doc.on('click', '#alertNo, #alertOk', () => $('#alert').hide());
|
||||
});
|
||||
//# sourceMappingURL=dredgepos.core.js.map
|
||||
1
wwwroot/scripts/js/dredgepos.core.js.map
Normal file
1
wwwroot/scripts/js/dredgepos.core.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"dredgepos.core.js","sourceRoot":"","sources":["../ts/dredgepos.core.ts"],"names":[],"mappings":"AAAK,IAAI,WAAW,GAAsB;IAClC,QAAQ,EAAG,IAAI;IACf,IAAI,EAAE,SAAS;IACf,YAAY,EAAE,EAAE;CACnB,CAAA;AAGD,kCAAkC;AACjC,IAAI,IAAI,GAAG,CAAC,GAAW,EAAE,YAAgC,EAAE,EAAE;IAC1D,IAAI,UAAU,GAAG,WAAW,CAAC,YAAY,CAAC,GAAG,CAAC,CAAA;IAE9C,IAAG,CAAC,YAAY;QAAE,OAAO,UAAU,CAAA;IACnC,IAAG,OAAO,YAAY,KAAK,QAAQ;QAAE,YAAY,GAAG,CAAC,YAAY,CAAC,CAAA;IAElE,YAAY,CAAC,OAAO,CAAE,CAAC,WAAW,EAAE,KAAK,EAAE,EAAE;QACzC,IAAI,YAAY,GAAG,KAAK,GAAC,CAAC,CAAA;QAC1B,UAAU,GAAG,UAAU,CAAC,OAAO,CAAC,IAAI,YAAY,GAAG,EAAE,WAAW,CAAC,CAAA;IACrE,CAAC,CAAC,CAAA;IAEF,OAAO,UAAU,CAAA;AACrB,CAAC,CAAA;AAED,qCAAqC;AACpC,IAAI,OAAO,GAAG,CAAC,QAAa,EAAE,EAAE;IAC7B,OAAO,OAAO,QAAQ,KAAK,WAAW,CAAA;AAC1C,CAAC,CAAA;AAED,2CAA2C;AAC1C,IAAI,IAAI,GAAG,CAAC,QAAiB,EAAE,IAAS,EAAE,MAAM,GAAG,MAAM,EAAE,eAA0B,EAAG,aAA8C,EAAE,cAAmB,EAAE,EAAE;IAC5J,IAAI,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;IACpD,OAAO,CAAC,CAAC,IAAI,CAAC;QACV,GAAG,EAAE,QAAQ;QACb,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI;QACV,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE;YAClB,IAAG,eAAe;gBACd,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAA;QAClD,CAAC;QACD,KAAK,EAAE,aAAa;QACpB,UAAU,EAAE,cAAc;KAC7B,CAAC,CAAA;AACN,CAAC,CAAA;AAGD;;;GAGG;AACF,IAAI,QAAQ,GAAG,CAAC,QAAiB,EAAE,IAAU,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE;IAC/D,IAAI,QAAQ,GAAI,IAAI,CAAC,KAAK,CACtB,CAAC,CAAC,IAAI,CAAC;QACH,GAAG,EAAE,QAAQ;QACb,MAAM,EAAE,MAAM;QACd,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;QAC1B,KAAK,EAAC,KAAK;KACd,CAAC,CAAC,YAAY,CAAC,CAAA;IAEpB,IAAG,QAAQ,CAAC,IAAI,EAAE;QACd,QAAQ,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;QACzC,OAAO,QAAQ,CAAC,IAAI,CAAA;KACvB;IAED,OAAO,QAAQ,CAAA;AACnB,CAAC,CAAA;AAED,gCAAgC;AAC/B,IAAI,QAAQ,GAAG,CAAC,GAAW,EAAS,EAAE;IACnC,MAAM,CAAC,QAAQ,CAAC,IAAI,GAAG,GAAG,CAAA;AAC9B,CAAC,CAAA;AAGA,IAAI,oBAAoB,GAAG,GAAG,EAAE;IAC7B,WAAW,CAAC,YAAY,GAAG,QAAQ,CAAC,oBAAoB,EAAE,IAAI,EAAE,KAAK,CAAC,CAAA;AAC1E,CAAC,CAAA;AAEA,aAAa;AACb,IAAI,KAAK,GAAG,CAAC,OAAe,EAAE,KAAK,GAAC,SAAS,EAAE,EAAE;IAC9C,IAAI,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAA;IAC1B,QAAQ,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAChC,QAAQ,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC3B,CAAC,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/B,CAAC,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEjC,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IACtC,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;AACzC,CAAC,CAAA;AAEA,aAAa;AACb,IAAI,OAAO,GAAG,CAAC,OAAe,EAAE,IAAS,EAAE,KAAK,GAAC,SAAS,EAAE,iBAAiB,CAAC,IAAS,EAAE,EAAE,GAAE,UAAU,EAAE,CAAA,CAAA,CAAC,EAAE,EAAE;IAC3G,IAAI,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAA;IAEvB,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,kBAAkB,EAAE,GAAG,EAAE;QAC7C,cAAc,CAAC,IAAI,CAAC,CAAA;QACpB,UAAU,EAAE,CAAA;QACZ,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAA;IAChD,CAAC,CAAC,CAAA;IAEF,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;IAC5B,CAAC,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;IAC9B,CAAC,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAEhC,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;IACpC,CAAC,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;IACrC,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;AACxC,CAAC,CAAA;AAGA,IAAI,UAAU,GAAG,GAAG,EAAE;IACnB,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAA;AACtB,CAAC,CAAA;AAEL,CAAC,CAAE,GAAG,EAAE;IACJ,IAAI,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAA;IACrB,oBAAoB,EAAE,CAAA;IAEtB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;AACnE,CAAC,CAAC,CAAA"}
|
||||
784
wwwroot/scripts/js/dredgepos.floorplan.js
Normal file
784
wwwroot/scripts/js/dredgepos.floorplan.js
Normal file
@@ -0,0 +1,784 @@
|
||||
/// <reference path="./typings/konva.d.ts" />
|
||||
let stage;
|
||||
let transformer;
|
||||
let tableLayer;
|
||||
let editMode = false;
|
||||
let activeTables = [];
|
||||
let selectedTable;
|
||||
let selectedTableNumber;
|
||||
let currentRoom;
|
||||
let basis = 1280;
|
||||
let scale = 1;
|
||||
let newTable;
|
||||
let roomName;
|
||||
//Makes sure canvas always fits inside the div
|
||||
function getDimensions(parentDiv) {
|
||||
let tableMap = $('#tableMap');
|
||||
let outerWidth = parentDiv.outerWidth();
|
||||
let outerHeight = parentDiv.outerHeight();
|
||||
let width = outerWidth;
|
||||
let height = outerWidth;
|
||||
if (outerWidth >= outerHeight) {
|
||||
width = outerHeight;
|
||||
height = outerHeight;
|
||||
}
|
||||
tableMap.height(height);
|
||||
tableMap.width(width);
|
||||
scale = width / basis;
|
||||
return { width: width, height: height };
|
||||
}
|
||||
function setupTableMap() {
|
||||
let doc = $(document);
|
||||
activeTables = ajaxSync('/ajax/getActiveTables/1', null, 'GET');
|
||||
let dimensions = getDimensions($('#mapContainer'));
|
||||
roomName = 'Deck & Courtyard';
|
||||
stage = new Konva.Stage({
|
||||
container: 'tableMap',
|
||||
width: dimensions.width,
|
||||
height: dimensions.height,
|
||||
});
|
||||
$('body').on('click', '.editModeButton', () => { toggleEditMode(); });
|
||||
$('.roomButton').on('click', function () {
|
||||
roomName = $(this).text();
|
||||
loadRoom($(this).data('value'));
|
||||
});
|
||||
$('.transferTableButton').on('click', function () {
|
||||
transferModeOn();
|
||||
});
|
||||
$('.addDecoration').on('click', function () {
|
||||
$('#decorator').css('display', 'flex');
|
||||
});
|
||||
$('.deleteDecoration').on('click', function () {
|
||||
deleteDecoration(selectedDecoration);
|
||||
});
|
||||
$('.decoratorItem').on('click', function () {
|
||||
addDecoration(this);
|
||||
});
|
||||
$('.changeShapeButton').on('click', function () {
|
||||
changeTableShape(selectedTableNumber);
|
||||
});
|
||||
$('.reserveTableButton').on('click', function () {
|
||||
if ($(this).text() === lang('reserve_table')) {
|
||||
reserveTable();
|
||||
}
|
||||
else {
|
||||
unreserveTable();
|
||||
}
|
||||
});
|
||||
$('.addTableButton').on('click', function () {
|
||||
addTable();
|
||||
});
|
||||
$('.deleteTableButton').on('click', function () {
|
||||
deleteTable();
|
||||
});
|
||||
loadRoom(roomToLoad);
|
||||
}
|
||||
let updateTableShape = (tableData) => {
|
||||
return ajaxSync('/ajax/updateTableShape', tableData);
|
||||
};
|
||||
//Change the shape of a table in edit mode.
|
||||
function changeTableShape(tableNumber) {
|
||||
let tableData = getTableData(tableNumber);
|
||||
let tableShape = tableData['shape'];
|
||||
let tableWidth = tableData['width'];
|
||||
let tableHeight = tableData['height'];
|
||||
let tableRotation = tableData['rotation'];
|
||||
let order = ['square', 'rect', 'longrect', 'diamond', 'circle', 'ellipse', 'longellipse'];
|
||||
if (order.indexOf(tableShape) === -1)
|
||||
tableShape = 'square';
|
||||
//What the next shape is
|
||||
let currentIndex = order.indexOf(tableShape);
|
||||
let nextIndex = currentIndex + 1;
|
||||
if (nextIndex > (order.length) - 1)
|
||||
nextIndex = 0;
|
||||
let nextShape = order[nextIndex];
|
||||
switch (nextShape) {
|
||||
case 'square':
|
||||
case 'circle':
|
||||
tableHeight = tableWidth;
|
||||
tableRotation = 0;
|
||||
break;
|
||||
case 'diamond':
|
||||
tableHeight = tableWidth;
|
||||
tableRotation = 45;
|
||||
break;
|
||||
case 'rect':
|
||||
case 'ellipse':
|
||||
tableHeight = tableWidth * 2;
|
||||
tableRotation = 0;
|
||||
break;
|
||||
case 'longrect':
|
||||
case 'longellipse':
|
||||
tableRotation = 90;
|
||||
break;
|
||||
}
|
||||
let updateData = {
|
||||
table_number: tableNumber,
|
||||
shape: nextShape,
|
||||
height: tableHeight,
|
||||
width: tableWidth,
|
||||
rotation: tableRotation
|
||||
};
|
||||
tableData = updateTableShape(updateData);
|
||||
let tableGroup = stage.find('#' + tableNumber)[0];
|
||||
transformer.nodes([]);
|
||||
tableGroup.destroy();
|
||||
let newTable = createTableElement(tableData);
|
||||
tableLayer.add(newTable);
|
||||
stage.draw();
|
||||
selectTable(tableNumber);
|
||||
loadRoom(currentRoom, tableNumber);
|
||||
}
|
||||
let createTable = (tableData) => {
|
||||
return ajaxSync('/ajax/createTable', tableData);
|
||||
};
|
||||
let tableExists = (tableNumber) => {
|
||||
return ajaxSync(`/ajax/tableExists/${tableNumber}`);
|
||||
};
|
||||
function addTable(tableNumber) {
|
||||
if (!tableNumber) {
|
||||
showVirtualNumpad(lang('new_table_number'), 4, false, false, true, addTable);
|
||||
}
|
||||
else {
|
||||
let newTableInfo = {
|
||||
table_number: tableNumber,
|
||||
room_id: currentRoom,
|
||||
default_covers: 2,
|
||||
width: 200,
|
||||
height: 200,
|
||||
rotation: 0,
|
||||
pos_x: basis / 2,
|
||||
pos_y: basis / 2,
|
||||
shape: 'square',
|
||||
merged_children: '',
|
||||
previous_state: '',
|
||||
status: 0,
|
||||
reservation: 0,
|
||||
venue_id: 1
|
||||
};
|
||||
let newTableData = createTable(newTableInfo);
|
||||
if (!newTableData.table_number) {
|
||||
alert(newTableData);
|
||||
return false;
|
||||
}
|
||||
newTable = createTableElement(newTableData);
|
||||
tableLayer.add(newTable);
|
||||
tableLayer.draw();
|
||||
selectTable(tableNumber);
|
||||
}
|
||||
}
|
||||
function selectTable(tableNumber) {
|
||||
let table = stage.find('#' + tableNumber)[0];
|
||||
table.fire('click');
|
||||
}
|
||||
function deleteTable(tableNumber = 0) {
|
||||
if (!tableNumber) {
|
||||
confirm(lang('confirm_delete_table', selectedTableNumber), selectedTableNumber, 'Confirm', deleteTable);
|
||||
}
|
||||
else {
|
||||
if (tableIsOpen(selectedTableNumber)) {
|
||||
alert(lang('error_delete_existing_table'));
|
||||
}
|
||||
else {
|
||||
ajax(`/ajax/deleteTable/${selectedTableNumber}`, null, 'GET');
|
||||
let table = stage.find('#' + tableNumber)[0];
|
||||
transformer.nodes([]);
|
||||
table.destroy();
|
||||
tableLayer.draw();
|
||||
selectedTable = null;
|
||||
selectedTableNumber = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Rotate a shape around any point.
|
||||
// shape is a Konva shape
|
||||
// angleDegrees is the angle to rotate by, in degrees.
|
||||
// point is an object {x: posX, y: posY}
|
||||
function rotateAroundPoint(shape, angleDegrees, point) {
|
||||
let angleRadians = angleDegrees * Math.PI / 180;
|
||||
// they lied, I did have to use trigonometry
|
||||
const x = point.x +
|
||||
(shape.x() - point.x) * Math.cos(angleRadians) -
|
||||
(shape.y() - point.y) * Math.sin(angleRadians);
|
||||
const y = point.y +
|
||||
(shape.x() - point.x) * Math.sin(angleRadians) +
|
||||
(shape.y() - point.y) * Math.cos(angleRadians);
|
||||
shape.rotation(shape.rotation() + angleDegrees); // rotate the shape in place
|
||||
shape.x(x); // move the rotated shape in relation to the rotation point.
|
||||
shape.y(y);
|
||||
}
|
||||
function createDecoration(data, idToSelect = false) {
|
||||
let draggable = editMode;
|
||||
var decoration = new Image();
|
||||
decoration.onload = function () {
|
||||
var dec = new Konva.Image({
|
||||
id: data.decoration_id.toString(),
|
||||
x: data.decoration_pos_x * scale,
|
||||
y: data.decoration_pos_y * scale,
|
||||
image: decoration,
|
||||
offsetX: data.decoration_width * 0.5 * scale,
|
||||
offsetY: data.decoration_height * 0.5 * scale,
|
||||
rotation: data.decoration_rotation,
|
||||
width: data.decoration_width * scale,
|
||||
height: data.decoration_height * scale,
|
||||
draggable: draggable,
|
||||
});
|
||||
if (editMode && dec.id() === idToSelect) {
|
||||
transformer.nodes([dec]);
|
||||
transformer.moveToTop();
|
||||
}
|
||||
dec.on('click', function () {
|
||||
selectDecoration(this);
|
||||
});
|
||||
dec.on('tap', function () {
|
||||
selectDecoration(this);
|
||||
});
|
||||
dec.on('dragend', function () {
|
||||
saveDecTransformation(this);
|
||||
});
|
||||
dec.on('transformend', function () {
|
||||
saveDecTransformation(this);
|
||||
});
|
||||
// add the shape to the layer
|
||||
tableLayer.add(dec);
|
||||
tableLayer.draw();
|
||||
dec.moveToBottom();
|
||||
};
|
||||
decoration.src = 'images/decorations/' + data.decoration_image;
|
||||
return decoration;
|
||||
}
|
||||
var selectedDecoration = false;
|
||||
function selectDecoration(decoration) {
|
||||
if (editMode) {
|
||||
if ((transformer.nodes().length > 0 && transformer.nodes()[0] != decoration) || transformer.nodes().length == 0) {
|
||||
resetActiveTable();
|
||||
transformer.nodes([decoration]);
|
||||
decoration.moveToTop();
|
||||
transformer.moveToTop();
|
||||
selectedDecoration = decoration;
|
||||
toggleFloorplanControls();
|
||||
}
|
||||
else {
|
||||
transformer.nodes([]);
|
||||
selectedDecoration = false;
|
||||
$('.deleteDecoration').css('display', 'none');
|
||||
}
|
||||
}
|
||||
}
|
||||
function createTableElement(data, selectTable = false) {
|
||||
// Create container group
|
||||
let draggable = editMode || newTable === data.table_number;
|
||||
let table = new Konva.Group({
|
||||
x: data.pos_x * scale,
|
||||
y: data.pos_y * scale,
|
||||
draggable: draggable,
|
||||
listening: true,
|
||||
id: data.table_number.toString()
|
||||
});
|
||||
let fillColor = 'gray';
|
||||
if (data.status === 'reserved') {
|
||||
fillColor = 'lightgreen';
|
||||
}
|
||||
if (activeTables.includes(data.table_number)) {
|
||||
fillColor = 'lightblue';
|
||||
}
|
||||
data.width = data.width * scale;
|
||||
data.height = data.height * scale;
|
||||
// Create background shape
|
||||
let shape;
|
||||
switch (data.shape) {
|
||||
case "circle": // fall-through
|
||||
case "ellipse": // fall-through
|
||||
case "longellipse":
|
||||
shape = new Konva.Ellipse({
|
||||
x: 0,
|
||||
y: 0,
|
||||
radiusX: data.width * 0.5,
|
||||
radiusY: data.height * 0.5,
|
||||
rotation: data.rotation,
|
||||
fill: fillColor,
|
||||
stroke: "black",
|
||||
strokeWidth: 4,
|
||||
draggable: false,
|
||||
listening: true
|
||||
});
|
||||
break;
|
||||
default:
|
||||
shape = new Konva.Rect({
|
||||
x: 0,
|
||||
y: 0,
|
||||
offsetX: data.width * 0.5,
|
||||
offsetY: data.height * 0.5,
|
||||
width: data.width,
|
||||
height: data.height,
|
||||
rotation: data.rotation,
|
||||
fill: fillColor,
|
||||
stroke: "black",
|
||||
strokeWidth: 4,
|
||||
draggable: false,
|
||||
listening: true
|
||||
});
|
||||
break;
|
||||
} // End switch
|
||||
// Create label
|
||||
let label = new Konva.Text({
|
||||
x: data.width * -0.5,
|
||||
y: data.height * -0.5,
|
||||
width: data.width,
|
||||
height: data.height,
|
||||
text: data.table_number.toString(),
|
||||
fontSize: 40 * scale,
|
||||
fill: "black",
|
||||
align: "center",
|
||||
verticalAlign: "middle",
|
||||
draggable: false,
|
||||
listening: false
|
||||
});
|
||||
tableNumber = data.tablenumber;
|
||||
table.add(shape, label);
|
||||
table.on('dblclick', function () {
|
||||
tableNumber = parseInt(getTableNumber(this));
|
||||
if (!editMode) {
|
||||
loadScreen('orderScreen', 'table=' + tableNumber);
|
||||
}
|
||||
});
|
||||
table.on('dbltap', function () {
|
||||
tableNumber = getTableNumber(this);
|
||||
loadScreen('orderScreen', 'table=' + tableNumber);
|
||||
});
|
||||
table.on('dragend', function () {
|
||||
saveTransformation(table);
|
||||
});
|
||||
innerShape = getTableShape(table);
|
||||
table.on('click', function () {
|
||||
selectTableShape(this);
|
||||
});
|
||||
table.on('tap', function () {
|
||||
selectTableShape(this);
|
||||
});
|
||||
innerShape.on('transformend', function () {
|
||||
saveTransformation(table);
|
||||
});
|
||||
// add the shape to the layer
|
||||
tableLayer.add(table);
|
||||
table.moveToTop();
|
||||
if (tableNumber === selectedTableNumber) {
|
||||
selectTable = table;
|
||||
}
|
||||
if (selectTable) {
|
||||
if (selectTable === tableNumber) {
|
||||
table.fire('click');
|
||||
}
|
||||
}
|
||||
return table;
|
||||
}
|
||||
function loadRoom(room, selectTable = 0, selectDecoration = false) {
|
||||
//if (room === currentRoom) return false
|
||||
ajax(`/ajax/getRoomData/${room}`, null, 'GET', (response) => {
|
||||
let floorplanDiv = $('#tableMap');
|
||||
let backgroundImage = response.background_image;
|
||||
floorplanDiv.css("background-image", `url(images/rooms/${backgroundImage})`);
|
||||
floorplanDiv.css("background-size", `${width}px ${height}px`);
|
||||
}, null, null);
|
||||
$('.roomButton').removeClass('active');
|
||||
let selector = ".roomButton:contains('" + roomName + "')";
|
||||
$(selector).addClass('active');
|
||||
currentRoom = room;
|
||||
resetActiveTable();
|
||||
stage.destroy();
|
||||
stage = new Konva.Stage({
|
||||
container: 'tableMap',
|
||||
width: width,
|
||||
height: height,
|
||||
});
|
||||
transformer = new Konva.Transformer({
|
||||
rotationSnaps: [0, 15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 165, 180, 225, 270, -15, -30, -45, -60, -75, -90, -105, -120, -135, -150, -165, -180, -225, -270, 360, -360],
|
||||
anchorSize: 40 * scale,
|
||||
ignoreStroke: true,
|
||||
centeredScaling: true
|
||||
});
|
||||
let tablesAndDecorations = ajaxSync(`/ajax/getTablesAndDecorations/${room}`, null, 'GET');
|
||||
let decorations = tablesAndDecorations['decorations'];
|
||||
let tables = tablesAndDecorations['tables'];
|
||||
tableLayer = new Konva.Layer();
|
||||
tableLayer.add(transformer);
|
||||
// Loop data and call the creation method for each decoration/table.
|
||||
decorations.forEach(itemData => {
|
||||
createDecoration(itemData, selectDecoration);
|
||||
});
|
||||
tables.forEach(itemData => {
|
||||
tableLayer.add(createTableElement(itemData, selectTable));
|
||||
});
|
||||
activeTables = getOpenTables();
|
||||
stage.add(tableLayer);
|
||||
}
|
||||
var mergeMode = false;
|
||||
var parentMergeTable;
|
||||
var childMergeTable;
|
||||
var tableTransferOrigin;
|
||||
var transferMode = false;
|
||||
function transferModeOn() {
|
||||
mergeModeOff();
|
||||
if (!transferMode) {
|
||||
tableTransferOrigin = selectedTableNumber;
|
||||
transferMode = true;
|
||||
$('.transferTableButton').addClass('active');
|
||||
$('.transferTableButton').text('Select a table to transfer items to');
|
||||
}
|
||||
else {
|
||||
transferModeOff();
|
||||
}
|
||||
}
|
||||
function transferModeOff() {
|
||||
transferMode = false;
|
||||
$('.transferTableButton').removeClass('active');
|
||||
$('.transferTableButton').text(lang('transfer_table'));
|
||||
}
|
||||
let getOpenTables = () => {
|
||||
return ajaxSync('/ajax/getActiveTables/1', null, 'GET');
|
||||
};
|
||||
let transferTableAjax = (origin, destination) => {
|
||||
ajax(`/ajax/transferTables/${origin}/${destination}`, null, 'GET');
|
||||
};
|
||||
function transferTables() {
|
||||
destination = selectedTableNumber;
|
||||
origin = tableTransferOrigin;
|
||||
if (destination !== origin) {
|
||||
transferTableAjax(origin, destination);
|
||||
activeTables = getOpenTables();
|
||||
transferModeOff();
|
||||
getTableShape(selectedTable).fill('lightblue');
|
||||
getTableShape(getTableGroup(origin)).fill('gray');
|
||||
}
|
||||
else {
|
||||
alert("Can't transfer a table to itself.");
|
||||
transferModeOff();
|
||||
}
|
||||
}
|
||||
function mergeModeOn() {
|
||||
transferModeOff();
|
||||
if (!mergeMode) {
|
||||
mergeMode = true;
|
||||
$('.mergeButton').addClass('active');
|
||||
$('.mergeButton').text('Select a table to merge with Table ' + selectedTableNumber);
|
||||
parentMergeTable = selectedTableNumber;
|
||||
}
|
||||
else {
|
||||
mergeModeOff();
|
||||
}
|
||||
}
|
||||
function mergeModeOff() {
|
||||
mergeMode = false;
|
||||
$('.mergeButton').removeClass('active');
|
||||
$('.mergeButton').text(lang('merge_table'));
|
||||
}
|
||||
let ajaxMergeTables = (parent, child) => {
|
||||
return ajaxSync(`/ajax/mergeTables/${parent}/${child}`, null, 'GET');
|
||||
};
|
||||
let ajaxUnmergeTable = (parent) => {
|
||||
return ajaxSync(`/ajax/unmergeTable/${parent}`, null, 'GET');
|
||||
};
|
||||
function mergeTables() {
|
||||
parentMergeTable = parseInt(parentMergeTable);
|
||||
childMergeTable = parseInt(childMergeTable);
|
||||
if (childMergeTable !== parentMergeTable) {
|
||||
let result = ajaxMergeTables(parentMergeTable, childMergeTable);
|
||||
mergeModeOff();
|
||||
loadRoom(currentRoom);
|
||||
newTable = getTableGroup(parentMergeTable);
|
||||
newTable.draggable(true);
|
||||
if (tableIsOpen(parentMergeTable)) {
|
||||
getTableShape(newTable).fill('lightblue');
|
||||
}
|
||||
}
|
||||
else {
|
||||
alert("Can't merge a table with itself!");
|
||||
mergeModeOff();
|
||||
}
|
||||
}
|
||||
//When a table is passed (a group of the shape plus the text), returns the number as string.
|
||||
function getTableNumber(tableGroup) {
|
||||
textItem = tableGroup.getChildren()[1];
|
||||
return textItem.getText();
|
||||
}
|
||||
function getTableGroup(tableNumber) {
|
||||
return stage.find('#' + tableNumber)[0];
|
||||
}
|
||||
function getTableShape(tableGroup) {
|
||||
return tableGroup.getChildren()[0];
|
||||
}
|
||||
function getReservation(id) {
|
||||
return ajaxSync('/ajax/getReservation', id);
|
||||
}
|
||||
//When a user selects a table.
|
||||
function selectTableShape(table) {
|
||||
let tableNumber = getTableNumber(table);
|
||||
let shape = getTableShape(table);
|
||||
let strokeColor = shape.stroke();
|
||||
selectedTable = table;
|
||||
selectedTableNumber = tableNumber;
|
||||
if (transferMode)
|
||||
transferTables();
|
||||
if (mergeMode) {
|
||||
childMergeTable = tableNumber;
|
||||
mergeTables();
|
||||
}
|
||||
else {
|
||||
//If table is not selected
|
||||
if (strokeColor !== "yellow") {
|
||||
let tableData = getTableData(selectedTableNumber);
|
||||
let coverNumberString = lang('covers', tableData.default_covers.toString());
|
||||
let tableString = '<b>' + lang('activeTable', selectedTableNumber.toString()) + '</b>';
|
||||
$('.reserveTableButton').text(lang('reserve_table'));
|
||||
if (tableData.status === 'reserved') {
|
||||
let reservation = getReservation(tableData.reservation_id);
|
||||
console.log(reservation);
|
||||
$('.reserveTableButton').text(lang('unreserve_table'));
|
||||
if (reservation.reservation_name) {
|
||||
reservationString = lang('reserved_for', reservation.reservation_name);
|
||||
}
|
||||
else {
|
||||
reservationString = lang('reserved');
|
||||
}
|
||||
tableString += '<small>' + reservationString + '</small>';
|
||||
}
|
||||
tableString += "<small> (" + coverNumberString + ")</small>";
|
||||
$('.currentTable').html(tableString);
|
||||
stage.find('Rect').forEach(function (rect, index) {
|
||||
rect.stroke("black");
|
||||
});
|
||||
stage.find('Ellipse').forEach(function (circ, index) {
|
||||
circ.stroke("black");
|
||||
});
|
||||
shape.stroke("yellow");
|
||||
toggleEditControls(true);
|
||||
if (editMode) {
|
||||
toggleFloorplanControls();
|
||||
$('.deleteDecoration').css('display', 'none');
|
||||
transformer.nodes([getTableShape(table)]);
|
||||
table.moveToTop();
|
||||
transformer.moveToTop();
|
||||
}
|
||||
tableLayer.draw();
|
||||
//If the table is already selected
|
||||
}
|
||||
else {
|
||||
resetActiveTable();
|
||||
transformer.nodes([]);
|
||||
tableLayer.draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
let getTableData = (tableNumber) => {
|
||||
return ajaxSync('/ajax/getTableData', tableNumber);
|
||||
};
|
||||
let isTableMerged = (tableNumber) => {
|
||||
let mergeData = getTableData(tableNumber).merged_children;
|
||||
return mergeData !== "";
|
||||
};
|
||||
function resetActiveTable() {
|
||||
if (!transferMode) {
|
||||
if (selectedTable) {
|
||||
getTableShape(selectedTable).stroke('black');
|
||||
}
|
||||
selectedTable = null;
|
||||
selectedTableNumber = "";
|
||||
toggleFloorplanControls(false, editMode);
|
||||
toggleEditControls(false);
|
||||
}
|
||||
else {
|
||||
$('.editControls').css('display', 'none');
|
||||
}
|
||||
}
|
||||
function addDecoration(button) {
|
||||
let insertData = {
|
||||
decoration_room: currentRoom,
|
||||
basis: basis,
|
||||
decoration_image: $(button).data('image')
|
||||
};
|
||||
ajaxSync('/ajax/addDecoration', insertData);
|
||||
$('#decorator').css('display', 'none');
|
||||
selectedDecoration = false;
|
||||
loadRoom(currentRoom);
|
||||
}
|
||||
function deleteDecoration(decoration) {
|
||||
ajax('/ajax/deleteDecoration', decoration.id());
|
||||
$('.deleteDecoration').css('display', 'none');
|
||||
decoration.destroy();
|
||||
selectedDecoration = false;
|
||||
transformer.nodes([]);
|
||||
}
|
||||
function saveDecTransformation(decoration) {
|
||||
let newData = {
|
||||
decoration_id: decoration.id(),
|
||||
decoration_pos_x: decoration.x() / scale,
|
||||
decoration_pos_y: decoration.y() / scale,
|
||||
decoration_width: parseInt((decoration.scaleX() * decoration.width()) / scale),
|
||||
decoration_height: parseInt((decoration.scaleY() * decoration.height()) / scale),
|
||||
decoration_rotation: parseInt(decoration.rotation()),
|
||||
decoration_image: decodeURIComponent(decoration.image().src),
|
||||
decoration_room: currentRoom
|
||||
};
|
||||
if (editMode) {
|
||||
idToSelect = decoration.id();
|
||||
}
|
||||
ajax('/ajax/updateDecoration', newData);
|
||||
}
|
||||
//When a table has been resized, rotated etc.
|
||||
function saveTransformation(table) {
|
||||
tableNumber = getTableNumber(table);
|
||||
shape = getTableShape(table);
|
||||
newRotation = parseInt(shape.rotation());
|
||||
newWidth = parseInt(shape.scaleX() * shape.width() / scale);
|
||||
newHeight = parseInt((shape.scaleY() * shape.height()) / scale);
|
||||
newXPos = parseInt(table.x() / scale);
|
||||
newYPos = parseInt(table.y() / scale);
|
||||
updateData = {
|
||||
table_number: tableNumber,
|
||||
rotation: newRotation,
|
||||
width: newWidth,
|
||||
height: newHeight,
|
||||
pos_x: newXPos,
|
||||
pos_y: newYPos
|
||||
};
|
||||
transformTable(updateData);
|
||||
}
|
||||
let transformTable = (tableData) => {
|
||||
return ajax("/ajax/transformTable", tableData);
|
||||
};
|
||||
function unmergeTable() {
|
||||
ajaxUnmergeTable(selectedTableNumber);
|
||||
loadRoom(currentRoom);
|
||||
}
|
||||
function reserveTable(covers) {
|
||||
if (!covers) {
|
||||
showVirtualNumpad(lang('how_many_covers'), 2, false, false, true, reserveTable);
|
||||
}
|
||||
else {
|
||||
let table = getTableGroup(selectedTableNumber);
|
||||
let newReservation = ajaxSync('/ajax/newEmptyReservation', selectedTableNumber);
|
||||
table.fire('click');
|
||||
let tableShape = getTableShape(table);
|
||||
tableShape.fill('lightgreen');
|
||||
table.draw();
|
||||
table.fire('click');
|
||||
completeReservation(newReservation);
|
||||
}
|
||||
}
|
||||
function unreserveTable(input) {
|
||||
if (!input) {
|
||||
confirm(lang('confirm_delete_reservation', selectedTableNumber), selectedTableNumber, lang('confirm'), unreserveTable);
|
||||
}
|
||||
else {
|
||||
ajaxSync('/ajax/unreserveTable', input);
|
||||
hideAlerts();
|
||||
table = getTableGroup(input);
|
||||
table.fire('click');
|
||||
tableShape = getTableShape(table);
|
||||
tableShape.fill('gray');
|
||||
table.draw();
|
||||
table.fire('click');
|
||||
}
|
||||
}
|
||||
function completeReservation(resName) {
|
||||
if (!resName) {
|
||||
showVirtualKeyboard(lang('enter_reservation_name'));
|
||||
}
|
||||
else {
|
||||
//callPhpFunction('updateTableMapTable', [selectedTableNumber, 'reservation_name', resName]);
|
||||
loadRoom(currentRoom, selectedTableNumber);
|
||||
}
|
||||
}
|
||||
function toggleEditMode() {
|
||||
let editModeButton = $('.editModeButton');
|
||||
if (editMode === true) {
|
||||
editMode = false;
|
||||
loadRoom(currentRoom);
|
||||
editModeButton.removeClass('active');
|
||||
editModeButton.html(lang('edit_floorplan'));
|
||||
toggleFloorplanControls(false);
|
||||
if (selectedTable)
|
||||
selectedTable.fire('click');
|
||||
stage.find('Group').forEach(function (table, index) {
|
||||
table.draggable(false);
|
||||
});
|
||||
}
|
||||
else {
|
||||
editMode = true;
|
||||
stage.find('Group').forEach(function (table, index) {
|
||||
table.draggable(true);
|
||||
if (getTableShape(table).stroke() === "yellow") {
|
||||
table.moveToTop();
|
||||
transformer.nodes([getTableShape(table)]);
|
||||
transformer.moveToTop();
|
||||
}
|
||||
});
|
||||
stage.find('Image').forEach(function (img, index) {
|
||||
img.draggable(true);
|
||||
});
|
||||
toggleFloorplanControls();
|
||||
transformer.moveToTop();
|
||||
tableLayer.draw();
|
||||
editModeButton.addClass('active');
|
||||
editModeButton.html(lang('stop_edit_floorplan'));
|
||||
}
|
||||
}
|
||||
function toggleFloorplanControls(onOrOff = true, subControlsOnly = false) {
|
||||
if (onOrOff || subControlsOnly) {
|
||||
$('.floorplanControls').css('visibility', 'visible');
|
||||
}
|
||||
else {
|
||||
$('.floorplanControls').css('visibility', 'hidden');
|
||||
}
|
||||
if (selectedTable) {
|
||||
$('.changeShapeButton').css('visibility', 'visible');
|
||||
$('.deleteTableButton').css('visibility', 'visible');
|
||||
}
|
||||
else {
|
||||
$('.changeShapeButton').css('visibility', 'hidden');
|
||||
$('.deleteTableButton').css('visibility', 'hidden');
|
||||
}
|
||||
if (selectedDecoration) {
|
||||
$('.deleteDecoration').css('display', 'flex');
|
||||
}
|
||||
else {
|
||||
$('.deleteDecoration').css('display', 'none');
|
||||
}
|
||||
}
|
||||
let tableIsOpen = (tableNumber) => {
|
||||
return ajaxSync(`/ajax/tableIsOpen/${tableNumber}`, null, 'GET');
|
||||
};
|
||||
function toggleEditControls(onOrOff = true) {
|
||||
if (onOrOff) {
|
||||
$('.editControls').css("display", "flex");
|
||||
if (isTableMerged(selectedTableNumber)) {
|
||||
$('.mergeControls').css("visibility", "visible");
|
||||
$('.unmergeButton').css('display', 'flex');
|
||||
$('.mergeButton').css('display', 'flex');
|
||||
}
|
||||
else {
|
||||
$('.mergeControls').css("visibility", "visible");
|
||||
$('.mergeButton').css('display', 'flex');
|
||||
$('.unmergeButton').css('display', 'none');
|
||||
}
|
||||
if (tableIsOpen(selectedTableNumber)) {
|
||||
$('.payTableButton').css('display', 'flex');
|
||||
$('.viewTableButton').css('display', 'flex');
|
||||
$('.reserveTableButton').css('display', 'none');
|
||||
$('.transferTableButton').css('display', 'flex');
|
||||
}
|
||||
else {
|
||||
$('.payTableButton').css('display', 'none');
|
||||
$('.viewTableButton').css('display', 'none');
|
||||
$('.reserveTableButton').css('display', 'flex');
|
||||
$('.transferTableButton').css('display', 'none');
|
||||
}
|
||||
}
|
||||
else {
|
||||
$('.editControls').css("display", "none");
|
||||
$('.mergeControls').css("visibility", "hidden");
|
||||
$('.mergeButton').css("display", "none");
|
||||
$('.unmergeButton').css("display", "none");
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=dredgepos.floorplan.js.map
|
||||
1
wwwroot/scripts/js/dredgepos.floorplan.js.map
Normal file
1
wwwroot/scripts/js/dredgepos.floorplan.js.map
Normal file
File diff suppressed because one or more lines are too long
10881
wwwroot/scripts/js/jquery.js
vendored
Normal file
10881
wwwroot/scripts/js/jquery.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
216
wwwroot/scripts/js/keyboards.js
Normal file
216
wwwroot/scripts/js/keyboards.js
Normal file
@@ -0,0 +1,216 @@
|
||||
let showVirtualNumpad = (heading, maxlength = 4, isPassword, allowDecimals = true, allowClose = true, submitFunction) => {
|
||||
let numpad = $('#virtualNumpad');
|
||||
let inputBox = $('#virtualNumpadInput');
|
||||
let closeKeyboardButton = $('.closeKeyboards');
|
||||
numpad.css('display', 'flex');
|
||||
let showCloseButton = allowClose ? 'flex' : 'none';
|
||||
closeKeyboardButton.css('display', showCloseButton);
|
||||
$('#virtualNumpadHeading').html(heading);
|
||||
/*
|
||||
The numpad always submits to a function.
|
||||
If a function isn't specified, it will submit
|
||||
to the same function that called it
|
||||
*/
|
||||
numpad.data('value', '');
|
||||
inputBox.text('');
|
||||
numpad.data('maxlength', maxlength);
|
||||
numpad.data('submitfunction', submitFunction);
|
||||
numpad.data('password', isPassword);
|
||||
numpad.data('allowdecimals', allowDecimals);
|
||||
$(document).unbind('keyup');
|
||||
$(document).keyup(e => {
|
||||
let key = e.key;
|
||||
switch (key) {
|
||||
case 'Backspace':
|
||||
case 'Delete':
|
||||
key = 'clear';
|
||||
break;
|
||||
case 'Enter':
|
||||
key = 'submit';
|
||||
break;
|
||||
}
|
||||
virtualNumpadInput(key);
|
||||
});
|
||||
};
|
||||
let hideVirtualKeyboard = () => {
|
||||
let keyboard = $('#virtualKeyboard');
|
||||
keyboard.hide();
|
||||
$('#virtualKeyboardHeading').html('');
|
||||
$(document).unbind('keyup');
|
||||
};
|
||||
let hideVirtualNumpad = () => {
|
||||
let numpad = $('#virtualNumpad');
|
||||
numpad.css('display', 'none');
|
||||
$('#virtualNumpadHeading').html('');
|
||||
$(document).unbind('keyup');
|
||||
};
|
||||
let virtualNumpadInput = (input) => {
|
||||
let inputBox = $('#virtualNumpadInput');
|
||||
let numpad = $('#virtualNumpad');
|
||||
let maxlength = numpad.data('maxlength');
|
||||
let allowDecimals = numpad.data('allowdecimals');
|
||||
let submitFunction = numpad.data('submitfunction');
|
||||
let allowedValues = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'submit', 'clear'];
|
||||
let currentValue = numpad.data('value').toString();
|
||||
//Test
|
||||
if (allowDecimals)
|
||||
allowedValues.push('.', ',');
|
||||
let validInput = allowedValues.includes(input);
|
||||
//If the input is a valid number, decimal point or command.
|
||||
if (validInput) {
|
||||
switch (input) {
|
||||
case 'submit':
|
||||
hideVirtualNumpad();
|
||||
let numpadValue = numpad.data('value').length > 0 ? numpad.data('value') : "0";
|
||||
submitFunction(numpadValue);
|
||||
break;
|
||||
case 'clear':
|
||||
clearNumpadInput();
|
||||
break;
|
||||
default:
|
||||
let newText = currentValue + input;
|
||||
let isPassword = numpad.data('password');
|
||||
let length = input.length + inputBox.text().length;
|
||||
if (length <= maxlength) {
|
||||
inputBox.append(isPassword ? '*' : input);
|
||||
numpad.data('value', newText);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
let clearNumpadInput = () => {
|
||||
$('#virtualNumpadInput').text("");
|
||||
$('#virtualNumpad').data('value', '');
|
||||
};
|
||||
let setupVirtualNumpad = () => {
|
||||
$(document).on('click', '.virtualNumpadButton', e => {
|
||||
virtualNumpadInput($(e.target).data('value').toString());
|
||||
});
|
||||
$('.closeKeyboards').on('click', () => {
|
||||
hideVirtualKeyboard();
|
||||
hideVirtualNumpad();
|
||||
});
|
||||
};
|
||||
let setupVirtualKeyboard = () => {
|
||||
Application.keyboard = {
|
||||
capsLock: false,
|
||||
shift: false,
|
||||
layout: 'default'
|
||||
};
|
||||
$(document).on('click', '.virtualKeyboardButton', e => {
|
||||
virtualKeyboardInput($(e.target).data('value'));
|
||||
});
|
||||
setKeyboardLayout('default');
|
||||
};
|
||||
let showVirtualKeyboard = (heading, maxlength = 32, isPassword = false, submitFunction = () => {
|
||||
hideVirtualKeyboard();
|
||||
}) => {
|
||||
let keyboard = $('#virtualKeyboard');
|
||||
let inputBox = $('#virtualKeyboardInput');
|
||||
keyboard.css('display', 'flex');
|
||||
$('#virtualKeyboardHeading').html(heading);
|
||||
keyboard.data('value', '');
|
||||
inputBox.text('');
|
||||
keyboard.data('maxlength', maxlength);
|
||||
keyboard.data('password', isPassword);
|
||||
keyboard.data('submitfunction', submitFunction);
|
||||
$(document).off('keyup');
|
||||
$(document).on('keyup', e => {
|
||||
let key = e.key;
|
||||
if (key == 'Enter')
|
||||
key = 'submit';
|
||||
virtualKeyboardInput(key);
|
||||
});
|
||||
};
|
||||
let virtualKeyboardInput = (input) => {
|
||||
let inputBox = $('#virtualKeyboardInput');
|
||||
let keyboard = $('#virtualKeyboard');
|
||||
let maxlength = keyboard.data('maxlength');
|
||||
let isPassword = keyboard.data('password');
|
||||
let length = input.length + inputBox.text().length;
|
||||
switch (input.toLowerCase()) {
|
||||
case 'backspace':
|
||||
case 'delete':
|
||||
let newText = inputBox.text().slice(0, -1);
|
||||
inputBox.text(newText);
|
||||
keyboard.data('value', newText);
|
||||
break;
|
||||
case 'submit':
|
||||
hideVirtualKeyboard();
|
||||
let submitFunction = keyboard.data('submitfunction');
|
||||
submitFunction();
|
||||
break;
|
||||
case 'shift':
|
||||
if (Application.keyboard.capsLock)
|
||||
break;
|
||||
Application.keyboard.shift = !Application.keyboard.shift;
|
||||
Application.keyboard.capsLock = false;
|
||||
setKeyboardLayout('default', Application.keyboard.shift ? 'shift' : '');
|
||||
break;
|
||||
case 'capslock':
|
||||
Application.keyboard.shift = false;
|
||||
Application.keyboard.capsLock = !Application.keyboard.capsLock;
|
||||
let capsLockButton = $('[data-value="capslock"]');
|
||||
capsLockButton.toggleClass('active');
|
||||
setKeyboardLayout('default', Application.keyboard.capsLock ? 'shift' : '');
|
||||
break;
|
||||
case 'space':
|
||||
input = ' ';
|
||||
break;
|
||||
}
|
||||
//Stops keys such as F5 being pressed.
|
||||
if (input.length == 1) {
|
||||
if (Application.keyboard.shift || Application.keyboard.capsLock) {
|
||||
input = input.toUpperCase();
|
||||
}
|
||||
let newText = inputBox.text() + input;
|
||||
keyboard.data('value', newText);
|
||||
inputBox.text(newText);
|
||||
//If shift, reload lowercase
|
||||
if (Application.keyboard.shift) {
|
||||
Application.keyboard.shift = false;
|
||||
setKeyboardLayout('default');
|
||||
}
|
||||
}
|
||||
};
|
||||
let setKeyboardLayout = (layout, modifier = '') => {
|
||||
let keyboardLayout = ajaxSync('/languages/english/keyboardLayout.json', null, 'get');
|
||||
if (modifier != '')
|
||||
modifier = `_${modifier}`;
|
||||
$('.virtualKeyboardRow').each((index, row) => {
|
||||
/*
|
||||
We start at 1 instead of 0. Makes it easier for non-programmers
|
||||
and translators making their own language packs
|
||||
*/
|
||||
index = index + 1;
|
||||
let currentRow = keyboardLayout[layout]["row" + index + modifier];
|
||||
$(row).children('a').each((keyIndex, button) => {
|
||||
let key = $(button);
|
||||
let keyValue = currentRow[keyIndex];
|
||||
/*
|
||||
KeyText is the text that appears
|
||||
in the button. KeyData is the value
|
||||
submitted when the button is pressed.
|
||||
*/
|
||||
let keyText = keyValue;
|
||||
let keyData = keyValue;
|
||||
key.addClass('posButton');
|
||||
key.addClass('virtualKeyboardButton');
|
||||
let pattern = new RegExp(/\[([^)]+)\]/);
|
||||
let matches = keyValue.match(pattern);
|
||||
if (matches) {
|
||||
keyText = keyValue.replace(pattern, '');
|
||||
keyData = matches[1];
|
||||
}
|
||||
key.html(keyText);
|
||||
//Use attr() as some keys have CSS dependent on data-value
|
||||
key.attr('data-value', keyData);
|
||||
key.data('value', keyData);
|
||||
});
|
||||
});
|
||||
};
|
||||
$(() => {
|
||||
setupVirtualNumpad();
|
||||
setupVirtualKeyboard();
|
||||
});
|
||||
//# sourceMappingURL=keyboards.js.map
|
||||
1
wwwroot/scripts/js/keyboards.js.map
Normal file
1
wwwroot/scripts/js/keyboards.js.map
Normal file
File diff suppressed because one or more lines are too long
18100
wwwroot/scripts/js/konva.js
Normal file
18100
wwwroot/scripts/js/konva.js
Normal file
File diff suppressed because it is too large
Load Diff
12
wwwroot/scripts/js/konva.min.js
vendored
Normal file
12
wwwroot/scripts/js/konva.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
wwwroot/scripts/js/types.js
Normal file
1
wwwroot/scripts/js/types.js
Normal file
@@ -0,0 +1 @@
|
||||
//# sourceMappingURL=types.js.map
|
||||
1
wwwroot/scripts/js/types.js.map
Normal file
1
wwwroot/scripts/js/types.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"types.js","sourceRoot":"","sources":["../ts/types.ts"],"names":[],"mappings":""}
|
||||
15
wwwroot/scripts/ts/dredgepos.authenticate.ts
Normal file
15
wwwroot/scripts/ts/dredgepos.authenticate.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
let showLoginBox = () => {
|
||||
showVirtualNumpad('Enter Login Code', 6, true, false, false, authenticate)
|
||||
}
|
||||
|
||||
let authenticate = (input : string) => {
|
||||
let login = ajaxSync('/ajax/authenticateClerk', input)
|
||||
if(login === 'success')
|
||||
redirect('/floorplan')
|
||||
else
|
||||
showLoginBox()
|
||||
}
|
||||
|
||||
$(() => {
|
||||
showLoginBox()
|
||||
})
|
||||
118
wwwroot/scripts/ts/dredgepos.core.ts
Normal file
118
wwwroot/scripts/ts/dredgepos.core.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
let Application : ApplicationState = {
|
||||
keyboard : null,
|
||||
mode: "default",
|
||||
languageVars: {}
|
||||
}
|
||||
|
||||
|
||||
/** Parses a language variable. */
|
||||
let lang = (key: string, replacements?: string[] | string) => {
|
||||
let finalValue = Application.languageVars[key]
|
||||
|
||||
if(!replacements) return finalValue
|
||||
if(typeof replacements === 'string') replacements = [replacements]
|
||||
|
||||
replacements.forEach( (replacement, index) => {
|
||||
let correctIndex = index+1
|
||||
finalValue = finalValue.replace(`[${correctIndex}]`, replacement)
|
||||
})
|
||||
|
||||
return finalValue
|
||||
}
|
||||
|
||||
/** Check if a variable is defined */
|
||||
let defined = (variable: any) => {
|
||||
return typeof variable !== 'undefined'
|
||||
}
|
||||
|
||||
/** Call an Ajax function asynchronously */
|
||||
let ajax = (endpoint : string, data: any, method = 'POST', successFunction : Function , errorFunction : JQuery.Ajax.ErrorCallback<any>, beforeFunction: any) => {
|
||||
data = (data == null) ? data : JSON.stringify(data)
|
||||
return $.ajax({
|
||||
url: endpoint,
|
||||
method: method,
|
||||
data: data,
|
||||
success: (response) => {
|
||||
if(successFunction)
|
||||
successFunction(JSON.parse(response.data))
|
||||
},
|
||||
error: errorFunction,
|
||||
beforeSend: beforeFunction
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
For the flow of the app, synchronous is commonly preferred
|
||||
though trying to keep it's usage as low as possible.
|
||||
*/
|
||||
let ajaxSync = (endpoint : string, data?: any, method = 'POST') => {
|
||||
let response = JSON.parse(
|
||||
$.ajax({
|
||||
url: endpoint,
|
||||
method: method,
|
||||
data: JSON.stringify(data),
|
||||
async:false,
|
||||
}).responseText)
|
||||
|
||||
if(response.data) {
|
||||
response.data = JSON.parse(response.data)
|
||||
return response.data
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
/* Redirect to a specific URL */
|
||||
let redirect = (url: string) : void => {
|
||||
window.location.href = url
|
||||
}
|
||||
|
||||
|
||||
let setLanguageVariables = () => {
|
||||
Application.languageVars = ajaxSync('/ajax/languageVars', null, 'GET')
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
let alert = (message: string, title='Message') => {
|
||||
let alertBox = $('#alert')
|
||||
alertBox.css('display', 'flex');
|
||||
alertBox.data('value', '');
|
||||
$('#alertHeading').text(title);
|
||||
$('#alertMessage').text(message);
|
||||
|
||||
$('#alertOk').css('display', 'flex');
|
||||
$('#alertYes').css('display', 'none');
|
||||
$('#alertNo').css('display', 'none');
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
let confirm = (message: string, data: any, title='Confirm', submitFunction = (data: any) => {hideAlerts()}) => {
|
||||
let alert = $('#alert')
|
||||
|
||||
$(document).on('click', '#alert #alertYes', () => {
|
||||
submitFunction(data)
|
||||
hideAlerts()
|
||||
$(document).off('click', '#alert #alertYes')
|
||||
})
|
||||
|
||||
alert.css('display', 'flex')
|
||||
$('#alertHeading').html(title)
|
||||
$('#alertMessage').html(message)
|
||||
|
||||
$('#alertOk').css('display', 'none')
|
||||
$('#alertYes').css('display', 'flex')
|
||||
$('#alertNo').css('display', 'flex')
|
||||
}
|
||||
|
||||
|
||||
let hideAlerts = () => {
|
||||
$('#alert').hide()
|
||||
}
|
||||
|
||||
$( () => {
|
||||
let doc = $(document)
|
||||
setLanguageVariables()
|
||||
|
||||
doc.on('click', '#alertNo, #alertOk', () => $('#alert').hide())
|
||||
})
|
||||
849
wwwroot/scripts/ts/dredgepos.floorplan.ts
Normal file
849
wwwroot/scripts/ts/dredgepos.floorplan.ts
Normal file
@@ -0,0 +1,849 @@
|
||||
/// <reference path="./typings/konva.d.ts" />
|
||||
let stage : Konva.Stage
|
||||
let transformer: Konva.Transformer;
|
||||
let tableLayer: Konva.Layer;
|
||||
let editMode = false;
|
||||
let activeTables : number[] = [];
|
||||
let selectedTable : table;
|
||||
let selectedTableNumber : number;
|
||||
let currentRoom : number;
|
||||
let basis = 1280;
|
||||
let scale : number = 1;
|
||||
let newTable : number;
|
||||
let roomName : string;
|
||||
|
||||
//Makes sure canvas always fits inside the div
|
||||
function getDimensions(parentDiv : JQuery) {
|
||||
let tableMap = $('#tableMap')
|
||||
let outerWidth = parentDiv.outerWidth();
|
||||
let outerHeight = parentDiv.outerHeight();
|
||||
|
||||
let width = outerWidth;
|
||||
let height = outerWidth;
|
||||
|
||||
if (outerWidth >= outerHeight) {
|
||||
width = outerHeight;
|
||||
height = outerHeight;
|
||||
}
|
||||
|
||||
tableMap.height(height)
|
||||
tableMap.width(width)
|
||||
scale = width / basis
|
||||
|
||||
return {width: width, height:height}
|
||||
}
|
||||
|
||||
function setupTableMap() {
|
||||
let doc = $(document)
|
||||
activeTables = ajaxSync('/ajax/getActiveTables/1', null, 'GET');
|
||||
|
||||
let dimensions = getDimensions($('#mapContainer'));
|
||||
roomName = 'Deck & Courtyard';
|
||||
stage = new Konva.Stage({
|
||||
container: 'tableMap',
|
||||
width: dimensions.width,
|
||||
height: dimensions.height,
|
||||
});
|
||||
|
||||
$('body').on('click', '.editModeButton', () => {toggleEditMode()} )
|
||||
|
||||
$('.roomButton').on('click', function () {
|
||||
roomName = $(this).text();
|
||||
loadRoom($(this).data('value'));
|
||||
});
|
||||
$('.transferTableButton').on('click', function () {
|
||||
transferModeOn();
|
||||
});
|
||||
$('.addDecoration').on('click', function () {
|
||||
$('#decorator').css('display', 'flex');
|
||||
});
|
||||
$('.deleteDecoration').on('click', function () {
|
||||
deleteDecoration(selectedDecoration);
|
||||
});
|
||||
$('.decoratorItem').on('click', function () {
|
||||
addDecoration(this);
|
||||
});
|
||||
$('.changeShapeButton').on('click', function () {
|
||||
changeTableShape(selectedTableNumber);
|
||||
});
|
||||
$('.reserveTableButton').on('click', function () {
|
||||
if ($(this).text() === lang('reserve_table')) {
|
||||
reserveTable();
|
||||
}
|
||||
else {
|
||||
unreserveTable();
|
||||
}
|
||||
});
|
||||
$('.addTableButton').on('click', function () {
|
||||
addTable();
|
||||
});
|
||||
$('.deleteTableButton').on('click', function () {
|
||||
deleteTable();
|
||||
});
|
||||
loadRoom(roomToLoad);
|
||||
}
|
||||
|
||||
let updateTableShape = (tableData) => {
|
||||
return ajaxSync('/ajax/updateTableShape', tableData)
|
||||
}
|
||||
|
||||
//Change the shape of a table in edit mode.
|
||||
function changeTableShape(tableNumber: number) {
|
||||
let tableData = getTableData(tableNumber)
|
||||
let tableShape = tableData['shape']
|
||||
let tableWidth = tableData['width']
|
||||
let tableHeight = tableData['height']
|
||||
let tableRotation = tableData['rotation']
|
||||
|
||||
let order = ['square', 'rect', 'longrect', 'diamond', 'circle', 'ellipse', 'longellipse']
|
||||
|
||||
if (order.indexOf(tableShape) === -1) tableShape = 'square'
|
||||
|
||||
//What the next shape is
|
||||
let currentIndex = order.indexOf(tableShape)
|
||||
let nextIndex = currentIndex + 1
|
||||
if (nextIndex > (order.length) - 1) nextIndex = 0
|
||||
|
||||
let nextShape = order[nextIndex]
|
||||
|
||||
switch(nextShape) {
|
||||
case 'square':
|
||||
case 'circle':
|
||||
tableHeight = tableWidth
|
||||
tableRotation = 0
|
||||
break
|
||||
case 'diamond':
|
||||
tableHeight = tableWidth
|
||||
tableRotation = 45
|
||||
break
|
||||
case 'rect':
|
||||
case 'ellipse':
|
||||
tableHeight = tableWidth * 2
|
||||
tableRotation = 0
|
||||
break
|
||||
case 'longrect':
|
||||
case 'longellipse':
|
||||
tableRotation = 90
|
||||
break
|
||||
}
|
||||
|
||||
let updateData = {
|
||||
table_number: tableNumber,
|
||||
shape: nextShape,
|
||||
height: tableHeight,
|
||||
width: tableWidth,
|
||||
rotation: tableRotation
|
||||
}
|
||||
|
||||
tableData = updateTableShape(updateData)
|
||||
let tableGroup = stage.find('#' + tableNumber)[0]
|
||||
transformer.nodes([]);
|
||||
tableGroup.destroy();
|
||||
|
||||
let newTable = createTableElement(tableData);
|
||||
tableLayer.add(newTable);
|
||||
stage.draw();
|
||||
|
||||
selectTable(tableNumber);
|
||||
loadRoom(currentRoom, tableNumber);
|
||||
}
|
||||
|
||||
let createTable = (tableData) => {
|
||||
return ajaxSync('/ajax/createTable', tableData)
|
||||
}
|
||||
|
||||
let tableExists = (tableNumber : number) => {
|
||||
return ajaxSync(`/ajax/tableExists/${tableNumber}`)
|
||||
}
|
||||
|
||||
function addTable(tableNumber : number) {
|
||||
if (!tableNumber) {
|
||||
showVirtualNumpad(lang('new_table_number'), 4, false, false, true, addTable);
|
||||
}
|
||||
else {
|
||||
let newTableInfo = {
|
||||
table_number: tableNumber,
|
||||
room_id: currentRoom,
|
||||
default_covers: 2,
|
||||
width: 200,
|
||||
height: 200,
|
||||
rotation: 0,
|
||||
pos_x: basis / 2,
|
||||
pos_y: basis / 2,
|
||||
shape: 'square',
|
||||
merged_children : '',
|
||||
previous_state: '',
|
||||
status: 0,
|
||||
reservation: 0,
|
||||
venue_id: 1
|
||||
};
|
||||
|
||||
let newTableData = createTable(newTableInfo)
|
||||
|
||||
if (!newTableData.table_number){
|
||||
alert(newTableData)
|
||||
return false
|
||||
}
|
||||
|
||||
newTable = createTableElement(newTableData);
|
||||
tableLayer.add(newTable);
|
||||
tableLayer.draw();
|
||||
selectTable(tableNumber);
|
||||
|
||||
}
|
||||
}
|
||||
function selectTable(tableNumber: number) {
|
||||
let table = stage.find('#' + tableNumber)[0];
|
||||
table.fire('click');
|
||||
}
|
||||
|
||||
function deleteTable(tableNumber = 0) {
|
||||
if (!tableNumber) {
|
||||
confirm(lang('confirm_delete_table', selectedTableNumber), selectedTableNumber, 'Confirm', deleteTable);
|
||||
}
|
||||
else {
|
||||
if (tableIsOpen(selectedTableNumber)) {
|
||||
alert(lang('error_delete_existing_table'));
|
||||
}
|
||||
else {
|
||||
ajax(`/ajax/deleteTable/${selectedTableNumber}`, null, 'GET');
|
||||
let table = stage.find('#' + tableNumber)[0];
|
||||
transformer.nodes([]);
|
||||
table.destroy();
|
||||
tableLayer.draw();
|
||||
selectedTable = null
|
||||
selectedTableNumber = null
|
||||
}
|
||||
}
|
||||
}
|
||||
// Rotate a shape around any point.
|
||||
// shape is a Konva shape
|
||||
// angleDegrees is the angle to rotate by, in degrees.
|
||||
// point is an object {x: posX, y: posY}
|
||||
function rotateAroundPoint(shape, angleDegrees, point) {
|
||||
let angleRadians = angleDegrees * Math.PI / 180;
|
||||
// they lied, I did have to use trigonometry
|
||||
const x = point.x +
|
||||
(shape.x() - point.x) * Math.cos(angleRadians) -
|
||||
(shape.y() - point.y) * Math.sin(angleRadians);
|
||||
const y = point.y +
|
||||
(shape.x() - point.x) * Math.sin(angleRadians) +
|
||||
(shape.y() - point.y) * Math.cos(angleRadians);
|
||||
shape.rotation(shape.rotation() + angleDegrees); // rotate the shape in place
|
||||
shape.x(x); // move the rotated shape in relation to the rotation point.
|
||||
shape.y(y);
|
||||
}
|
||||
|
||||
function createDecoration(data, idToSelect = false) {
|
||||
let draggable = editMode;
|
||||
var decoration = new Image();
|
||||
decoration.onload = function () {
|
||||
var dec = new Konva.Image({
|
||||
id: data.decoration_id.toString(),
|
||||
x: data.decoration_pos_x * scale,
|
||||
y: data.decoration_pos_y * scale,
|
||||
image: decoration,
|
||||
offsetX: data.decoration_width * 0.5 * scale,
|
||||
offsetY: data.decoration_height * 0.5 * scale,
|
||||
rotation: data.decoration_rotation,
|
||||
width: data.decoration_width * scale,
|
||||
height: data.decoration_height * scale,
|
||||
draggable: draggable,
|
||||
});
|
||||
|
||||
if (editMode && dec.id() === idToSelect) {
|
||||
transformer.nodes([dec]);
|
||||
transformer.moveToTop();
|
||||
}
|
||||
|
||||
|
||||
dec.on('click', function () {
|
||||
selectDecoration(this);
|
||||
});
|
||||
dec.on('tap', function () {
|
||||
selectDecoration(this);
|
||||
});
|
||||
dec.on('dragend', function () {
|
||||
saveDecTransformation(this);
|
||||
});
|
||||
|
||||
dec.on('transformend', function () {
|
||||
saveDecTransformation(this);
|
||||
});
|
||||
// add the shape to the layer
|
||||
tableLayer.add(dec);
|
||||
tableLayer.draw();
|
||||
dec.moveToBottom();
|
||||
};
|
||||
decoration.src = 'images/decorations/' + data.decoration_image;
|
||||
return decoration;
|
||||
}
|
||||
|
||||
var selectedDecoration = false;
|
||||
function selectDecoration(decoration) {
|
||||
if (editMode) {
|
||||
if ((transformer.nodes().length > 0 && transformer.nodes()[0] != decoration) || transformer.nodes().length == 0) {
|
||||
resetActiveTable();
|
||||
transformer.nodes([decoration]);
|
||||
decoration.moveToTop();
|
||||
transformer.moveToTop();
|
||||
selectedDecoration = decoration;
|
||||
toggleFloorplanControls();
|
||||
}
|
||||
else {
|
||||
transformer.nodes([]);
|
||||
selectedDecoration = false;
|
||||
$('.deleteDecoration').css('display', 'none');
|
||||
}
|
||||
}
|
||||
}
|
||||
function createTableElement(data, selectTable = false) {
|
||||
// Create container group
|
||||
|
||||
let draggable = editMode || newTable === data.table_number;
|
||||
|
||||
let table = new Konva.Group({
|
||||
x: data.pos_x * scale,
|
||||
y: data.pos_y * scale,
|
||||
draggable: draggable,
|
||||
listening: true,
|
||||
id: data.table_number.toString()
|
||||
});
|
||||
let fillColor = 'gray';
|
||||
if (data.status === 'reserved') {
|
||||
fillColor = 'lightgreen';
|
||||
}
|
||||
if (activeTables.includes(data.table_number)) {
|
||||
fillColor = 'lightblue';
|
||||
}
|
||||
data.width = data.width * scale;
|
||||
data.height = data.height * scale;
|
||||
// Create background shape
|
||||
let shape;
|
||||
switch (data.shape) {
|
||||
case "circle": // fall-through
|
||||
case "ellipse": // fall-through
|
||||
case "longellipse":
|
||||
shape = new Konva.Ellipse({
|
||||
x: 0,
|
||||
y: 0,
|
||||
radiusX: data.width * 0.5,
|
||||
radiusY: data.height * 0.5,
|
||||
rotation: data.rotation,
|
||||
fill: fillColor,
|
||||
stroke: "black",
|
||||
strokeWidth: 4,
|
||||
draggable: false,
|
||||
listening: true
|
||||
});
|
||||
break;
|
||||
default:
|
||||
shape = new Konva.Rect({
|
||||
x: 0,
|
||||
y: 0,
|
||||
offsetX: data.width * 0.5,
|
||||
offsetY: data.height * 0.5,
|
||||
width: data.width,
|
||||
height: data.height,
|
||||
rotation: data.rotation,
|
||||
fill: fillColor,
|
||||
stroke: "black",
|
||||
strokeWidth: 4,
|
||||
draggable: false,
|
||||
listening: true
|
||||
});
|
||||
break;
|
||||
} // End switch
|
||||
// Create label
|
||||
let label = new Konva.Text({
|
||||
x: data.width * -0.5,
|
||||
y: data.height * -0.5,
|
||||
width: data.width,
|
||||
height: data.height,
|
||||
text: data.table_number.toString(),
|
||||
fontSize: 40 * scale,
|
||||
fill: "black",
|
||||
align: "center",
|
||||
verticalAlign: "middle",
|
||||
draggable: false,
|
||||
listening: false
|
||||
});
|
||||
tableNumber = data.tablenumber;
|
||||
table.add(shape, label);
|
||||
table.on('dblclick', function () {
|
||||
tableNumber = parseInt(getTableNumber(this));
|
||||
if (!editMode) {
|
||||
loadScreen('orderScreen', 'table=' + tableNumber);
|
||||
}
|
||||
});
|
||||
table.on('dbltap', function () {
|
||||
tableNumber = getTableNumber(this);
|
||||
loadScreen('orderScreen', 'table=' + tableNumber);
|
||||
});
|
||||
table.on('dragend', function () {
|
||||
saveTransformation(table);
|
||||
});
|
||||
innerShape = getTableShape(table);
|
||||
table.on('click', function () {
|
||||
selectTableShape(this);
|
||||
});
|
||||
table.on('tap', function () {
|
||||
selectTableShape(this);
|
||||
});
|
||||
innerShape.on('transformend', function () {
|
||||
saveTransformation(table);
|
||||
});
|
||||
// add the shape to the layer
|
||||
tableLayer.add(table);
|
||||
table.moveToTop();
|
||||
if (tableNumber === selectedTableNumber) {
|
||||
selectTable = table;
|
||||
}
|
||||
if (selectTable) {
|
||||
if (selectTable === tableNumber) {
|
||||
table.fire('click');
|
||||
}
|
||||
}
|
||||
return table;
|
||||
}
|
||||
function loadRoom(room: number, selectTable : number = 0, selectDecoration = false) {
|
||||
//if (room === currentRoom) return false
|
||||
|
||||
ajax(`/ajax/getRoomData/${room}`, null, 'GET', (response) => {
|
||||
let floorplanDiv = $('#tableMap')
|
||||
let backgroundImage = response.background_image
|
||||
floorplanDiv.css("background-image", `url(images/rooms/${backgroundImage})`)
|
||||
floorplanDiv.css("background-size", `${width}px ${height}px`)
|
||||
}, null, null)
|
||||
|
||||
$('.roomButton').removeClass('active');
|
||||
let selector = ".roomButton:contains('" + roomName + "')";
|
||||
$(selector).addClass('active');
|
||||
currentRoom = room;
|
||||
resetActiveTable();
|
||||
stage.destroy();
|
||||
stage = new Konva.Stage({
|
||||
container: 'tableMap',
|
||||
width: width,
|
||||
height: height,
|
||||
});
|
||||
|
||||
transformer = new Konva.Transformer({
|
||||
rotationSnaps: [0, 15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 165, 180, 225, 270, -15, -30, -45, -60, -75, -90, -105, -120, -135, -150, -165, -180, -225, -270, 360, -360],
|
||||
anchorSize: 40 * scale,
|
||||
ignoreStroke: true,
|
||||
centeredScaling: true
|
||||
});
|
||||
|
||||
let tablesAndDecorations = ajaxSync(`/ajax/getTablesAndDecorations/${room}`, null, 'GET');
|
||||
let decorations = tablesAndDecorations['decorations']
|
||||
let tables = tablesAndDecorations['tables']
|
||||
|
||||
|
||||
tableLayer = new Konva.Layer();
|
||||
tableLayer.add(transformer);
|
||||
|
||||
// Loop data and call the creation method for each decoration/table.
|
||||
decorations.forEach(itemData => {
|
||||
createDecoration(itemData, selectDecoration);
|
||||
});
|
||||
|
||||
tables.forEach(itemData => {
|
||||
tableLayer.add(createTableElement(itemData, selectTable));
|
||||
});
|
||||
activeTables = getOpenTables()
|
||||
stage.add(tableLayer);
|
||||
}
|
||||
|
||||
var mergeMode = false;
|
||||
var parentMergeTable;
|
||||
var childMergeTable;
|
||||
var tableTransferOrigin;
|
||||
var transferMode = false;
|
||||
function transferModeOn() {
|
||||
mergeModeOff();
|
||||
if (!transferMode) {
|
||||
tableTransferOrigin = selectedTableNumber;
|
||||
transferMode = true;
|
||||
$('.transferTableButton').addClass('active');
|
||||
$('.transferTableButton').text('Select a table to transfer items to');
|
||||
}
|
||||
else {
|
||||
transferModeOff();
|
||||
}
|
||||
}
|
||||
function transferModeOff() {
|
||||
transferMode = false;
|
||||
$('.transferTableButton').removeClass('active');
|
||||
$('.transferTableButton').text(lang('transfer_table'));
|
||||
}
|
||||
|
||||
let getOpenTables = () => {
|
||||
return ajaxSync('/ajax/getActiveTables/1', null, 'GET');
|
||||
}
|
||||
|
||||
let transferTableAjax = (origin, destination) => {
|
||||
ajax(`/ajax/transferTables/${origin}/${destination}`, null, 'GET')
|
||||
}
|
||||
|
||||
function transferTables() {
|
||||
destination = selectedTableNumber;
|
||||
origin = tableTransferOrigin;
|
||||
if (destination !== origin) {
|
||||
transferTableAjax(origin, destination)
|
||||
activeTables = getOpenTables()
|
||||
transferModeOff();
|
||||
getTableShape(selectedTable).fill('lightblue')
|
||||
getTableShape( getTableGroup(origin) ).fill('gray')
|
||||
}
|
||||
else {
|
||||
alert("Can't transfer a table to itself.");
|
||||
transferModeOff();
|
||||
}
|
||||
}
|
||||
function mergeModeOn() {
|
||||
transferModeOff();
|
||||
if (!mergeMode) {
|
||||
mergeMode = true;
|
||||
$('.mergeButton').addClass('active');
|
||||
$('.mergeButton').text('Select a table to merge with Table ' + selectedTableNumber);
|
||||
parentMergeTable = selectedTableNumber;
|
||||
}
|
||||
else {
|
||||
mergeModeOff();
|
||||
}
|
||||
}
|
||||
function mergeModeOff() {
|
||||
mergeMode = false;
|
||||
$('.mergeButton').removeClass('active');
|
||||
$('.mergeButton').text(lang('merge_table'));
|
||||
}
|
||||
|
||||
let ajaxMergeTables = (parent, child) => {
|
||||
return ajaxSync(`/ajax/mergeTables/${parent}/${child}`, null, 'GET')
|
||||
}
|
||||
|
||||
let ajaxUnmergeTable = (parent) => {
|
||||
return ajaxSync(`/ajax/unmergeTable/${parent}`, null, 'GET')
|
||||
}
|
||||
|
||||
function mergeTables() {
|
||||
parentMergeTable = parseInt(parentMergeTable);
|
||||
childMergeTable = parseInt(childMergeTable);
|
||||
if (childMergeTable !== parentMergeTable) {
|
||||
let result = ajaxMergeTables(parentMergeTable, childMergeTable)
|
||||
mergeModeOff();
|
||||
|
||||
loadRoom(currentRoom)
|
||||
newTable = getTableGroup(parentMergeTable);
|
||||
newTable.draggable(true);
|
||||
|
||||
if (tableIsOpen(parentMergeTable)) {
|
||||
getTableShape(newTable).fill('lightblue');
|
||||
}
|
||||
}
|
||||
else {
|
||||
alert("Can't merge a table with itself!");
|
||||
mergeModeOff();
|
||||
}
|
||||
}
|
||||
//When a table is passed (a group of the shape plus the text), returns the number as string.
|
||||
function getTableNumber(tableGroup) {
|
||||
textItem = tableGroup.getChildren()[1];
|
||||
return textItem.getText();
|
||||
}
|
||||
function getTableGroup(tableNumber) {
|
||||
return stage.find('#' + tableNumber)[0];
|
||||
}
|
||||
function getTableShape(tableGroup) {
|
||||
return tableGroup.getChildren()[0];
|
||||
}
|
||||
|
||||
function getReservation(id) {
|
||||
return ajaxSync('/ajax/getReservation', id)
|
||||
}
|
||||
|
||||
//When a user selects a table.
|
||||
function selectTableShape(table) {
|
||||
let tableNumber = getTableNumber(table);
|
||||
let shape = getTableShape(table);
|
||||
let strokeColor = shape.stroke();
|
||||
selectedTable = table;
|
||||
selectedTableNumber = tableNumber;
|
||||
if(transferMode) transferTables()
|
||||
if (mergeMode) {
|
||||
childMergeTable = tableNumber;
|
||||
mergeTables();
|
||||
}
|
||||
else {
|
||||
//If table is not selected
|
||||
if (strokeColor !== "yellow") {
|
||||
let tableData = getTableData(selectedTableNumber)
|
||||
|
||||
let coverNumberString = lang('covers', tableData.default_covers.toString());
|
||||
let tableString = '<b>' + lang('activeTable', selectedTableNumber.toString()) + '</b>';
|
||||
$('.reserveTableButton').text(lang('reserve_table'));
|
||||
if (tableData.status === 'reserved') {
|
||||
let reservation = getReservation(tableData.reservation_id)
|
||||
console.log(reservation)
|
||||
$('.reserveTableButton').text(lang('unreserve_table'));
|
||||
if (reservation.reservation_name) {
|
||||
reservationString = lang('reserved_for', reservation.reservation_name);
|
||||
}
|
||||
else {
|
||||
reservationString = lang('reserved');
|
||||
}
|
||||
tableString += '<small>' + reservationString + '</small>';
|
||||
}
|
||||
tableString += "<small> (" + coverNumberString + ")</small>";
|
||||
$('.currentTable').html(tableString);
|
||||
|
||||
stage.find('Rect').forEach(function (rect, index) {
|
||||
rect.stroke("black");
|
||||
});
|
||||
stage.find('Ellipse').forEach(function (circ, index) {
|
||||
circ.stroke("black");
|
||||
});
|
||||
shape.stroke("yellow");
|
||||
toggleEditControls(true);
|
||||
if (editMode) {
|
||||
toggleFloorplanControls();
|
||||
$('.deleteDecoration').css('display', 'none');
|
||||
transformer.nodes([getTableShape(table)]);
|
||||
table.moveToTop();
|
||||
transformer.moveToTop();
|
||||
}
|
||||
tableLayer.draw();
|
||||
//If the table is already selected
|
||||
}
|
||||
else {
|
||||
resetActiveTable();
|
||||
transformer.nodes([]);
|
||||
tableLayer.draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let getTableData = (tableNumber) => {
|
||||
return ajaxSync('/ajax/getTableData', tableNumber)
|
||||
}
|
||||
|
||||
let isTableMerged = (tableNumber) => {
|
||||
let mergeData = getTableData(tableNumber).merged_children
|
||||
return mergeData !== ""
|
||||
}
|
||||
|
||||
function resetActiveTable() {
|
||||
if (!transferMode) {
|
||||
if (selectedTable) {
|
||||
getTableShape(selectedTable).stroke('black');
|
||||
}
|
||||
selectedTable = null;
|
||||
selectedTableNumber = "";
|
||||
toggleFloorplanControls(false, editMode);
|
||||
toggleEditControls(false);
|
||||
}
|
||||
else {
|
||||
$('.editControls').css('display', 'none');
|
||||
}
|
||||
}
|
||||
function addDecoration(button) {
|
||||
let insertData = {
|
||||
decoration_room: currentRoom,
|
||||
basis: basis,
|
||||
decoration_image: $(button).data('image')
|
||||
}
|
||||
|
||||
ajaxSync('/ajax/addDecoration', insertData)
|
||||
$('#decorator').css('display', 'none');
|
||||
selectedDecoration = false;
|
||||
loadRoom(currentRoom);
|
||||
}
|
||||
function deleteDecoration(decoration) {
|
||||
ajax('/ajax/deleteDecoration', decoration.id());
|
||||
$('.deleteDecoration').css('display', 'none');
|
||||
decoration.destroy()
|
||||
selectedDecoration = false;
|
||||
transformer.nodes([])
|
||||
}
|
||||
function saveDecTransformation(decoration: Konva.Shape) {
|
||||
let newData = {
|
||||
decoration_id: decoration.id(),
|
||||
decoration_pos_x: decoration.x() / scale,
|
||||
decoration_pos_y: decoration.y() / scale,
|
||||
decoration_width: parseInt((decoration.scaleX() * decoration.width()) / scale),
|
||||
decoration_height: parseInt((decoration.scaleY() * decoration.height()) / scale),
|
||||
decoration_rotation: parseInt(decoration.rotation()),
|
||||
decoration_image: decodeURIComponent(decoration.image().src),
|
||||
decoration_room: currentRoom
|
||||
};
|
||||
|
||||
if (editMode) {
|
||||
idToSelect = decoration.id();
|
||||
}
|
||||
ajax('/ajax/updateDecoration', newData)
|
||||
}
|
||||
//When a table has been resized, rotated etc.
|
||||
function saveTransformation(table) {
|
||||
tableNumber = getTableNumber(table);
|
||||
shape = getTableShape(table);
|
||||
newRotation = parseInt(shape.rotation());
|
||||
newWidth = parseInt(shape.scaleX() * shape.width() / scale);
|
||||
newHeight = parseInt((shape.scaleY() * shape.height()) / scale);
|
||||
newXPos = parseInt(table.x() / scale);
|
||||
newYPos = parseInt(table.y() / scale);
|
||||
updateData = {
|
||||
table_number: tableNumber,
|
||||
rotation: newRotation,
|
||||
width: newWidth,
|
||||
height: newHeight,
|
||||
pos_x: newXPos,
|
||||
pos_y: newYPos
|
||||
};
|
||||
transformTable(updateData)
|
||||
}
|
||||
|
||||
let transformTable = (tableData) => {
|
||||
return ajax("/ajax/transformTable", tableData)
|
||||
}
|
||||
|
||||
function unmergeTable() {
|
||||
|
||||
ajaxUnmergeTable(selectedTableNumber)
|
||||
loadRoom(currentRoom);
|
||||
}
|
||||
function reserveTable(covers) {
|
||||
if (!covers) {
|
||||
showVirtualNumpad(lang('how_many_covers'), 2, false, false, true, reserveTable);
|
||||
}
|
||||
else {
|
||||
let table = getTableGroup(selectedTableNumber);
|
||||
let newReservation = ajaxSync('/ajax/newEmptyReservation', selectedTableNumber)
|
||||
|
||||
table.fire('click');
|
||||
let tableShape = getTableShape(table);
|
||||
tableShape.fill('lightgreen');
|
||||
table.draw();
|
||||
table.fire('click');
|
||||
completeReservation(newReservation);
|
||||
}
|
||||
}
|
||||
|
||||
function unreserveTable(input) {
|
||||
if (!input) {
|
||||
confirm(lang('confirm_delete_reservation', selectedTableNumber), selectedTableNumber, lang('confirm'), unreserveTable);
|
||||
}
|
||||
else {
|
||||
ajaxSync('/ajax/unreserveTable', input)
|
||||
hideAlerts()
|
||||
table = getTableGroup(input);
|
||||
table.fire('click');
|
||||
tableShape = getTableShape(table);
|
||||
tableShape.fill('gray');
|
||||
table.draw();
|
||||
table.fire('click');
|
||||
}
|
||||
}
|
||||
function completeReservation(resName) {
|
||||
if (!resName) {
|
||||
showVirtualKeyboard(lang('enter_reservation_name'));
|
||||
}
|
||||
else {
|
||||
//callPhpFunction('updateTableMapTable', [selectedTableNumber, 'reservation_name', resName]);
|
||||
loadRoom(currentRoom, selectedTableNumber);
|
||||
}
|
||||
}
|
||||
function toggleEditMode() {
|
||||
let editModeButton = $('.editModeButton');
|
||||
if (editMode === true) {
|
||||
editMode = false;
|
||||
loadRoom(currentRoom);
|
||||
editModeButton.removeClass('active');
|
||||
editModeButton.html(lang('edit_floorplan'));
|
||||
toggleFloorplanControls(false);
|
||||
if (selectedTable)
|
||||
selectedTable.fire('click');
|
||||
stage.find('Group').forEach(function (table, index) {
|
||||
table.draggable(false);
|
||||
});
|
||||
}
|
||||
else {
|
||||
editMode = true;
|
||||
stage.find('Group').forEach(function (table, index) {
|
||||
table.draggable(true);
|
||||
if (getTableShape(table).stroke() === "yellow") {
|
||||
table.moveToTop();
|
||||
transformer.nodes([getTableShape(table)]);
|
||||
transformer.moveToTop();
|
||||
}
|
||||
});
|
||||
stage.find('Image').forEach(function (img, index) {
|
||||
img.draggable(true);
|
||||
});
|
||||
toggleFloorplanControls();
|
||||
transformer.moveToTop();
|
||||
tableLayer.draw();
|
||||
editModeButton.addClass('active');
|
||||
editModeButton.html(lang('stop_edit_floorplan'));
|
||||
}
|
||||
}
|
||||
function toggleFloorplanControls(onOrOff = true, subControlsOnly = false) {
|
||||
if (onOrOff || subControlsOnly) {
|
||||
$('.floorplanControls').css('visibility', 'visible');
|
||||
}
|
||||
else {
|
||||
$('.floorplanControls').css('visibility', 'hidden');
|
||||
}
|
||||
if (selectedTable) {
|
||||
$('.changeShapeButton').css('visibility', 'visible');
|
||||
$('.deleteTableButton').css('visibility', 'visible');
|
||||
}
|
||||
else {
|
||||
$('.changeShapeButton').css('visibility', 'hidden');
|
||||
$('.deleteTableButton').css('visibility', 'hidden');
|
||||
}
|
||||
if (selectedDecoration) {
|
||||
$('.deleteDecoration').css('display', 'flex');
|
||||
}
|
||||
else {
|
||||
$('.deleteDecoration').css('display', 'none');
|
||||
}
|
||||
}
|
||||
|
||||
let tableIsOpen = (tableNumber) => {
|
||||
return ajaxSync(`/ajax/tableIsOpen/${tableNumber}`, null, 'GET')
|
||||
}
|
||||
|
||||
function toggleEditControls(onOrOff = true) {
|
||||
if (onOrOff) {
|
||||
$('.editControls').css("display", "flex");
|
||||
if (isTableMerged(selectedTableNumber)) {
|
||||
$('.mergeControls').css("visibility", "visible");
|
||||
$('.unmergeButton').css('display', 'flex');
|
||||
$('.mergeButton').css('display', 'flex');
|
||||
}
|
||||
else {
|
||||
$('.mergeControls').css("visibility", "visible");
|
||||
$('.mergeButton').css('display', 'flex');
|
||||
$('.unmergeButton').css('display', 'none');
|
||||
}
|
||||
if (tableIsOpen(selectedTableNumber)) {
|
||||
$('.payTableButton').css('display', 'flex');
|
||||
$('.viewTableButton').css('display', 'flex');
|
||||
$('.reserveTableButton').css('display', 'none');
|
||||
$('.transferTableButton').css('display', 'flex');
|
||||
}
|
||||
else {
|
||||
$('.payTableButton').css('display', 'none');
|
||||
$('.viewTableButton').css('display', 'none');
|
||||
$('.reserveTableButton').css('display', 'flex');
|
||||
$('.transferTableButton').css('display', 'none');
|
||||
}
|
||||
}
|
||||
else {
|
||||
$('.editControls').css("display", "none");
|
||||
$('.mergeControls').css("visibility", "hidden");
|
||||
$('.mergeButton').css("display", "none");
|
||||
$('.unmergeButton').css("display", "none");
|
||||
}
|
||||
}
|
||||
256
wwwroot/scripts/ts/keyboards.ts
Normal file
256
wwwroot/scripts/ts/keyboards.ts
Normal file
@@ -0,0 +1,256 @@
|
||||
let showVirtualNumpad = (heading: string, maxlength = 4, isPassword: boolean, allowDecimals = true, allowClose = true, submitFunction: Function) => {
|
||||
let numpad = $('#virtualNumpad');
|
||||
let inputBox = $('#virtualNumpadInput')
|
||||
let closeKeyboardButton = $('.closeKeyboards')
|
||||
|
||||
numpad.css('display', 'flex')
|
||||
|
||||
let showCloseButton = allowClose ? 'flex' : 'none'
|
||||
closeKeyboardButton.css('display', showCloseButton)
|
||||
$('#virtualNumpadHeading').html(heading)
|
||||
|
||||
/*
|
||||
The numpad always submits to a function.
|
||||
If a function isn't specified, it will submit
|
||||
to the same function that called it
|
||||
*/
|
||||
|
||||
numpad.data('value', '');
|
||||
inputBox.text('');
|
||||
|
||||
numpad.data('maxlength', maxlength)
|
||||
numpad.data('submitfunction', submitFunction)
|
||||
numpad.data('password', isPassword);
|
||||
numpad.data('allowdecimals', allowDecimals);
|
||||
|
||||
$(document).unbind('keyup');
|
||||
$(document).keyup(e => {
|
||||
let key = e.key;
|
||||
|
||||
switch (key) {
|
||||
case 'Backspace':
|
||||
case 'Delete':
|
||||
key = 'clear'
|
||||
break;
|
||||
case 'Enter':
|
||||
key = 'submit'
|
||||
break;
|
||||
}
|
||||
|
||||
virtualNumpadInput(key)
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
let hideVirtualKeyboard = () => {
|
||||
let keyboard = $('#virtualKeyboard');
|
||||
keyboard.hide()
|
||||
$('#virtualKeyboardHeading').html('');
|
||||
$(document).unbind('keyup');
|
||||
}
|
||||
|
||||
let hideVirtualNumpad = () => {
|
||||
let numpad = $('#virtualNumpad')
|
||||
numpad.css('display', 'none')
|
||||
$('#virtualNumpadHeading').html('')
|
||||
$(document).unbind('keyup')
|
||||
}
|
||||
|
||||
let virtualNumpadInput = (input: string) => {
|
||||
let inputBox = $('#virtualNumpadInput')
|
||||
let numpad = $('#virtualNumpad')
|
||||
let maxlength = numpad.data('maxlength')
|
||||
let allowDecimals = numpad.data('allowdecimals')
|
||||
let submitFunction = numpad.data('submitfunction')
|
||||
let allowedValues = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'submit', 'clear']
|
||||
let currentValue = numpad.data('value').toString()
|
||||
//Test
|
||||
if (allowDecimals)
|
||||
allowedValues.push('.', ',')
|
||||
|
||||
let validInput = allowedValues.includes(input);
|
||||
//If the input is a valid number, decimal point or command.
|
||||
if (validInput) {
|
||||
switch (input) {
|
||||
case 'submit':
|
||||
hideVirtualNumpad()
|
||||
let numpadValue: string = numpad.data('value').length > 0 ? numpad.data('value') : "0"
|
||||
submitFunction(numpadValue)
|
||||
break;
|
||||
case 'clear':
|
||||
clearNumpadInput()
|
||||
break;
|
||||
default:
|
||||
let newText = currentValue + input
|
||||
let isPassword = numpad.data('password')
|
||||
let length = input.length + inputBox.text().length
|
||||
|
||||
if (length <= maxlength) {
|
||||
inputBox.append(isPassword ? '*' : input)
|
||||
numpad.data('value', newText)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let clearNumpadInput = () => {
|
||||
$('#virtualNumpadInput').text("")
|
||||
$('#virtualNumpad').data('value', '')
|
||||
}
|
||||
|
||||
let setupVirtualNumpad = () => {
|
||||
$(document).on('click', '.virtualNumpadButton', e => {
|
||||
virtualNumpadInput($(e.target).data('value').toString())
|
||||
})
|
||||
|
||||
$('.closeKeyboards').on('click', () => {
|
||||
hideVirtualKeyboard();
|
||||
hideVirtualNumpad()
|
||||
});
|
||||
}
|
||||
|
||||
let setupVirtualKeyboard = () => {
|
||||
Application.keyboard = {
|
||||
capsLock: false,
|
||||
shift: false,
|
||||
layout: 'default'
|
||||
}
|
||||
|
||||
$(document).on('click', '.virtualKeyboardButton', e => {
|
||||
virtualKeyboardInput($(e.target).data('value'));
|
||||
})
|
||||
|
||||
setKeyboardLayout('default')
|
||||
}
|
||||
|
||||
let showVirtualKeyboard = (heading: string, maxlength = 32, isPassword = false, submitFunction = () => {
|
||||
hideVirtualKeyboard()
|
||||
}) => {
|
||||
let keyboard = $('#virtualKeyboard')
|
||||
let inputBox = $('#virtualKeyboardInput')
|
||||
|
||||
keyboard.css('display', 'flex')
|
||||
$('#virtualKeyboardHeading').html(heading)
|
||||
|
||||
keyboard.data('value', '')
|
||||
inputBox.text('')
|
||||
keyboard.data('maxlength', maxlength)
|
||||
keyboard.data('password', isPassword)
|
||||
keyboard.data('submitfunction', submitFunction)
|
||||
|
||||
$(document).off('keyup')
|
||||
$(document).on('keyup', e => {
|
||||
let key = e.key
|
||||
if (key == 'Enter')
|
||||
key = 'submit'
|
||||
|
||||
virtualKeyboardInput(key)
|
||||
})
|
||||
}
|
||||
|
||||
let virtualKeyboardInput = (input: string) => {
|
||||
let inputBox = $('#virtualKeyboardInput')
|
||||
let keyboard = $('#virtualKeyboard');
|
||||
|
||||
let maxlength = keyboard.data('maxlength');
|
||||
let isPassword = keyboard.data('password');
|
||||
let length = input.length + inputBox.text().length
|
||||
|
||||
switch (input.toLowerCase()) {
|
||||
case 'backspace':
|
||||
case 'delete':
|
||||
let newText = inputBox.text().slice(0, -1);
|
||||
inputBox.text(newText)
|
||||
keyboard.data('value', newText);
|
||||
break;
|
||||
case 'submit':
|
||||
hideVirtualKeyboard();
|
||||
let submitFunction = keyboard.data('submitfunction')
|
||||
submitFunction();
|
||||
break;
|
||||
case 'shift':
|
||||
if (Application.keyboard.capsLock) break;
|
||||
Application.keyboard.shift = !Application.keyboard.shift
|
||||
Application.keyboard.capsLock = false
|
||||
setKeyboardLayout('default', Application.keyboard.shift ? 'shift' : '')
|
||||
break;
|
||||
case 'capslock':
|
||||
Application.keyboard.shift = false
|
||||
Application.keyboard.capsLock = !Application.keyboard.capsLock
|
||||
let capsLockButton = $('[data-value="capslock"]')
|
||||
capsLockButton.toggleClass('active')
|
||||
setKeyboardLayout('default', Application.keyboard.capsLock ? 'shift' : '')
|
||||
break;
|
||||
case 'space':
|
||||
input = ' ';
|
||||
break;
|
||||
}
|
||||
|
||||
//Stops keys such as F5 being pressed.
|
||||
if (input.length == 1) {
|
||||
if (Application.keyboard.shift || Application.keyboard.capsLock) {
|
||||
input = input.toUpperCase()
|
||||
}
|
||||
|
||||
let newText = inputBox.text() + input;
|
||||
keyboard.data('value', newText);
|
||||
inputBox.text(newText)
|
||||
|
||||
//If shift, reload lowercase
|
||||
if (Application.keyboard.shift) {
|
||||
Application.keyboard.shift = false
|
||||
setKeyboardLayout('default');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let setKeyboardLayout = (layout: string, modifier = '') => {
|
||||
let keyboardLayout = ajaxSync('/languages/english/keyboardLayout.json', null, 'get')
|
||||
if (modifier != '') modifier = `_${modifier}`
|
||||
|
||||
$('.virtualKeyboardRow').each((index, row) => {
|
||||
/*
|
||||
We start at 1 instead of 0. Makes it easier for non-programmers
|
||||
and translators making their own language packs
|
||||
*/
|
||||
index = index + 1;
|
||||
let currentRow: Record<string, string> = keyboardLayout[layout]["row" + index + modifier]
|
||||
|
||||
$(row).children('a').each((keyIndex, button) => {
|
||||
let key = $(button);
|
||||
let keyValue: string = currentRow[keyIndex];
|
||||
|
||||
/*
|
||||
KeyText is the text that appears
|
||||
in the button. KeyData is the value
|
||||
submitted when the button is pressed.
|
||||
*/
|
||||
let keyText = keyValue;
|
||||
let keyData = keyValue;
|
||||
|
||||
key.addClass('posButton');
|
||||
key.addClass('virtualKeyboardButton');
|
||||
|
||||
let pattern = new RegExp(/\[([^)]+)\]/);
|
||||
let matches = keyValue.match(pattern);
|
||||
|
||||
if (matches) {
|
||||
keyText = keyValue.replace(pattern, '');
|
||||
keyData = matches[1];
|
||||
}
|
||||
|
||||
key.html(keyText)
|
||||
|
||||
//Use attr() as some keys have CSS dependent on data-value
|
||||
key.attr('data-value', keyData)
|
||||
key.data('value', keyData)
|
||||
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
$(() => {
|
||||
setupVirtualNumpad()
|
||||
setupVirtualKeyboard();
|
||||
})
|
||||
6
wwwroot/scripts/ts/package.json
Normal file
6
wwwroot/scripts/ts/package.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "ts",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
}
|
||||
}
|
||||
18
wwwroot/scripts/ts/tsconfig.json
Normal file
18
wwwroot/scripts/ts/tsconfig.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"compilerOptions":{
|
||||
"lib":[
|
||||
"esnext",
|
||||
"dom"
|
||||
],
|
||||
"noImplicitAny":true,
|
||||
"removeComments":false,
|
||||
"preserveConstEnums":true,
|
||||
"outDir":"../js",
|
||||
"target":"ES2016",
|
||||
"sourceMap":true,
|
||||
"moduleResolution": "node"
|
||||
},
|
||||
"include":[
|
||||
"*"
|
||||
]
|
||||
}
|
||||
44
wwwroot/scripts/ts/types.ts
Normal file
44
wwwroot/scripts/ts/types.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
type PosMode = "edit" | "void" | "transfer" | "default"
|
||||
|
||||
interface ajaxResult {
|
||||
status: string
|
||||
data : any
|
||||
}
|
||||
|
||||
interface ApplicationState {
|
||||
keyboard: keyboard
|
||||
mode: PosMode
|
||||
languageVars: Record<any, string>
|
||||
}
|
||||
|
||||
|
||||
interface table {
|
||||
table_number: number,
|
||||
room_id: number
|
||||
venue_id: number
|
||||
pos_x: number
|
||||
pos_y: number
|
||||
shape: string
|
||||
width: number
|
||||
height: number
|
||||
default_covers: number
|
||||
rotation: number
|
||||
merged_children: string
|
||||
previous_state: string
|
||||
status: string
|
||||
table_id: number
|
||||
}
|
||||
|
||||
interface room {
|
||||
room_id: number
|
||||
room_name: string
|
||||
background_image: string
|
||||
venue_id: number
|
||||
}
|
||||
|
||||
|
||||
interface keyboard {
|
||||
capsLock: boolean
|
||||
shift: boolean
|
||||
layout: string
|
||||
}
|
||||
38
wwwroot/scripts/ts/typings/currency.d.ts
vendored
Normal file
38
wwwroot/scripts/ts/typings/currency.d.ts
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
declare namespace currency {
|
||||
type Any = number | string | currency;
|
||||
type Format = (currency?: currency, opts?: Options) => string;
|
||||
interface Constructor {
|
||||
(value: currency.Any, opts?: currency.Options): currency,
|
||||
new(value: currency.Any, opts?: currency.Options): currency
|
||||
}
|
||||
interface Options {
|
||||
symbol?: string,
|
||||
separator?: string,
|
||||
decimal?: string,
|
||||
errorOnInvalid?: boolean,
|
||||
precision?: number,
|
||||
increment?: number,
|
||||
useVedic?: boolean,
|
||||
pattern?: string,
|
||||
negativePattern?: string,
|
||||
format?: currency.Format,
|
||||
fromCents?: boolean
|
||||
}
|
||||
}
|
||||
|
||||
interface currency {
|
||||
add(number: currency.Any): currency;
|
||||
subtract(number: currency.Any): currency;
|
||||
multiply(number: currency.Any): currency;
|
||||
divide(number: currency.Any): currency;
|
||||
distribute(count: number): Array<currency>;
|
||||
dollars(): number;
|
||||
cents(): number;
|
||||
format(opts?: currency.Options | currency.Format): string;
|
||||
toString(): string;
|
||||
toJSON(): number;
|
||||
readonly intValue: number;
|
||||
readonly value: number;
|
||||
}
|
||||
|
||||
declare const currency: currency.Constructor;
|
||||
174
wwwroot/scripts/ts/typings/konva.d.ts
vendored
Normal file
174
wwwroot/scripts/ts/typings/konva.d.ts
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
// filters
|
||||
import { Blur } from 'konva/lib/filters/Blur';
|
||||
import { Brighten } from 'konva/lib/filters/Brighten';
|
||||
import { Contrast } from 'konva/lib/filters/Contrast';
|
||||
import { Emboss } from 'konva/lib/filters/Emboss';
|
||||
import { Enhance } from 'konva/lib/filters/Enhance';
|
||||
import { Grayscale } from 'konva/lib/filters/Grayscale';
|
||||
import { HSL } from 'konva/lib/filters/HSL';
|
||||
import { HSV } from 'konva/lib/filters/HSV';
|
||||
import { Invert } from 'konva/lib/filters/Invert';
|
||||
import { Kaleidoscope } from 'konva/lib/filters/Kaleidoscope';
|
||||
import { Mask } from 'konva/lib/filters/Mask';
|
||||
import { Noise } from 'konva/lib/filters/Noise';
|
||||
import { Pixelate } from 'konva/lib/filters/Pixelate';
|
||||
import { Posterize } from 'konva/lib/filters/Posterize';
|
||||
import { RGB } from 'konva/lib/filters/RGB';
|
||||
import { RGBA } from 'konva/lib/filters/RGBA';
|
||||
import { Sepia } from 'konva/lib/filters/Sepia';
|
||||
import { Solarize } from 'konva/lib/filters/Solarize';
|
||||
import { Threshold } from 'konva/lib/filters/Threshold';
|
||||
|
||||
declare global {
|
||||
export namespace Konva {
|
||||
export let enableTrace: number;
|
||||
export let pixelRatio: number;
|
||||
export let dragDistance: number;
|
||||
export let angleDeg: boolean;
|
||||
export let showWarnings: boolean;
|
||||
export let capturePointerEventsEnabled: boolean;
|
||||
export let dragButtons: Array<number>;
|
||||
export let hitOnDragEnabled: boolean;
|
||||
export const isDragging: () => boolean;
|
||||
export const isDragReady: () => boolean;
|
||||
|
||||
export type Vector2d = import('konva/lib/types').Vector2d;
|
||||
|
||||
export const Node: typeof import('konva/lib/Node').Node;
|
||||
export type Node = import('konva/lib/Node').Node;
|
||||
export type NodeConfig = import('konva/lib/Node').NodeConfig;
|
||||
|
||||
export type KonvaEventObject<EventType> =
|
||||
import('konva/lib/Node').KonvaEventObject<EventType>;
|
||||
|
||||
export type KonvaPointerEvent =
|
||||
import('konva/lib/PointerEvents').KonvaPointerEvent;
|
||||
|
||||
export type KonvaEventListener<This, EventType> =
|
||||
import('konva/lib/Node').KonvaEventListener<This, EventType>;
|
||||
|
||||
export const Container: typeof import('konva/lib/Container').Container;
|
||||
export type Container = import('konva/lib/Container').Container<Node>;
|
||||
export type ContainerConfig = import('konva/lib/Container').ContainerConfig;
|
||||
|
||||
export const Transform: typeof import('konva/lib/Util').Transform;
|
||||
export type Transform = import('konva/lib/Util').Transform;
|
||||
|
||||
export const Util: typeof import('konva/lib/Util').Util;
|
||||
|
||||
export const Context: typeof import('konva/lib/Context').Context;
|
||||
export type Context = import('konva/lib/Context').Context;
|
||||
|
||||
export const Stage: typeof import('konva/lib/Stage').Stage;
|
||||
export type Stage = import('konva/lib/Stage').Stage;
|
||||
export const stages: typeof import('konva/lib/Stage').stages;
|
||||
|
||||
export const Layer: typeof import('konva/lib/Layer').Layer;
|
||||
export type Layer = import('konva/lib/Layer').Layer;
|
||||
export type LayerConfig = import('konva/lib/Layer').LayerConfig;
|
||||
|
||||
export const FastLayer: typeof import('konva/lib/FastLayer').FastLayer;
|
||||
export type FastLayer = import('konva/lib/FastLayer').FastLayer;
|
||||
|
||||
export const Group: typeof import('konva/lib/Group').Group;
|
||||
export type Group = import('konva/lib/Group').Group;
|
||||
|
||||
export const DD: typeof import('konva/lib/DragAndDrop').DD;
|
||||
|
||||
export const Shape: typeof import('konva/lib/Shape').Shape;
|
||||
export type Shape = import('konva/lib/Shape').Shape;
|
||||
export type ShapeConfig = import('konva/lib/Shape').ShapeConfig;
|
||||
export const shapes: typeof import('konva/lib/Shape').shapes;
|
||||
|
||||
export const Animation: typeof import('konva/lib/Animation').Animation;
|
||||
export type Animation = import('konva/lib/Animation').Animation;
|
||||
|
||||
export const Tween: typeof import('konva/lib/Tween').Tween;
|
||||
export type Tween = import('konva/lib/Tween').Tween;
|
||||
export type TweenConfig = import('konva/lib/Tween').TweenConfig;
|
||||
export const Easings: typeof import('konva/lib/Tween').Easings;
|
||||
|
||||
export const Arc: typeof import('konva/lib/shapes/Arc').Arc;
|
||||
export type Arc = import('konva/lib/shapes/Arc').Arc;
|
||||
export type ArcConfig = import('konva/lib/shapes/Arc').ArcConfig;
|
||||
export const Arrow: typeof import('konva/lib/shapes/Arrow').Arrow;
|
||||
export type Arrow = import('konva/lib/shapes/Arrow').Arrow;
|
||||
export type ArrowConfig = import('konva/lib/shapes/Arrow').ArrowConfig;
|
||||
export const Circle: typeof import('konva/lib/shapes/Circle').Circle;
|
||||
export type Circle = import('konva/lib/shapes/Circle').Circle;
|
||||
export type CircleConfig = import('konva/lib/shapes/Circle').CircleConfig;
|
||||
export const Ellipse: typeof import('konva/lib/shapes/Ellipse').Ellipse;
|
||||
export type Ellipse = import('konva/lib/shapes/Ellipse').Ellipse;
|
||||
export type EllipseConfig =
|
||||
import('konva/lib/shapes/Ellipse').EllipseConfig;
|
||||
export const Image: typeof import('konva/lib/shapes/Image').Image;
|
||||
export type Image = import('konva/lib/shapes/Image').Image;
|
||||
export type ImageConfig = import('konva/lib/shapes/Image').ImageConfig;
|
||||
export const Label: typeof import('konva/lib/shapes/Label').Label;
|
||||
export type Label = import('konva/lib/shapes/Label').Label;
|
||||
export type LabelConfig = import('konva/lib/shapes/Label').LabelConfig;
|
||||
export const Tag: typeof import('konva/lib/shapes/Label').Tag;
|
||||
export type Tag = import('konva/lib/shapes/Label').Tag;
|
||||
export type TagConfig = import('konva/lib/shapes/Label').TagConfig;
|
||||
export const Line: typeof import('konva/lib/shapes/Line').Line;
|
||||
export type Line = import('konva/lib/shapes/Line').Line;
|
||||
export type LineConfig = import('konva/lib/shapes/Line').LineConfig;
|
||||
export const Path: typeof import('konva/lib/shapes/Path').Path;
|
||||
export type Path = import('konva/lib/shapes/Path').Path;
|
||||
export type PathConfig = import('konva/lib/shapes/Path').PathConfig;
|
||||
export const Rect: typeof import('konva/lib/shapes/Rect').Rect;
|
||||
export type Rect = import('konva/lib/shapes/Rect').Rect;
|
||||
export type RectConfig = import('konva/lib/shapes/Rect').RectConfig;
|
||||
export const RegularPolygon: typeof import('konva/lib/shapes/RegularPolygon').RegularPolygon;
|
||||
export type RegularPolygon =
|
||||
import('konva/lib/shapes/RegularPolygon').RegularPolygon;
|
||||
export type RegularPolygonConfig =
|
||||
import('konva/lib/shapes/RegularPolygon').RegularPolygonConfig;
|
||||
export const Ring: typeof import('konva/lib/shapes/Ring').Ring;
|
||||
export type Ring = import('konva/lib/shapes/Ring').Ring;
|
||||
export type RingConfig = import('konva/lib/shapes/Ring').RingConfig;
|
||||
export const Sprite: typeof import('konva/lib/shapes/Sprite').Sprite;
|
||||
export type Sprite = import('konva/lib/shapes/Sprite').Sprite;
|
||||
export type SpriteConfig = import('konva/lib/shapes/Sprite').SpriteConfig;
|
||||
export const Star: typeof import('konva/lib/shapes/Star').Star;
|
||||
export type Star = import('konva/lib/shapes/Star').Star;
|
||||
export type StarConfig = import('konva/lib/shapes/Star').StarConfig;
|
||||
export const Text: typeof import('konva/lib/shapes/Text').Text;
|
||||
export type Text = import('konva/lib/shapes/Text').Text;
|
||||
export type TextConfig = import('konva/lib/shapes/Text').TextConfig;
|
||||
export const TextPath: typeof import('konva/lib/shapes/TextPath').TextPath;
|
||||
export type TextPath = import('konva/lib/shapes/TextPath').TextPath;
|
||||
export type TextPathConfig =
|
||||
import('konva/lib/shapes/TextPath').TextPathConfig;
|
||||
export const Transformer: typeof import('konva/lib/shapes/Transformer').Transformer;
|
||||
export type Transformer =
|
||||
import('konva/lib/shapes/Transformer').Transformer;
|
||||
export type TransformerConfig =
|
||||
import('konva/lib/shapes/Transformer').TransformerConfig;
|
||||
export const Wedge: typeof import('konva/lib/shapes/Wedge').Wedge;
|
||||
export type Wedge = import('konva/lib/shapes/Wedge').Wedge;
|
||||
export type WedgeConfig = import('konva/lib/shapes/Wedge').WedgeConfig;
|
||||
|
||||
export const Filters: {
|
||||
Blur: typeof Blur;
|
||||
Brighten: typeof Brighten;
|
||||
Contrast: typeof Contrast;
|
||||
Emboss: typeof Emboss;
|
||||
Enhance: typeof Enhance;
|
||||
Grayscale: typeof Grayscale;
|
||||
HSL: typeof HSL;
|
||||
HSV: typeof HSV;
|
||||
Invert: typeof Invert;
|
||||
Kaleidoscope: typeof Kaleidoscope;
|
||||
Mask: typeof Mask;
|
||||
Noise: typeof Noise;
|
||||
Pixelate: typeof Pixelate;
|
||||
Posterize: typeof Posterize;
|
||||
RGB: typeof RGB;
|
||||
RGBA: typeof RGBA;
|
||||
Sepia: typeof Sepia;
|
||||
Solarize: typeof Solarize;
|
||||
Threshold: typeof Threshold;
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user