Neue Unterschriftenfunktion und Lizenzanzeige in der Mobilversion
This commit is contained in:
@@ -386,6 +386,7 @@
|
||||
<Content Include="Scripts\umd\popper-utils.min.js" />
|
||||
<Content Include="Scripts\umd\popper.js" />
|
||||
<Content Include="Scripts\umd\popper.min.js" />
|
||||
<Content Include="Scripts\utils\trimCanvas.js" />
|
||||
<Content Include="Scripts\utils\dateUtils.js" />
|
||||
<Content Include="Scripts\view-scripts\report.js" />
|
||||
<Content Include="Scripts\view-scripts\scheduler.js" />
|
||||
@@ -606,7 +607,7 @@
|
||||
<VisualStudio>
|
||||
<FlavorProperties GUID="{349c5851-65df-11da-9384-00065b846f21}">
|
||||
<WebProjectProperties>
|
||||
<UseIIS>False</UseIIS>
|
||||
<UseIIS>True</UseIIS>
|
||||
<AutoAssignPort>False</AutoAssignPort>
|
||||
<DevelopmentServerPort>8808</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
|
||||
@@ -109,4 +109,30 @@ function hasEmptyRequiredFields(form) {
|
||||
});
|
||||
|
||||
return count > 0;
|
||||
}
|
||||
|
||||
function showAboutPopup() {
|
||||
var text = "SignaturePad:<br/>Copyright (c) 2018 Szymon Nowak<br/><br/>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights<br/>to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:<br/>The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.<br/>THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.";
|
||||
|
||||
$("#popupTitle").text("Copyrights");
|
||||
$("#popupMessage").html(text);
|
||||
|
||||
$("#messagePopup").modal(
|
||||
{
|
||||
backdrop: "static",
|
||||
keyboard: false
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function cloneCanvas(oldCanvas) {
|
||||
var newCanvas = document.createElement("canvas");
|
||||
var context = newCanvas.getContext("2d");
|
||||
|
||||
newCanvas.width = oldCanvas.width;
|
||||
newCanvas.height = oldCanvas.height;
|
||||
|
||||
context.drawImage(oldCanvas, 0, 0);
|
||||
|
||||
return newCanvas;
|
||||
}
|
||||
@@ -1,135 +1,31 @@
|
||||
class Signature {
|
||||
constructor() {
|
||||
this.color = "#000000";
|
||||
this.sign = false;
|
||||
this.beginSign = false;
|
||||
this.lineWidth = 2;
|
||||
this.canvas = document.getElementById("sketch-pad");
|
||||
this.offsetLeft = this.canvas.offsetLeft;
|
||||
this.offsetRight = this.canvas.offsetRight;
|
||||
this.context = this.canvas.getContext("2d");
|
||||
this.context.lineJoin = "round";
|
||||
this.context.lineCap = "round";
|
||||
this.onCanvasMouseDown();
|
||||
this.onCanvasMouseUp();
|
||||
this.onCanvasMouseMove();
|
||||
this.onCanvasTouchStart();
|
||||
this.onCanvasTouchMove();
|
||||
this.onCanvasTouchEnd();
|
||||
this.createSignature();
|
||||
this.clearCanvas();
|
||||
this.resetCanvas();
|
||||
}
|
||||
// Blendet das Popup mit der gespeicherten Unterschrift wieder aus
|
||||
function hideSignature() {
|
||||
$("#signature-img-popup").modal("hide");
|
||||
|
||||
updateMousePosition(mX, mY) {
|
||||
var rect = this.canvas.getBoundingClientRect();
|
||||
var scaleX = this.canvas.width / rect.width;
|
||||
var scaleY = this.canvas.height / rect.height;
|
||||
this.cursorX = (mX - rect.left) * scaleX;
|
||||
this.cursorY = (mY - rect.top) * scaleY;
|
||||
}
|
||||
var url = getResetSignatureImageUrl();
|
||||
|
||||
onCanvasMouseDown() {
|
||||
this.canvas.addEventListener("mousedown", ({ clientX, clientY }) => {
|
||||
$("body").addClass("stop-scrolling");
|
||||
$("body").bind("touchmove",
|
||||
function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
$.get(url);
|
||||
}
|
||||
|
||||
this.sign = true;
|
||||
this.updateMousePosition(clientX, clientY);
|
||||
}, false);
|
||||
}
|
||||
function resizeCanvas() {
|
||||
if($("#sketch-pad").length !== 0) {
|
||||
var rowWidth = $("#canvas-row").innerWidth();
|
||||
var canvasWidth = $("#sketch-pad").innerWidth();
|
||||
|
||||
onCanvasMouseUp() {
|
||||
this.canvas.addEventListener("mouseup", () => {
|
||||
$("body").removeClass("stop-scrolling");
|
||||
$("body").unbind("touchmove");
|
||||
var newWidth = rowWidth;
|
||||
|
||||
this.sign = false;
|
||||
this.beginSign = false;
|
||||
}, false);
|
||||
}
|
||||
|
||||
onCanvasMouseMove() {
|
||||
this.canvas.addEventListener("mousemove", ({ clientX, clientY }) => {
|
||||
if (this.sign) {
|
||||
this.updateMousePosition(clientX, clientY);
|
||||
this.createSignature();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onCanvasTouchStart() {
|
||||
this.canvas.addEventListener("touchstart", (e) => {
|
||||
var touch = e.touches[0];
|
||||
var mouseEvent = new MouseEvent("mousedown", { clientX: touch.clientX, clientY: touch.clientY });
|
||||
|
||||
this.canvas.dispatchEvent(mouseEvent);
|
||||
}, false);
|
||||
}
|
||||
|
||||
onCanvasTouchMove() {
|
||||
this.canvas.addEventListener("touchmove", (e) => {
|
||||
var touch = e.touches[0];
|
||||
var mouseEvent = new MouseEvent("mousemove", { clientX: touch.clientX, clientY: touch.clientY });
|
||||
|
||||
this.canvas.dispatchEvent(mouseEvent);
|
||||
}, false);
|
||||
}
|
||||
|
||||
onCanvasTouchEnd() {
|
||||
this.canvas.addEventListener("touchend", (e) => {
|
||||
var mouseEvent = new MouseEvent("mouseup", {});
|
||||
|
||||
this.canvas.dispatchEvent(mouseEvent);
|
||||
}, false);
|
||||
}
|
||||
|
||||
createSignature() {
|
||||
if (!this.beginSign) {
|
||||
this.context.beginPath();
|
||||
this.context.moveTo(this.cursorX, this.cursorY);
|
||||
this.beginSign = true;
|
||||
} else {
|
||||
this.context.lineTo(this.cursorX, this.cursorY);
|
||||
this.context.strokeStyle = this.color;
|
||||
this.context.lineWidth = this.lineWidth;
|
||||
this.context.stroke();
|
||||
if(newWidth !== canvasWidth) {
|
||||
$("#sketch-pad").prop("width", newWidth);
|
||||
}
|
||||
}
|
||||
|
||||
clearCanvas() {
|
||||
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
|
||||
}
|
||||
|
||||
resetCanvas() {
|
||||
document.getElementById("clear-canvas-btn").addEventListener("click",
|
||||
() => {
|
||||
this.clearCanvas();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", event => {
|
||||
if ($("#sketch-pad").length !== 0) {
|
||||
new Signature();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("DOMContentLoaded", event => {
|
||||
if ($("#report-sketch-pad").length !== 0) {
|
||||
new Signature();
|
||||
}
|
||||
});
|
||||
|
||||
function prepareSigningPopup(serviceRecordOid) {
|
||||
function initializeSignature(selectedServiceRecordOid) {
|
||||
$("#main-container, #checkbox-container").hide();
|
||||
$("#signature-container").addClass("d-block");
|
||||
|
||||
$.get(getSelectedRecordInformationUrlWithOid(), { oid: serviceRecordOid }).done(function(jsonServiceRecord) {
|
||||
if (jsonServiceRecord === "SessionTimeout") {
|
||||
$.get(getSelectedRecordInformationUrlWithOid(), { oid: selectedServiceRecordOid }).done(function(jsonServiceRecord) {
|
||||
if(jsonServiceRecord === "SessionTimeout") {
|
||||
window.location.href = getRedirectLink();
|
||||
return;
|
||||
}
|
||||
@@ -154,79 +50,64 @@ function prepareSigningPopup(serviceRecordOid) {
|
||||
$("#signature-employee").text(record.Employee.FirstName + " " + record.Employee.LastName);
|
||||
$("#signature-date-time").text(datum + " " + startDate + " - " + endDate);
|
||||
|
||||
$("#service-record-oid-holder").val(serviceRecordOid);
|
||||
|
||||
resizeCanvas();
|
||||
|
||||
var canvas = document.getElementById("sketch-pad");
|
||||
|
||||
var signaturePad = new SignaturePad(canvas, { backgroundColor: "rgba(255, 255, 255, 0)" });
|
||||
|
||||
var saveButton = document.getElementById("save-signature-btn");
|
||||
var clearButton = document.getElementById("clear-canvas-btn");
|
||||
var cancelButton = document.getElementById("cancel-signature-btn");
|
||||
|
||||
saveButton.addEventListener("click", function(event) {
|
||||
var url = getSetSelectedSignatureUrl();
|
||||
var date = moment(new Date());
|
||||
|
||||
var clonedCanvas = trimCanvas(cloneCanvas(document.getElementById("sketch-pad")));
|
||||
|
||||
var context = clonedCanvas.getContext("2d");
|
||||
context.globalCompositeOperation = "destination-over";
|
||||
context.fillStyle = "white";
|
||||
context.fillRect(0, 0, clonedCanvas.width, clonedCanvas.height);
|
||||
|
||||
var dataUrl = clonedCanvas.toDataURL("image/png");
|
||||
|
||||
var formattedDate = date.format("DD.MM.YYYY HH:mm:ss");
|
||||
|
||||
showSpinner();
|
||||
|
||||
$.post(url, { blob: dataUrl, timeStamp: formattedDate, serviceRecordOid: selectedServiceRecordOid }).done(function(json) {
|
||||
hideSpinner();
|
||||
|
||||
if(isEmptyOrSpaces(json)) {
|
||||
$("#signature-container").removeClass("d-block");
|
||||
$("#main-container, #checkbox-container").show();
|
||||
showMessagePopupWithCallback("Unterschrift", "Die Unterschrift wurde erfolgreich gespeichert.", function() {
|
||||
showSpinner();
|
||||
location.reload();
|
||||
}, true);
|
||||
} else {
|
||||
showMessagePopup("Fehler", json);
|
||||
signaturePad.clear();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
clearButton.addEventListener("click", function(event) {
|
||||
signaturePad.clear();
|
||||
});
|
||||
|
||||
cancelButton.addEventListener("click", function(event) {
|
||||
showMessagePopupWithCallback("Unterschrift", "Sind Sie sicher, dass Sie die Unterschrift nicht speichern möchten?",
|
||||
function() {
|
||||
$("#signature-container, #checkbox-container").removeClass("d-block");
|
||||
$("#main-container").show();
|
||||
|
||||
signaturePad.clear();
|
||||
|
||||
$.get(getResetSignatureImageUrl());
|
||||
}, false);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function saveSignature() {
|
||||
var url = getSetSelectedSignatureUrl();
|
||||
var date = moment(new Date());
|
||||
|
||||
var canvas = document.getElementById("sketch-pad");
|
||||
var context = canvas.getContext("2d");
|
||||
context.globalCompositeOperation = "destination-over";
|
||||
context.fillStyle = "white";
|
||||
context.fillRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
var dataUrl = document.getElementById("sketch-pad").toDataURL();
|
||||
|
||||
var formattedDate = date.format("DD.MM.YYYY HH:mm:ss");
|
||||
|
||||
var serviceRecordOid = $("#service-record-oid-holder").val();
|
||||
|
||||
showSpinner();
|
||||
|
||||
$.post(url, { blob: dataUrl, timeStamp: formattedDate, serviceRecordOid: serviceRecordOid }).done(function(json) {
|
||||
hideSpinner();
|
||||
|
||||
if (isEmptyOrSpaces(json)) {
|
||||
$("#signature-container").removeClass("d-block");
|
||||
$("#main-container, #checkbox-container").show();
|
||||
showMessagePopupWithCallback("Unterschrift", "Die Unterschrift wurde erfolgreich gespeichert.", function() {
|
||||
showSpinner();
|
||||
location.reload();
|
||||
}, true);
|
||||
} else {
|
||||
showMessagePopup("Fehler", json);
|
||||
new Signature();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function confirmCancellation() {
|
||||
showMessagePopupWithCallback("Unterschrift", "Sind Sie sicher, dass Sie die Unterschrift nicht speichern möchten?",
|
||||
function() {
|
||||
$("#signature-container, #checkbox-container").removeClass("d-block");
|
||||
$("#main-container").show();
|
||||
|
||||
var canvas = document.getElementById("sketch-pad");
|
||||
var context = canvas.getContext("2d");
|
||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||
|
||||
$.get(getResetSignatureImageUrl());
|
||||
}, false);
|
||||
}
|
||||
|
||||
function hideSignature() {
|
||||
$("#signature-img-popup").modal("hide");
|
||||
|
||||
var url = getResetSignatureImageUrl();
|
||||
|
||||
$.get(url);
|
||||
}
|
||||
|
||||
function resizeCanvas() {
|
||||
if($("#sketch-pad").length !== 0) {
|
||||
var rowWidth = $("#canvas-row").innerWidth();
|
||||
var canvasWidth = $("#sketch-pad").innerWidth();
|
||||
|
||||
var newWidth = rowWidth;
|
||||
|
||||
if(newWidth !== canvasWidth) {
|
||||
$("#sketch-pad").prop("width", newWidth);
|
||||
new Signature();
|
||||
}
|
||||
}
|
||||
}
|
||||
86
BeWoPlanerMobil/Scripts/utils/trimCanvas.js
Normal file
86
BeWoPlanerMobil/Scripts/utils/trimCanvas.js
Normal file
@@ -0,0 +1,86 @@
|
||||
function trimCanvas(canvas) {
|
||||
var context = canvas.getContext("2d");
|
||||
|
||||
var imgWidth = canvas.width;
|
||||
var imgHeight = canvas.height;
|
||||
|
||||
var imgData = context.getImageData(0, 0, imgWidth, imgHeight).data;
|
||||
|
||||
// get the corners of the relevant content (everything that's not white)
|
||||
var cropTop = scanY(true, imgWidth, imgHeight, imgData);
|
||||
var cropBottom = scanY(false, imgWidth, imgHeight, imgData);
|
||||
var cropLeft = scanX(true, imgWidth, imgHeight, imgData);
|
||||
var cropRight = scanX(false, imgWidth, imgHeight, imgData);
|
||||
|
||||
// + 1 is needed because this is a difference, there are n + 1 pixels in
|
||||
// between the two numbers inclusive
|
||||
var cropXDiff = (cropRight - cropLeft) + 1;
|
||||
var cropYDiff = (cropBottom - cropTop) + 1;
|
||||
|
||||
// get the relevant data from the calculated coordinates
|
||||
var trimmedData = context.getImageData(cropLeft, cropTop, cropXDiff, cropYDiff);
|
||||
|
||||
// set the trimmed width and height
|
||||
canvas.width = cropXDiff;
|
||||
canvas.height = cropYDiff;
|
||||
// clear the canvas
|
||||
context.clearRect(0, 0, cropXDiff, cropYDiff);
|
||||
// place the trimmed data into the cleared canvas to create
|
||||
// a new, trimmed canvas
|
||||
context.putImageData(trimmedData, 0, 0);
|
||||
return canvas; // for chaining
|
||||
}
|
||||
|
||||
// returns the RGBA values of an x, y coord of imgData
|
||||
function getRGBA(x, y, imgWidth, imgData) {
|
||||
return {
|
||||
red: imgData[(imgWidth * y + x) * 4],
|
||||
green: imgData[(imgWidth * y + x) * 4 + 1],
|
||||
blue: imgData[(imgWidth * y + x) * 4 + 2],
|
||||
alpha: imgData[(imgWidth * y + x) * 4 + 3]
|
||||
}
|
||||
}
|
||||
|
||||
function getAlpha(x, y, imgWidth, imgData) {
|
||||
return getRGBA(x, y, imgWidth, imgData).alpha;
|
||||
}
|
||||
|
||||
// finds the first y coord in imgData that is not white
|
||||
function scanY(fromTop, imgWidth, imgHeight, imgData) {
|
||||
var offset = fromTop ? 1 : -1;
|
||||
var firstCol = fromTop ? 0 : imgHeight - 1;
|
||||
|
||||
// loop through each row
|
||||
for(var y = firstCol; fromTop ? (y < imgHeight) : (y > -1); y += offset) {
|
||||
// loop through each column
|
||||
for(var x = 0; x < imgWidth; x++) {
|
||||
// if not white, return col
|
||||
if(getAlpha(x, y, imgWidth, imgData)) {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the whole image is white already
|
||||
return null
|
||||
}
|
||||
|
||||
// finds the first x coord in imgData that is not white
|
||||
function scanX(fromLeft, imgWidth, imgHeight, imgData) {
|
||||
var offset = fromLeft ? 1 : -1;
|
||||
var firstRow = fromLeft ? 0 : imgWidth - 1;
|
||||
|
||||
// loop through each column
|
||||
for(var x = firstRow; fromLeft ? (x < imgWidth) : (x > -1); x += offset) {
|
||||
// loop through each row
|
||||
for(var y = 0; y < imgHeight; y++) {
|
||||
// if not white, return row
|
||||
if(getAlpha(x, y, imgWidth, imgData)) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the whole image is white already
|
||||
return null;
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
$("#report-info-column").html("Unterschrift für erbrachte Leistungen von " + customer + " im " + month + " " + year);
|
||||
|
||||
resizeCanvas();
|
||||
//resizeCanvas();
|
||||
}
|
||||
|
||||
function saveReportSignature() {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace BeWoPlanerMobil.Util
|
||||
{
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
);
|
||||
}
|
||||
|
||||
resizeCanvas();
|
||||
//resizeCanvas();
|
||||
|
||||
@if (Model != null && Model.IsInEditingMode)
|
||||
{
|
||||
@@ -680,7 +680,7 @@
|
||||
@if(Model.ShowSignature && !serviceRecord.SignatureOid.HasValue)
|
||||
{
|
||||
<div class="col-auto">
|
||||
<button type="button" class="btn btn-primary" onclick="prepareSigningPopup(@serviceRecord.ServiceRecordOid)">
|
||||
<button type="button" class="btn btn-primary" onclick="initializeSignature(@serviceRecord.ServiceRecordOid)">
|
||||
<span class="fas fa-signature"></span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -1467,11 +1467,22 @@
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h4 class="d-inline">Unterschrift</h4>
|
||||
<button type="button" class="btn btn-primary float-right" onclick="confirmCancellation()">
|
||||
<button type="button" class="btn btn-primary float-right" id="cancel-signature-btn">
|
||||
<span class="fas fa-times-circle"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@if(Html.IsInDebugMode())
|
||||
{
|
||||
<div class="row">
|
||||
<div class="col text-secondary">
|
||||
Debuginfo:
|
||||
</div>
|
||||
<div class="col" id="debug-info">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="row">
|
||||
<div class="col text-secondary">
|
||||
Hilfeplan:
|
||||
@@ -1515,12 +1526,12 @@
|
||||
|
||||
<div class="row mt-3" id="canvas-row">
|
||||
<div class="canvas-container" id="canvas-container">
|
||||
<canvas id="sketch-pad" width="500" height="200" class="bg-white rounded" style="border: 1px solid #343A40;"></canvas>
|
||||
<canvas id="sketch-pad" width="500" height="200" class="bg-white" style="border: 1px solid #343A40;"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<button type="button" class="btn btn-primary float-right" onclick="saveSignature()">Speichern</button>
|
||||
<button type="button" class="btn btn-primary float-right" id="save-signature-btn">Speichern</button>
|
||||
<button type="button" class="btn btn-secondary float-right mr-3" id="clear-canvas-btn">Neu</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -33,6 +33,8 @@
|
||||
<script src="~/Scripts/view-scripts/scheduler.js"></script>
|
||||
<script src="~/Scripts/utils/dateUtils.js"></script>
|
||||
<script src="~/Scripts/view-scripts/report.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/signature_pad@2.3.2/dist/signature_pad.min.js"></script>
|
||||
<script src="~/Scripts/utils/trimCanvas.js"></script>
|
||||
|
||||
<script>
|
||||
$(document).ready(function() {
|
||||
@@ -166,6 +168,13 @@
|
||||
</button>
|
||||
}
|
||||
</li>
|
||||
|
||||
<li class="nav-item">
|
||||
<button class="btn btn-link text-light no-underline" onclick="showAboutPopup()">
|
||||
<i class="fas fa-balance-scale text-primary"></i>
|
||||
Über
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user