Working Externa js functions

next: PDF field names to match loop
This commit is contained in:
jndaniels 2024-11-23 05:58:39 -06:00
parent 0122c97b76
commit 2d16ea65c9
19 changed files with 10887 additions and 133 deletions

View File

@ -53,8 +53,7 @@
"name": "affected", "name": "affected",
"type": "number" "type": "number"
} }
], ]
"output": true
} }
} }
} }

View File

@ -1,25 +1,39 @@
{ {
"meta": { "meta": {
"options": {
"linkedFile": "/views/index.ejs",
"linkedForm": "serverconnectform1"
},
"$_POST": [ "$_POST": [
{ {
"type": "text", "type": "text",
"fieldName": "db_fullName",
"name": "db_fullName" "name": "db_fullName"
}, },
{ {
"type": "text", "type": "text",
"fieldName": "db_licenseNumber",
"name": "db_licenseNumber" "name": "db_licenseNumber"
}, },
{
"type": "text",
"name": "db_stateIssue"
},
{ {
"type": "number", "type": "number",
"fieldName": "db_employeeID",
"options": {
"rules": {
"core:number": {}
}
},
"name": "db_employeeID" "name": "db_employeeID"
}, },
{ {
"type": "text", "type": "text",
"fieldName": "owner",
"name": "owner" "name": "owner"
},
{
"type": "text",
"fieldName": "db_stateIssue",
"name": "db_stateIssue"
} }
] ]
}, },
@ -110,7 +124,8 @@
"name": "affected", "name": "affected",
"type": "number" "type": "number"
} }
] ],
"output": true
} }
} }
} }

Binary file not shown.

20
public/PDF/dbMap.js Normal file
View File

@ -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

View File

@ -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
}

42
public/PDF/jsPDF.js Normal file
View File

@ -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
}

101
public/PDF/libPDFscripts.js Normal file
View File

@ -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;
}

View File

@ -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]));

43
public/PDF/pdfScripts.js Normal file
View File

@ -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()];
}

10293
public/PDF/test-Copy.pdf Normal file

File diff suppressed because it is too large Load Diff

View File

@ -25,5 +25,16 @@ dmx.config({
], ],
"outputType": "text" "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

View File

@ -1,11 +1,39 @@
{ {
"Trainer": { "Trainer": [
"Jeff": {}, {
"Amy": {}, "Name": "Jeff Daniels",
"Justin": {}, "Login": "dnije",
"Teresa": {}, "ID": 1
"Angie": {}, },
"Valerie": {}, {
"Pree": {} "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
}
]
} }

View File

@ -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> <div is="dmx-browser" id="browser1"></div>
<dmx-datetime id="DateTimeNow" interval="minutes"></dmx-datetime> <dmx-datetime id="DateTimeNow" interval="minutes"></dmx-datetime>
<script is="dmx-flow" id="delConfirm" type="text/dmx-flow">{ <script is="dmx-flow" id="delConfirm" type="text/dmx-flow">{
bootbox.confirm: { bootbox.confirm: {
name: "confirmYesNo", name: "confirmYesNo",
output: true,
message: "Delete ", message: "Delete ",
title: "Remove list item", title: "Remove list item",
buttons: { buttons: {
@ -16,7 +15,6 @@
steps: { steps: {
serverConnect: { serverConnect: {
name: "pageFlowSC1", name: "pageFlowSC1",
output: true,
outputType: "object", outputType: "object",
url: "/api/delRecord", url: "/api/delRecord",
site: "ERTFastFiller" site: "ERTFastFiller"
@ -31,8 +29,32 @@
<dmx-value id="dataID"></dmx-value> <dmx-value id="dataID"></dmx-value>
<dmx-json-datasource id="stateJSON" is="dmx-serverconnect" url="/states.json"></dmx-json-datasource> <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> <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" 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-content">
<div class="modal-header"> <div class="modal-header">
<h5 class="modal-title">Driver Information</h5> <h5 class="modal-title">Driver Information</h5>
@ -40,7 +62,7 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="container"> <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"> <div class="form-group mb-3 row">
<label for="inp_db_fullName" class="col-sm-2 col-form-label">full name</label> <label for="inp_db_fullName" class="col-sm-2 col-form-label">full name</label>
<div class="col-sm-10"> <div class="col-sm-10">
@ -54,32 +76,36 @@
</div> </div>
</div> </div>
<div class="form-group mb-3 row"> <div class="form-group mb-3 row">
<label for="inp_db_stateIssue" class="col-sm-2 col-form-label">state issue</label> <label for="db_stateIssue" class="col-sm-2 col-form-label">state issue</label>
<div class="col-sm-10"> <div class="col-sm-4">
<select id="select1" class="form-select" dmx-bind:options="stateJSON.data.states" optiontext="name" optionvalue="abbreviation"> <select id="db_stateIssue" class="form-select" dmx-bind:options="stateJSON.data.states" optiontext="name" optionvalue="abbreviation" name="db_stateIssue" dmx-bind:value="selectedValue">
<option value="1">Option One</option>
<option value="2">Option Two</option>
<option value="3">Option Three</option>
</select> </select>
</div> </div>
<div class="col-6">
<small id="bs5-form-group-help1" class="form-text text-muted">Your great help text.</small>
</div>
</div> </div>
<div class="form-group mb-3 row"> <div class="form-group mb-3 row">
<label for="inp_db_employeeID" class="col-sm-2 col-form-label">Trainer</label> <label for="inp_db_employeeID" class="col-sm-2 col-form-label">Trainer</label>
<div class="col-sm-10"> <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"> <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> </div>
<div class="form-group mb-3 row"> <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"> <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> </div>
<div class="form-group mb-3 row"> <div class="form-group mb-3 row">
<div class="col-sm-2">&nbsp;</div> <div class="col-sm-2">&nbsp;</div>
<div class="col-sm-10"> <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 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>
</div> </div>
</form> </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> <button id="btn5" class="btn btn-warning" data-bs-target="undefined" dmx-on:click="browser1.goto('/signature',true,'Get Signature')">Signature</button>
</div> </div>
<div class="text-center offset-2 col-3" id="cRight"> <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> </div>
<div class="row" dmx-hide="datastore1.data.isEmpty()"> <div class="row" dmx-hide="datastore1.data.isEmpty()">
</div> </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"> <table class="table">
<thead> <thead>
<tr> <tr>
<th>Id</th> <th>DELETE</th>
<th>Db full name</th> <th>DA Name</th>
<th>Db license number</th> <th>license number</th>
<th>Db state issue</th> <th>state issue</th>
<th>Db employee</th> <th>Trainer #</th>
<th>Owner</th> <th>Date</th>
</tr> </tr>
</thead> </thead>
<tbody is="dmx-repeat" dmx-generator="bs5table" dmx-bind:repeat="DBSC1.data.query" id="tableRepeat1"> <tbody is="dmx-repeat" dmx-generator="bs5table" dmx-bind:repeat="DBSC1.data.query" id="tableRepeat1">
<tr> <tr>
<td> <td dmx-bs-tooltip="'Click will delete without confirmation'" data-bs-trigger="hover" data-bs-placement="left">
<form id="IDAction" action="/api/delRecord" method="post" is="dmx-serverconnect-form" dmx-on:success="DBSC1.load({})"> <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"> <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> </form>
</td> </td>
@ -135,8 +199,10 @@
</tbody> </tbody>
</table> </table>
<div class="row"> <div class="row">
<h3>{{DBSC1.data.query.count()+" Records"}}</h3> <h3>{{DBSC1.data.query.count()+" Training records"}}</h3>
</div> </div>
</div> </div>
<!--
<script src="/PDF/pdfLibSignature.js"></script>
-->
<meta name="ac:route" content="/"> <meta name="ac:route" content="/">

View File

@ -46,7 +46,7 @@
<div class="navbar-nav w-100"> <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="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"> <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="#">Another action</a>
<a class="dropdown-item" href="/signature" internal="true">Signature</a> <a class="dropdown-item" href="/signature" internal="true">Signature</a>
</div> </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> <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> </footer>
<script src="/bootstrap/5/js/bootstrap.bundle.min.js"></script> <script src="/bootstrap/5/js/bootstrap.bundle.min.js"></script>
<script src="/PDF/pdfLibSignature.js"></script>
</body> </body>

View File

@ -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:{}}" --> <!-- 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.&nbsp;</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="container wappler-block pt-3 pb-3">
<div class="modal" id="modal-success" is="dmx-bs5-modal" tabindex="-1" role="dialog"> <div class="modal" id="modal-success" is="dmx-bs5-modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document"> <div class="modal-dialog" role="document">
@ -55,7 +104,10 @@
<label class="form-check-label" for="CKBinput3">Show Section detail</label> <label class="form-check-label" for="CKBinput3">Show Section detail</label>
</div> </div>
</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>
</div> </div>
<dmx-toggle id="toggle1" checked="true"></dmx-toggle> <dmx-toggle id="toggle1" checked="true"></dmx-toggle>
@ -69,7 +121,8 @@
<div class="container border-primary border-2 border"> <div class="container border-primary border-2 border">
<nav class="navbar navbar-expand-lg"> <nav class="navbar navbar-expand-lg">
<span class="navbar-text"> <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 id="collapse1" class="collapse navbar-collapse">
<div class="nav w-100"> <div class="nav w-100">
<a class="nav-item nav-link" href="#">Link</a> <a class="nav-item nav-link" href="#">Link</a>
@ -85,7 +138,7 @@
<div class="row"> <div class="row">
<div class="col-3"> <div class="col-3">
<p class="text-center"><b>Who you are grading</b></p> <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> </select>
</div> </div>
<div class="col"> <div class="col">
@ -96,12 +149,12 @@
<th>License No.</th> <th>License No.</th>
<th>Issue State</th> <th>Issue State</th>
<th>Employee No.</th> <th>Employee No.</th>
<th>Driver Trainer</th> <th>DATE</th>
</tr> </tr>
</thead> </thead>
<tbody is="dmx-repeat" dmx-generator="bs5table" dmx-bind:repeat="data_view1.data" id="tableRepeat4"> <tbody is="dmx-repeat" dmx-generator="bs5table" dmx-bind:repeat="data_view1.data" id="tableRepeat4">
<tr class="text-xl-center"> <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_licenseNumber"></td>
<td dmx-text="db_stateIssue" dmx-class:bg-danger="db_stateIssue.isEmpty()"></td> <td dmx-text="db_stateIssue" dmx-class:bg-danger="db_stateIssue.isEmpty()"></td>
<td dmx-text="db_employeeID"></td> <td dmx-text="db_employeeID"></td>
@ -109,12 +162,15 @@
</tr> </tr>
</tbody> </tbody>
</table> </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> </div>
<div class="row"> <div class="row">
<div class="col"> <div class="col">
<button id="btn2" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#modal1">Print</button> <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>
<div class="col"></div> <div class="col"></div>
<div class="col"></div> <div class="col"></div>
@ -157,7 +213,10 @@
<div class="row" dmx-hide="offcanvas1.CKBinput2.checked"> <div class="row" dmx-hide="offcanvas1.CKBinput2.checked">
<div class="col"> <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> <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"> <thead class="table-primary">
<tr> <tr>
<th scope="col">Tier</th> <th scope="col">Tier</th>
@ -213,11 +272,14 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<header>
<h3 id="scoreHeader" dmx-show="!datastore1.data.hasItems()">No Score shown yet.</h3>
</header>
<div class="container" id="DS"> <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&nbsp;</h3>
</header>
</div>
<table class="table table-striped" dmx-show="datastore1.data.hasItems()">
<thead> <thead>
<tr> <tr>
<th>$id</th> <th>$id</th>
@ -238,70 +300,8 @@
</tbody> </tbody>
</table> </table>
</div> </div>
<script> <script src="https://unpkg.com/pdf-lib/dist/pdf-lib.min.js"></script>
const canvas = document.getElementById('signatureCanvas'); <script src="/PDF/libPDFscripts.js"></script>
const ctx = canvas.getContext('2d'); <!--
let drawing = false; <script src="/PDF/pdfLibSignature.js"></script>
-->
// 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>

View File

@ -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>

View File

@ -29,6 +29,11 @@
</div> </div>
</div> </div>
<button id="btn3" class="btn">Button</button> <button id="btn3" class="btn">Button</button>
<!--
<script src="/PDF/pdfLibSignature.js"></script>
-->
<!--
<script> <script>
const canvas = document.getElementById('signatureCanvas'); const canvas = document.getElementById('signatureCanvas');
const ctx = canvas.getContext('2d'); const ctx = canvas.getContext('2d');
@ -40,7 +45,7 @@
// Function to get the canvas offset // Function to get the canvas offset
function getCanvasOffset() { function getCanvasOffset() {
const rect = canvas.getBoundingClientRect(); const rect = canvas.getBoundingClientRect();
console.log("offsetX:",rect.left, " OffsetY:",rect.top) // console.log("offsetX:",rect.left, " OffsetY:",rect.top)
return { return {
offsetX: rect.left, offsetX: rect.left,
offsetY: rect.top offsetY: rect.top
@ -76,11 +81,11 @@ function getCanvasOffset() {
const { offsetX, offsetY } = getCanvasOffset(); const { offsetX, offsetY } = getCanvasOffset();
let x = e.clientX - offsetX //canvas.offsetLeft; let x = e.clientX - offsetX //canvas.offsetLeft;
let y = e.clientY - offsetY //canvas.offsetTop; 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 x = e.clientX - canvas.offsetLeft;
//let y = e.clientY - canvas.offsetTop; //let y = e.clientY - canvas.offsetTop;
console.log("X:", x, " Y:", y) //console.log("X:", x, " Y:", y)
ctx.lineTo(x, y); ctx.lineTo(x, y);
ctx.stroke(); ctx.stroke();
ctx.beginPath(); ctx.beginPath();
@ -96,6 +101,6 @@ function getCanvasOffset() {
canvas.addEventListener('touchmove', (e) => draw(e.touches[0])); canvas.addEventListener('touchmove', (e) => draw(e.touches[0]));
</script> </script>
-->
<script src="/bootstrap/5/js/bootstrap.bundle.min.js"></script> <script src="/bootstrap/5/js/bootstrap.bundle.min.js"></script>