Working Externa js functions
next: PDF field names to match loop
This commit is contained in:
parent
0122c97b76
commit
2d16ea65c9
|
|
@ -53,8 +53,7 @@
|
|||
"name": "affected",
|
||||
"type": "number"
|
||||
}
|
||||
],
|
||||
"output": true
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +1,39 @@
|
|||
{
|
||||
"meta": {
|
||||
"options": {
|
||||
"linkedFile": "/views/index.ejs",
|
||||
"linkedForm": "serverconnectform1"
|
||||
},
|
||||
"$_POST": [
|
||||
{
|
||||
"type": "text",
|
||||
"fieldName": "db_fullName",
|
||||
"name": "db_fullName"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"fieldName": "db_licenseNumber",
|
||||
"name": "db_licenseNumber"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"name": "db_stateIssue"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"fieldName": "db_employeeID",
|
||||
"options": {
|
||||
"rules": {
|
||||
"core:number": {}
|
||||
}
|
||||
},
|
||||
"name": "db_employeeID"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"fieldName": "owner",
|
||||
"name": "owner"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"fieldName": "db_stateIssue",
|
||||
"name": "db_stateIssue"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -110,7 +124,8 @@
|
|||
"name": "affected",
|
||||
"type": "number"
|
||||
}
|
||||
]
|
||||
],
|
||||
"output": true
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
|
@ -0,0 +1,20 @@
|
|||
// JavaScript Document
|
||||
// map to create substitution to match the Datasource field => PDF Field name
|
||||
// [DataSource Field, PDF Field]
|
||||
const map = new Map([
|
||||
['a', 1],
|
||||
['b', 2],
|
||||
['c', 3]
|
||||
]);
|
||||
|
||||
map.set('key', 'value') // sets 'key' to = 'value' in Map object name map
|
||||
|
||||
const m = map.get('key') // returns value
|
||||
|
||||
function getValueByKey(map, key) {
|
||||
const entry = [...map].find(([k, v]) => k === key);
|
||||
return entry ? entry[1] : undefined;
|
||||
}
|
||||
|
||||
const keyToFind = 'b';
|
||||
const value = getValueByKey(map, keyToFind); // Returns 2
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
// JavaScript Document
|
||||
|
||||
function myFunction() {
|
||||
let myVar = 'Hello, Wappler!';
|
||||
return myVar;
|
||||
}
|
||||
|
||||
function runMyFunction() {
|
||||
// alert("function run")
|
||||
let result = generateRandomIdentifier(9);
|
||||
// Use Wappler dmx.set to bind result to a Wappler variable if needed
|
||||
//<p>{{myResult}}</p>
|
||||
console.log(result)
|
||||
dmx.global.set('myResult', result);
|
||||
|
||||
}
|
||||
async function toBase64(filePath) {
|
||||
const img = await fetch(filePath).then(res => res.arrayBuffer())
|
||||
console.log(img)
|
||||
dmx.global.set('imgResult', img)
|
||||
return img
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
async function updatePdfFields(pdfBytes, dataSource) {
|
||||
// Load the PDF document
|
||||
const pdfDoc = await PDFDocument.load(pdfBytes);
|
||||
const form = pdfDoc.getForm();
|
||||
|
||||
// Loop over each record in the Wappler data source
|
||||
dataSource.forEach((record) => {
|
||||
// Loop over each key-value pair in the record
|
||||
Object.entries(record).forEach(([fieldName, fieldValue]) => {
|
||||
// Find the form field in the PDF by name
|
||||
const formField = form.getTextField(fieldName);
|
||||
|
||||
// If the field exists in the PDF, update it with the value
|
||||
if (formField) {
|
||||
formField.setText(String(fieldValue));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Serialize the PDF back to bytes and return
|
||||
const updatedPdfBytes = await pdfDoc.save();
|
||||
return updatedPdfBytes;
|
||||
}
|
||||
|
||||
// Usage Example
|
||||
async function main() {
|
||||
// Load your PDF as bytes (e.g., using fetch)
|
||||
const pdfBytes = await fetch("path/to/your.pdf").then((res) =>
|
||||
res.arrayBuffer()
|
||||
);
|
||||
|
||||
// Sample data source from Wappler
|
||||
const dataSource = [
|
||||
{ fieldName1: "Value1", fieldName2: "Value2" },
|
||||
{ fieldName1: "AnotherValue1", fieldName2: "AnotherValue2" },
|
||||
];
|
||||
|
||||
// Call the function to update the PDF fields
|
||||
const updatedPdfBytes = await updatePdfFields(pdfBytes, dataSource);
|
||||
|
||||
// Do something with the updated PDF, e.g., download it or display it
|
||||
}
|
||||
|
|
@ -0,0 +1,101 @@
|
|||
// JavaScript Document
|
||||
|
||||
//Use this function as a start - to pass the path, then datasource to update with pdfbytes, then download -- Maybe combine into one file?
|
||||
//wich is more efficient?
|
||||
|
||||
//filepath = /PDF/XXX.pdf, dataSource = datastore.var
|
||||
// *** Use of 'rest paramater' syntax to add extra datasources at the end.
|
||||
//return array of datasources i.e [datastore,data_view1] and pass that array to updatePdfFields
|
||||
//Consider default values = filepath = '/PDF/masterTemplate.pdf'
|
||||
async function toBase64(filePath, ...dataSources) {
|
||||
console.log(filePath);
|
||||
const pdfBytes = await fetch(filePath).then((res) => res.arrayBuffer());
|
||||
|
||||
// console.log(dataSources); // should be only 2,
|
||||
updatePdfFields(pdfBytes, dataSources);
|
||||
|
||||
//return pdfBytes
|
||||
}
|
||||
|
||||
async function updatePdfFields(pdfBytes, dataSources) {
|
||||
// Load the PDF document
|
||||
console.log("pdfBytes.size =", pdfBytes.byteLength);
|
||||
console.log(dataSources);
|
||||
const pdfDoc = await PDFLib.PDFDocument.load(pdfBytes);
|
||||
const form = pdfDoc.getForm();
|
||||
|
||||
// Loop over each data source passed to the function
|
||||
dataSources.forEach((dataSource) => {
|
||||
// Loop over each record in the current data source
|
||||
dataSource.forEach((record) => {
|
||||
// Loop over each key-value pair in the record
|
||||
Object.entries(record).forEach(([fieldName, fieldValue]) => {
|
||||
console.log(fieldName, " => ", fieldValue);
|
||||
|
||||
// Find the form field in the PDF by name
|
||||
/** !!! BLOCK 1 Start
|
||||
const formField = form.getTextField(fieldName);
|
||||
// If the field exists in the PDF, update it with the value
|
||||
if (formField) {
|
||||
formField.setText(String(fieldValue));
|
||||
}
|
||||
**/ // BLOCK 1 END
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Serialize the PDF back to bytes
|
||||
const updatedPdfBytes = await pdfDoc.save();
|
||||
|
||||
// Trigger download of the updated PDF
|
||||
downloadPdf(updatedPdfBytes, "UpdatedDocument.pdf");
|
||||
}
|
||||
|
||||
// Function to trigger download of the updated PDF
|
||||
function downloadPdf(pdfBytes, fileName) {
|
||||
// Create a Blob from the PDF bytes
|
||||
const blob = new Blob([pdfBytes], { type: "application/pdf" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
// Create a link element for the download
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
link.download = fileName;
|
||||
|
||||
// Append the link to the document, trigger a click, and remove it afterward
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
|
||||
// Release the object URL to free up memory
|
||||
URL.revokeObjectURL(url);
|
||||
}
|
||||
|
||||
// Usage Example
|
||||
async function main() {
|
||||
// Load your PDF as bytes (e.g., using fetch)
|
||||
const pdfBytes = await fetch("path/to/your.pdf").then((res) =>
|
||||
res.arrayBuffer()
|
||||
);
|
||||
|
||||
// Sample data sources from Wappler
|
||||
const dataSource1 = [{ fieldName1: "Value1", fieldName2: "Value2" }];
|
||||
const dataSource2 = [
|
||||
{ fieldName3: "AnotherValue1", fieldName4: "AnotherValue2" },
|
||||
];
|
||||
|
||||
// Call the function with multiple data sources
|
||||
await updatePdfFields(pdfBytes, dataSource1, dataSource2);
|
||||
}
|
||||
|
||||
function generateRandomFilename() {
|
||||
const characters =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
let filename = "";
|
||||
for (let i = 0; i < 8; i++) {
|
||||
const randomIndex = Math.floor(Math.random() * characters.length);
|
||||
filename += characters[randomIndex];
|
||||
}
|
||||
console.log("Random Filename: ", filename);
|
||||
return filename;
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
// JavaScript Document v1.2
|
||||
|
||||
const canvas = document.getElementById('signatureCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
let drawing = false;
|
||||
|
||||
function myTestFunction(variable1, variable2) {
|
||||
console.log(variable1, variable2);
|
||||
// Your logic here
|
||||
}
|
||||
// Get the canvas element
|
||||
|
||||
|
||||
// Function to get the canvas offset
|
||||
function getCanvasOffset() {
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
//console.log("offsetX:",rect.left, " OffsetY:",rect.top)
|
||||
return {
|
||||
offsetX: rect.left,
|
||||
offsetY: rect.top
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function clearCanvas() {
|
||||
console.log("Clear Signature area")
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
|
||||
function startDrawing(e) {
|
||||
console.log("Start Signature Capture")
|
||||
//console.log(e)
|
||||
drawing = true;
|
||||
draw(e);
|
||||
}
|
||||
|
||||
function endDrawing() {
|
||||
console.log("Stopped Signature Capture")
|
||||
drawing = false;
|
||||
ctx.beginPath();
|
||||
}
|
||||
|
||||
function draw(e) {
|
||||
//console.log(e)
|
||||
if (!drawing) return;
|
||||
ctx.lineWidth = 2;
|
||||
ctx.lineCap = 'round';
|
||||
ctx.strokeStyle = '#000';
|
||||
|
||||
const { offsetX, offsetY } = getCanvasOffset();
|
||||
let x = e.clientX - offsetX //canvas.offsetLeft;
|
||||
let y = e.clientY - offsetY //canvas.offsetTop;
|
||||
//console.log("X:",x," Y:",y)
|
||||
|
||||
//let x = e.clientX - canvas.offsetLeft;
|
||||
//let y = e.clientY - canvas.offsetTop;
|
||||
//console.log("X:", x, " Y:", y)
|
||||
ctx.lineTo(x, y);
|
||||
ctx.stroke();
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, y);
|
||||
}
|
||||
|
||||
|
||||
function generateRandomIdentifier(size) {
|
||||
|
||||
if (size > 20) {
|
||||
let size = 20
|
||||
console.log("randomIdentifier Exceeded max len of 20. Defaults to 20 ")
|
||||
}
|
||||
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
let randIdentifier = '';
|
||||
for (let i = 0; i < size; i++) {
|
||||
const randomIndex = Math.floor(Math.random() * characters.length);
|
||||
randIdentifier += characters[randomIndex];
|
||||
}
|
||||
console.log("Random randIdentifier: ", randIdentifier);
|
||||
return randIdentifier;
|
||||
}
|
||||
//canvas.addEventListener('mousedown', startDrawing);
|
||||
//canvas.addEventListener('mouseup', endDrawing);
|
||||
//canvas.addEventListener('mousemove', draw);
|
||||
|
||||
// ** TOUCH EVENT LISTNERS FOR TABLETS
|
||||
|
||||
//canvas.addEventListener('touchstart', (e) => startDrawing(e.touches[0]));
|
||||
//canvas.addEventListener('touchend', endDrawing);
|
||||
//canvas.addEventListener('touchmove', (e) => draw(e.touches[0]));
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
// JavaScript Document
|
||||
|
||||
//import { PDFDocument } from 'pdf-lib'
|
||||
|
||||
//http://localhost:8100/assets/pdf/testpdf.pdf
|
||||
async function fillform() {
|
||||
const formURL = "/assets/pdf/testpdf.pdf";
|
||||
const formPdfBytes = await fetch(formURL).then((res) => res.arrayBuffer());
|
||||
const pdfdoc = await PDFDocument.load(formPdfBytes);
|
||||
}
|
||||
|
||||
function myTestFunction(variable1, variable2) {
|
||||
console.log(variable1, variable2);
|
||||
// Your logic here
|
||||
}
|
||||
|
||||
//Use this function wihouth the http to pull from remote host.
|
||||
async function pullPDF() {
|
||||
// IDEA: Load all the possible methods and calls in one run then you can expose to Wappler for processing. As long as the dmx.set function will work
|
||||
|
||||
const formUrl = "/assets/PDFdemo.pdf"; //'https://pdf-lib.js.org/assets/dod_character.pdf'
|
||||
const formPdfBytes = await fetch(formUrl).then((res) => res.arrayBuffer());
|
||||
const pdfDoc = await PDFLib.PDFDocument.load(formPdfBytes);
|
||||
const form = pdfDoc.getForm();
|
||||
|
||||
console.log("Size of pdf:", formPdfBytes.byteLength);
|
||||
|
||||
const fieldnames = []; //empty array to assign each field name to.
|
||||
const fields = form.getFields();
|
||||
|
||||
fields.forEach((field) => {
|
||||
const name = field.getName();
|
||||
fieldnames.push(name);
|
||||
console.log("Field name:", name);
|
||||
});
|
||||
|
||||
console.log("First field name:", fields[0].getName());
|
||||
|
||||
console.log(fieldnames);
|
||||
// dmx.set('fieldsList', fieldnames)
|
||||
console.log("Size of pdf:", pdfObjects[1].byteLength);
|
||||
const pdfObjects = [formUrl, formPdfBytes, pdfDoc, form, form.getFields()];
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -25,5 +25,16 @@ dmx.config({
|
|||
],
|
||||
"outputType": "text"
|
||||
}
|
||||
},
|
||||
"observationPage": {
|
||||
"flowClearPoints": {
|
||||
"meta": [
|
||||
{
|
||||
"name": "zzmyTestFunction",
|
||||
"type": "text"
|
||||
}
|
||||
],
|
||||
"local": {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
|
@ -1,11 +1,39 @@
|
|||
{
|
||||
"Trainer": {
|
||||
"Jeff": {},
|
||||
"Amy": {},
|
||||
"Justin": {},
|
||||
"Teresa": {},
|
||||
"Angie": {},
|
||||
"Valerie": {},
|
||||
"Pree": {}
|
||||
"Trainer": [
|
||||
{
|
||||
"Name": "Jeff Daniels",
|
||||
"Login": "dnije",
|
||||
"ID": 1
|
||||
},
|
||||
{
|
||||
"Name": "Angie Houghland",
|
||||
"Login": "uhougang",
|
||||
"ID": 2
|
||||
},
|
||||
{
|
||||
"Name": "Justin Casas",
|
||||
"Login": "casasjus",
|
||||
"ID": 3
|
||||
},
|
||||
{
|
||||
"Name": "Theresa Alvarez",
|
||||
"Login": "theralva",
|
||||
"ID": 4
|
||||
},
|
||||
{
|
||||
"Name": "Amy oConner",
|
||||
"Login": "amycocon",
|
||||
"ID": 5
|
||||
},
|
||||
{
|
||||
"Name": "Valerie Spencer",
|
||||
"Login": "spencval",
|
||||
"ID": 6
|
||||
},
|
||||
{
|
||||
"Name": "Pree Suresh",
|
||||
"Login": "epreesur",
|
||||
"ID": 7
|
||||
}
|
||||
]
|
||||
}
|
||||
122
views/index.ejs
122
views/index.ejs
|
|
@ -1,11 +1,10 @@
|
|||
<!-- Wappler include head-page="layouts/main" fontawesome_5="cdn" bootstrap5="local" is="dmx-app" id="index" appConnect="local" components="{dmxBootstrap5Navigation:{},dmxAnimateCSS:{},dmxStateManagement:{},dmxDatastore:{},dmxBootstrap5Modal:{},dmxFormatter:{},dmxBootstrap5TableGenerator:{},dmxBootstrap5Toasts:{},dmxBootbox5:{},dmxBrowser:{}}" -->
|
||||
<!-- Wappler include head-page="layouts/main" fontawesome_5="cdn" bootstrap5="local" is="dmx-app" id="index" appConnect="local" components="{dmxBootstrap5Navigation:{},dmxAnimateCSS:{},dmxStateManagement:{},dmxDatastore:{},dmxBootstrap5Modal:{},dmxFormatter:{},dmxBootstrap5TableGenerator:{},dmxBootstrap5Toasts:{},dmxBootbox5:{},dmxBrowser:{},dmxBootstrap5Tooltips:{}}" -->
|
||||
<div is="dmx-browser" id="browser1"></div>
|
||||
|
||||
<dmx-datetime id="DateTimeNow" interval="minutes"></dmx-datetime>
|
||||
<script is="dmx-flow" id="delConfirm" type="text/dmx-flow">{
|
||||
bootbox.confirm: {
|
||||
name: "confirmYesNo",
|
||||
output: true,
|
||||
message: "Delete ",
|
||||
title: "Remove list item",
|
||||
buttons: {
|
||||
|
|
@ -16,7 +15,6 @@
|
|||
steps: {
|
||||
serverConnect: {
|
||||
name: "pageFlowSC1",
|
||||
output: true,
|
||||
outputType: "object",
|
||||
url: "/api/delRecord",
|
||||
site: "ERTFastFiller"
|
||||
|
|
@ -31,8 +29,32 @@
|
|||
<dmx-value id="dataID"></dmx-value>
|
||||
<dmx-json-datasource id="stateJSON" is="dmx-serverconnect" url="/states.json"></dmx-json-datasource>
|
||||
<dmx-json-datasource id="trainerJSON" is="dmx-serverconnect" url="/trainer.json"></dmx-json-datasource>
|
||||
|
||||
<div class="modal" id="SignatureModal1" is="dmx-bs5-modal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Signature Capture</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body text-center">
|
||||
<p>Driver must sign for Road Test</p>
|
||||
<canvas id="signatureCanvas" width="700" height="200" style="border:1px solid #000;" onmousedown="startDrawing(event)" onmouseup="endDrawing()" onmousemove="draw(event)"></canvas>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button id="btn4" class="btn btn-warning w-25" data-bs-toggle="button" onclick="clearCanvas()">Clear Signature</button>
|
||||
<button type="button" class="btn btn-danger w-auto" data-bs-dismiss="modal" dmx-bs-tooltip="'Close Signature Panel'" data-bs-trigger="hover" data-bs-placement="top">Close</button>
|
||||
<button type="button" class="btn btn-success w-auto">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="modal" id="modal1" is="dmx-bs5-modal" tabindex="-1">
|
||||
<div class="modal-dialog modal-dialog-centered" role="document">
|
||||
<div class="modal-dialog modal-dialog-centered modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Driver Information</h5>
|
||||
|
|
@ -40,7 +62,7 @@
|
|||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="container">
|
||||
<form is="dmx-serverconnect-form" id="serverconnectform1" method="post" action="/api/insert" dmx-generator="bootstrap5" dmx-form-type="horizontal" dmx-on:done="modal1.hide();DBSC1.load({})">
|
||||
<form is="dmx-serverconnect-form" id="serverconnectform1" method="post" action="/api/insert" dmx-generator="bootstrap5" dmx-form-type="horizontal" dmx-on:done="modal1.hide();DBSC1.load({})" dmx-on:submit="">
|
||||
<div class="form-group mb-3 row">
|
||||
<label for="inp_db_fullName" class="col-sm-2 col-form-label">full name</label>
|
||||
<div class="col-sm-10">
|
||||
|
|
@ -54,32 +76,36 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="form-group mb-3 row">
|
||||
<label for="inp_db_stateIssue" class="col-sm-2 col-form-label">state issue</label>
|
||||
<div class="col-sm-10">
|
||||
<select id="select1" class="form-select" dmx-bind:options="stateJSON.data.states" optiontext="name" optionvalue="abbreviation">
|
||||
<option value="1">Option One</option>
|
||||
<option value="2">Option Two</option>
|
||||
<option value="3">Option Three</option>
|
||||
<label for="db_stateIssue" class="col-sm-2 col-form-label">state issue</label>
|
||||
<div class="col-sm-4">
|
||||
<select id="db_stateIssue" class="form-select" dmx-bind:options="stateJSON.data.states" optiontext="name" optionvalue="abbreviation" name="db_stateIssue" dmx-bind:value="selectedValue">
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-6">
|
||||
<small id="bs5-form-group-help1" class="form-text text-muted">Your great help text.</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group mb-3 row">
|
||||
<label for="inp_db_employeeID" class="col-sm-2 col-form-label">Trainer</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="number" class="form-control" id="inp_db_employeeID" name="db_employeeID" aria-describedby="inp_db_employeeID_help" placeholder="Enter Db employee">
|
||||
<div class="col-sm-3">
|
||||
<input type="number" class="form-control" id="inp_db_employeeID" name="db_employeeID" aria-describedby="inp_db_employeeID_help" placeholder="Enter Db employee" dmx-bind:value="select1.selectedValue" readonly="true">
|
||||
</div>
|
||||
<div class="col-6 offset-1">
|
||||
<select id="select1" class="form-select" dmx-bind:options="trainerJSON.data.Trainer" name="db_trainerID" optiontext="Name" optionvalue="ID" dmx-bind:value="selectedValue">
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group mb-3 row">
|
||||
<label for="inp_owner" class="col-sm-2 col-form-label">Owner</label>
|
||||
<label for="inp_owner" class="col-sm-2 col-form-label">Date</label>
|
||||
<div class="col-sm-10">
|
||||
<input type="text" class="form-control" id="inp_owner" name="owner" aria-describedby="inp_owner_help" placeholder="Enter Owner">
|
||||
<input type="text" class="form-control" id="inp_owner" name="owner" aria-describedby="inp_owner_help" placeholder="Enter Owner" dmx-bind:value="DateTimeNow.datetime.formatDate('MM-dd-yyyy')" readonly="true">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group mb-3 row">
|
||||
<div class="col-sm-2"> </div>
|
||||
<div class="col-sm-10">
|
||||
<button type="submit" class="btn btn-success" dmx-bind:disabled="state.executing">Save <span class="spinner-border spinner-border-sm" role="status" dmx-show="state.executing"></span></button>
|
||||
<button id="btn4" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
<button id="xbtn4" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
@ -101,28 +127,66 @@
|
|||
<button id="btn5" class="btn btn-warning" data-bs-target="undefined" dmx-on:click="browser1.goto('/signature',true,'Get Signature')">Signature</button>
|
||||
</div>
|
||||
<div class="text-center offset-2 col-3" id="cRight">
|
||||
<button id="btn2" class="btn lh-lg btn-warning">Driver Trainers</button>
|
||||
<button id="btn2" class="btn lh-lg btn-warning" data-bs-toggle="modal" data-bs-target="#SignatureModal1">Driver Trainers</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" dmx-hide="datastore1.data.isEmpty()">
|
||||
</div>
|
||||
<div class="row" id="daForm">
|
||||
|
||||
<div class="col">
|
||||
<form is="dmx-serverconnect-form" id="serverconnectform2" method="post" action="/api/insert" dmx-generator="bootstrap5" dmx-form-type="horizontal">
|
||||
<div class="form-group mb-3 row">
|
||||
<div class="col-sm-7">
|
||||
<input type="text" class="form-control" id="inp_db_fullName" name="db_fullName" aria-describedby="inp_db_fullName_help" placeholder="Enter Db full name">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group mb-3 row">
|
||||
<div class="col-sm-7">
|
||||
<input type="text" class="form-control" id="inp_db_licenseNumber" name="db_licenseNumber" aria-describedby="inp_db_licenseNumber_help" placeholder="Enter Db license number">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group mb-3 row">
|
||||
<div class="col-sm-7">
|
||||
<input type="number" class="form-control" id="inp_db_employeeID" name="db_employeeID" aria-describedby="inp_db_employeeID_help" placeholder="Enter Db employee">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group mb-3 row">
|
||||
<div class="col-sm-6">
|
||||
<input type="text" class="form-control" id="inp_owner" name="owner" aria-describedby="inp_owner_help" placeholder="Enter Owner">
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group mb-3 row">
|
||||
<div class="col-sm-7">
|
||||
<input type="text" class="form-control" id="inp_db_stateIssue" name="db_stateIssue" aria-describedby="inp_db_stateIssue_help" placeholder="Enter Db state issue">
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="col">
|
||||
<h1>Display Area.</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" id="eSignature">
|
||||
<p>This area will display the signature.</p>
|
||||
</div>
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<th>Db full name</th>
|
||||
<th>Db license number</th>
|
||||
<th>Db state issue</th>
|
||||
<th>Db employee</th>
|
||||
<th>Owner</th>
|
||||
<th>DELETE</th>
|
||||
<th>DA Name</th>
|
||||
<th>license number</th>
|
||||
<th>state issue</th>
|
||||
<th>Trainer #</th>
|
||||
<th>Date</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody is="dmx-repeat" dmx-generator="bs5table" dmx-bind:repeat="DBSC1.data.query" id="tableRepeat1">
|
||||
<tr>
|
||||
<td>
|
||||
<form id="IDAction" action="/api/delRecord" method="post" is="dmx-serverconnect-form" dmx-on:success="DBSC1.load({})">
|
||||
<td dmx-bs-tooltip="'Click will delete without confirmation'" data-bs-trigger="hover" data-bs-placement="left">
|
||||
<form action="/api/delRecord" method="post" dmx-on:success="DBSC1.load({})" is="dmx-serverconnect-form" id="serverconnectform3">
|
||||
<input id="deleteid" name="deleteid" type="hidden" class="form-control" dmx-bind:value="ID">
|
||||
<button id="btn3" class="btn btn-sm btn-warning" dmx-text="ID" type="submit">Button</button>
|
||||
<button id="btn3" class="btn btn-sm btn-outline-danger" dmx-text="ID" type="submit" dmx-on:mouseover="">Button</button>
|
||||
</form>
|
||||
|
||||
</td>
|
||||
|
|
@ -135,8 +199,10 @@
|
|||
</tbody>
|
||||
</table>
|
||||
<div class="row">
|
||||
<h3>{{DBSC1.data.query.count()+" Records"}}</h3>
|
||||
<h3>{{DBSC1.data.query.count()+" Training records"}}</h3>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
<script src="/PDF/pdfLibSignature.js"></script>
|
||||
-->
|
||||
<meta name="ac:route" content="/">
|
||||
|
|
@ -46,7 +46,7 @@
|
|||
<div class="navbar-nav w-100">
|
||||
<div class="nav-item dropdown"><a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#" id="dropdown1" role="button" aria-haspopup="true" aria-expanded="false">Command</a>
|
||||
<div class="dropdown-menu" aria-labelledby="dropdown1">
|
||||
<a class="dropdown-item" href="#">Action</a>
|
||||
<a class="dropdown-item" href="/" internal="true">Home</a>
|
||||
<a class="dropdown-item" href="#">Another action</a>
|
||||
<a class="dropdown-item" href="/signature" internal="true">Signature</a>
|
||||
</div>
|
||||
|
|
@ -71,7 +71,7 @@
|
|||
<p class="text-center d-lg-none d-xl-block">ERT Fast Fill - Developed by Jeff Daniels (DNIJE) / Data only locally saved / Powered by Docker and Node.js</p>
|
||||
</footer>
|
||||
<script src="/bootstrap/5/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
<script src="/PDF/pdfLibSignature.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,53 @@
|
|||
<!-- Wappler include head-page="layouts/main" fontawesome_5="cdn" bootstrap5="local" is="dmx-app" id="observationPage" appConnect="local" components="{dmxBootstrap5TableGenerator:{},dmxMasonry:{},dmxFormatter:{},dmxBootstrap5Popovers:{},dmxBootstrap5Toasts:{},dmxDataTraversal:{},dmxStateManagement:{},dmxDatastore:{},dmxValidator:{},dmxBootstrap5Offcanvas:{},dmxBootstrap5Modal:{},dmxBootstrap5Navigation:{},dmxBootstrap5Tooltips:{},dmxBootbox5:{}}" -->
|
||||
<div class="modal" id="modalTestButton" is="dmx-bs5-modal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">ModalTestButton</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<table class="table table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Id</th>
|
||||
<th>Db full name</th>
|
||||
<th>Db license number</th>
|
||||
<th>Db state issue</th>
|
||||
<th>Db employee</th>
|
||||
<th>Owner</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody is="dmx-repeat" dmx-generator="bs5table" dmx-bind:repeat="data_view1.data" id="tableRepeat5">
|
||||
<tr>
|
||||
<td dmx-text="ID"></td>
|
||||
<td dmx-text="db_fullName"></td>
|
||||
<td dmx-text="db_licenseNumber"></td>
|
||||
<td dmx-text="db_stateIssue"></td>
|
||||
<td dmx-text="db_employeeID"></td>
|
||||
<td dmx-text="owner"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>Only here for a demo purpose - Maybe will stay or go. dunno. </p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary">Save changes</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<dmx-value id="var1"></dmx-value>
|
||||
<script is="dmx-flow" id="flowClearPoints" type="text/dmx-flow">{
|
||||
runJS: {
|
||||
name: "zzmyTestFunction",
|
||||
output: true,
|
||||
outputType: "text",
|
||||
function: "toBase64",
|
||||
args: ["/PDF/testpdf.pdf", "{{datastore1.data}}", "{{data_view1.data}}"]
|
||||
}
|
||||
}</script>
|
||||
<div class="container wappler-block pt-3 pb-3">
|
||||
<div class="modal" id="modal-success" is="dmx-bs5-modal" tabindex="-1" role="dialog">
|
||||
<div class="modal-dialog" role="document">
|
||||
|
|
@ -55,7 +104,10 @@
|
|||
<label class="form-check-label" for="CKBinput3">Show Section detail</label>
|
||||
</div>
|
||||
</div>
|
||||
<p>Offcanvas body text goes here.</p>
|
||||
<p>
|
||||
|
||||
</p>
|
||||
<div class="container"><button id="btn6" class="btn text-bg-danger" dmx-on:click="run({run:{name:'CLearPoints',outputType:'text',action:`datastore1.clear()`}})">Clear Point Table</button></div>
|
||||
</div>
|
||||
</div>
|
||||
<dmx-toggle id="toggle1" checked="true"></dmx-toggle>
|
||||
|
|
@ -69,7 +121,8 @@
|
|||
<div class="container border-primary border-2 border">
|
||||
<nav class="navbar navbar-expand-lg">
|
||||
<span class="navbar-text">
|
||||
<button id="btn3" class="btn" data-bs-toggle="modal" data-bs-target="#modal1">Button</button>Navbar Text</span>
|
||||
<button id="btn3" class="btn" data-bs-toggle="modal" data-bs-target="#modal1" dmx-on:click="run({runJS:{name:'r_downloadPDF',outputType:'text',function:'downloadPDF',args:['PDFBytes']}})">Download PDF
|
||||
</button>Navbar Text</span>
|
||||
<div id="collapse1" class="collapse navbar-collapse">
|
||||
<div class="nav w-100">
|
||||
<a class="nav-item nav-link" href="#">Link</a>
|
||||
|
|
@ -85,7 +138,7 @@
|
|||
<div class="row">
|
||||
<div class="col-3">
|
||||
<p class="text-center"><b>Who you are grading</b></p>
|
||||
<select id="select1" class="form-select" dmx-bind:options="qDB.data.query" optiontext="db_fullName" optionvalue="db_employeeID">
|
||||
<select id="select1" class="form-select" dmx-bind:options="qDB.data.query" optiontext="db_fullName" optionvalue="ID">
|
||||
</select>
|
||||
</div>
|
||||
<div class="col">
|
||||
|
|
@ -96,12 +149,12 @@
|
|||
<th>License No.</th>
|
||||
<th>Issue State</th>
|
||||
<th>Employee No.</th>
|
||||
<th>Driver Trainer</th>
|
||||
<th>DATE</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody is="dmx-repeat" dmx-generator="bs5table" dmx-bind:repeat="data_view1.data" id="tableRepeat4">
|
||||
<tr class="text-xl-center">
|
||||
<td dmx-text="db_fullName"></td>
|
||||
<td dmx-text="db_fullName" dmx-bs-tooltip="('Record # '+ID)" data-bs-trigger="hover" data-bs-placement="top"></td>
|
||||
<td dmx-text="db_licenseNumber"></td>
|
||||
<td dmx-text="db_stateIssue" dmx-class:bg-danger="db_stateIssue.isEmpty()"></td>
|
||||
<td dmx-text="db_employeeID"></td>
|
||||
|
|
@ -109,12 +162,15 @@
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<dmx-data-view id="data_view1" dmx-bind:data="qDB.data.query" filter="db_employeeID==select1.value"></dmx-data-view>
|
||||
<dmx-data-view id="data_view1" dmx-bind:data="qDB.data.query" filter="ID==select1.value"></dmx-data-view>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<button id="btn2" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modal1">Print</button>
|
||||
<button id="savePDF" class="btn btn-warning" data-bs-target="#modal1" dmx-on:click="flowClearPoints.run()">SAVE</button>
|
||||
<button id="btn7" class="btn" data-bs-toggle="modal" data-bs-target="#modalTestButton">modalTest</button>
|
||||
<p>A nice paragraph {{myResult}}</p>
|
||||
</div>
|
||||
<div class="col"></div>
|
||||
<div class="col"></div>
|
||||
|
|
@ -157,7 +213,10 @@
|
|||
<div class="row" dmx-hide="offcanvas1.CKBinput2.checked">
|
||||
<div class="col">
|
||||
<p class="fw-bold">The DT should fill out the evaluation form during the Enhanced Road Test based on the below points system and description. Every item in Section must have a score to be considered complete and valid; there should be no blank spaces. A DA candidate must have a score of total score 10 or lower to pass.</p>
|
||||
<table class="table">
|
||||
|
||||
</div>
|
||||
<div class="col">
|
||||
<table class="table table-striped">
|
||||
<thead class="table-primary">
|
||||
<tr>
|
||||
<th scope="col">Tier</th>
|
||||
|
|
@ -213,11 +272,14 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<header>
|
||||
<h3 id="scoreHeader" dmx-show="!datastore1.data.hasItems()">No Score shown yet.</h3>
|
||||
</header>
|
||||
|
||||
<div class="container" id="DS">
|
||||
<table class="table table-striped">
|
||||
<div class="row">
|
||||
<header class="text-center">
|
||||
<h3 id="scoreHeader" dmx-show="!datastore1.data.hasItems()" class="text-bg-danger" dmx-bs-popover="'If you save this file without points the observation will have zero points.'" dmx-bind:popover-title="'Info'" data-bs-trigger="hover focus">No Points recorded </h3>
|
||||
</header>
|
||||
</div>
|
||||
<table class="table table-striped" dmx-show="datastore1.data.hasItems()">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>$id</th>
|
||||
|
|
@ -238,70 +300,8 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<script>
|
||||
const canvas = document.getElementById('signatureCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
let drawing = false;
|
||||
|
||||
// Get the canvas element
|
||||
|
||||
|
||||
// Function to get the canvas offset
|
||||
function getCanvasOffset() {
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
//console.log("offsetX:",rect.left, " OffsetY:",rect.top)
|
||||
return {
|
||||
offsetX: rect.left,
|
||||
offsetY: rect.top
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function clearCanvas() {
|
||||
console.log("Clear Signature area")
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
|
||||
function startDrawing(e) {
|
||||
console.log("Start Signature Capture")
|
||||
//console.log(e)
|
||||
drawing = true;
|
||||
draw(e);
|
||||
}
|
||||
|
||||
function endDrawing() {
|
||||
console.log("Stopped Signature Capture")
|
||||
drawing = false;
|
||||
ctx.beginPath();
|
||||
}
|
||||
|
||||
function draw(e) {
|
||||
//console.log(e)
|
||||
if (!drawing) return;
|
||||
ctx.lineWidth = 2;
|
||||
ctx.lineCap = 'round';
|
||||
ctx.strokeStyle = '#000';
|
||||
|
||||
const { offsetX, offsetY } = getCanvasOffset();
|
||||
let x = e.clientX - offsetX //canvas.offsetLeft;
|
||||
let y = e.clientY - offsetY //canvas.offsetTop;
|
||||
//console.log("X:",x," Y:",y)
|
||||
|
||||
//let x = e.clientX - canvas.offsetLeft;
|
||||
//let y = e.clientY - canvas.offsetTop;
|
||||
//console.log("X:", x, " Y:", y)
|
||||
ctx.lineTo(x, y);
|
||||
ctx.stroke();
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(x, y);
|
||||
}
|
||||
|
||||
//canvas.addEventListener('mousedown', startDrawing);
|
||||
//canvas.addEventListener('mouseup', endDrawing);
|
||||
//canvas.addEventListener('mousemove', draw);
|
||||
|
||||
canvas.addEventListener('touchstart', (e) => startDrawing(e.touches[0]));
|
||||
canvas.addEventListener('touchend', endDrawing);
|
||||
canvas.addEventListener('touchmove', (e) => draw(e.touches[0]));
|
||||
|
||||
</script>
|
||||
<script src="https://unpkg.com/pdf-lib/dist/pdf-lib.min.js"></script>
|
||||
<script src="/PDF/libPDFscripts.js"></script>
|
||||
<!--
|
||||
<script src="/PDF/pdfLibSignature.js"></script>
|
||||
-->
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<!-- Wappler include head-page="observationPage" appConnect="local" is="dmx-app" bootstrap5="local" fontawesome_5="cdn" -->
|
||||
<div class="modal" id="SignatureModal1" is="dmx-bs5-modal" tabindex="-1">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Signature Capture</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
</div>
|
||||
<div class="modal-body text-center">
|
||||
<p>Driver must sign for Road Test</p>
|
||||
<canvas id="signatureCanvas" width="700" height="200" style="border:1px solid #000;" onmousedown="startDrawing(event)" onmouseup="endDrawing()" onmousemove="draw(event)"></canvas>
|
||||
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button id="btn4" class="btn btn-warning w-25" data-bs-toggle="button" onclick="clearCanvas()">Clear Signature</button>
|
||||
<button type="button" class="btn btn-danger w-auto" data-bs-dismiss="modal" dmx-bs-tooltip="'Close Signature Panel'" data-bs-trigger="hover" data-bs-placement="top">Close</button>
|
||||
<button type="button" class="btn btn-success w-auto">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -29,6 +29,11 @@
|
|||
</div>
|
||||
</div>
|
||||
<button id="btn3" class="btn">Button</button>
|
||||
<!--
|
||||
<script src="/PDF/pdfLibSignature.js"></script>
|
||||
-->
|
||||
|
||||
<!--
|
||||
<script>
|
||||
const canvas = document.getElementById('signatureCanvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
|
@ -40,7 +45,7 @@
|
|||
// Function to get the canvas offset
|
||||
function getCanvasOffset() {
|
||||
const rect = canvas.getBoundingClientRect();
|
||||
console.log("offsetX:",rect.left, " OffsetY:",rect.top)
|
||||
// console.log("offsetX:",rect.left, " OffsetY:",rect.top)
|
||||
return {
|
||||
offsetX: rect.left,
|
||||
offsetY: rect.top
|
||||
|
|
@ -76,11 +81,11 @@ function getCanvasOffset() {
|
|||
const { offsetX, offsetY } = getCanvasOffset();
|
||||
let x = e.clientX - offsetX //canvas.offsetLeft;
|
||||
let y = e.clientY - offsetY //canvas.offsetTop;
|
||||
console.log("X:",x," Y:",y)
|
||||
//console.log("X:",x," Y:",y)
|
||||
|
||||
//let x = e.clientX - canvas.offsetLeft;
|
||||
//let y = e.clientY - canvas.offsetTop;
|
||||
console.log("X:", x, " Y:", y)
|
||||
//console.log("X:", x, " Y:", y)
|
||||
ctx.lineTo(x, y);
|
||||
ctx.stroke();
|
||||
ctx.beginPath();
|
||||
|
|
@ -96,6 +101,6 @@ function getCanvasOffset() {
|
|||
canvas.addEventListener('touchmove', (e) => draw(e.touches[0]));
|
||||
|
||||
</script>
|
||||
|
||||
-->
|
||||
|
||||
<script src="/bootstrap/5/js/bootstrap.bundle.min.js"></script>
|
||||
Loading…
Reference in New Issue