Portal updates and general bug fixes (#2318)
[openemr.git] / portal / sign / assets / signer_api.js
blob6adc07e668d51ddb36abfe62516599bc988929e6
1 /**
2  * @package   OpenEMR
3  * @link      http://www.open-emr.org
4  * @author    Jerry Padgett <sjpadgett@gmail.com>
5  * @copyright Copyright (c) 2016-2019 Jerry Padgett <sjpadgett@gmail.com>
6  * @license   https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
7  */
9 function getSignature(othis) {
10     let libUrl, signer, signerType = "";
11     let isLink = $(othis).attr('src').indexOf('signhere');
13     if ($(othis).attr('src') != signhere && isLink == -1) {
14         $(othis).attr('src', signhere);
15         return;
16     }
17     try {
18         if (webRoot !== undefined && webRoot !== null) {
19             libUrl = webRoot + '/portal/';
20         }
21     } catch (e) {
22         libUrl = "./";
23     }
24     if ($(othis).attr('type') == 'admin-signature') {
25         signer = cuser;
26         signerType = "admin-signature";
27     } else {
28         signer = ptName;
29         signerType = "patient-signature";
30     }
31     let params = {
32         pid: cpid,
33         user: cuser,
34         signer: signer,
35         type: signerType
36     };
38     let url = libUrl + "sign/lib/show-signature.php";
39     fetch(url, {
40         method: 'POST',
41         body: JSON.stringify(params),
42         headers: {
43             'Accept': 'application/json, text/plain, */*',
44             'Content-Type': 'application/json'
45         }
46     }).then(signature => signature.json())
47       .then(signature => {
48         placeImg(signature, othis)
49     }).catch(error => alert(error));
52 function placeImg(responseData, el) {
53     if (responseData == "error") {
54         $(el).attr('src', "");
55         alert('Error Patient and or User Id missing');
56         return;
57     }
58     else if (responseData == "insert error") {
59         $(el).attr('src', "");
60         alert('Error adding signature');
61         return;
62     }
63     else if (responseData == "waiting" && $(el).attr('type') == 'patient-signature') {
64         $(el).attr('src', "");
65         alert('Signature not on file. Please sign');
66         $("#isAdmin").attr('checked', false);
67         $("#openSignModal").modal("show");
68         return;
69     }
70     else if (responseData == "waiting" && $(el).attr('type') == 'admin-signature') {
71         $(el).attr('src', "");
72         alert('Signature not on file. Please sign');
73         $("#isAdmin").attr('checked', true);
74         $("#openSignModal").modal("show");
75         return;
76     }
77     let i = new Image();
78     i.onload = function () {
79         $(el).attr('src', i.src); // display image
80     };
81     i.src = isDataURL(responseData) ? responseData : 'data:image/png;base64,' + responseData; // load image
84 function signDoc(signImage) {
85     let libUrl, signer, signerType = "";
86     let pid = 0;
88     try {
89         if (webRoot !== undefined && webRoot !== null)
90             libUrl = webRoot + '/portal/';
91     } catch (e) {
92         libUrl = "./";
93     }
94     if ($("#isAdmin").is(':checked') == false) {
95         pid = cpid;
96         signer = ptName;
97         signerType = "patient-signature";
98     } else {
99         pid = 0;
100         signer = cuser;
101         signerType = "admin-signature";
102     }
103     let data = {
104         pid: pid,
105         user: cuser,
106         signer: signer,
107         type: signerType,
108         output: signImage
109     };
111     let url = libUrl + "sign/lib/save-signature.php";
112     fetch(url, {
113         method: 'POST',
114         body: JSON.stringify(data),
115         headers: {
116             'Content-Type': 'application/json',
117             'Connection': 'close'
118         }
119     }).then(response => response.text())
120       .then(
121         $("#loading").toggle(),
122         $("#openSignModal").modal("hide")
123       ).catch(error => alert(error));
125     $("#loading").toggle();
128 function isDataURL(dataUrl) {
129     return !!dataUrl.match(isDataURL.regex);
131 isDataURL.regex = /^\s*data:([a-z]+\/[a-z]+(;[a-z\-]+\=[a-z\-]+)?)?(;base64)?,[a-z0-9\!\$\&\'\,\(\)\*\+\,\;\=\-\.\_\~\:\@\/\?\%\s]*\s*$/i;
133 $(function () {
134     let isAdmin = 0;
135     let url = top.webroot_url ? top.webroot_url : webRoot;
136     url += "/portal/sign/assets/signer_modal.tpl.php?isAdmin=" + encodeURIComponent(isAdmin);
137     fetch(url)
138         .then(jsonTemplate => jsonTemplate.json())
139         .then(jsonTemplate => {
140             $("body").append(jsonTemplate);
141         })
142         .then(function () {
143             initSignerApi();
144         })
145         .catch((error) => alert(error));
148 function initSignerApi() {
149     $(function () {
150         const canvasOptions = {
151             minWidth: 1,
152             maxWidth: 2,
153             minDistance: 4,
154             throttle: 0,
155             velocityFilterWeight: .2,
156             penColor: 'rgb(0, 0, 255)',
157         };
158         var wrapper = document.getElementById("openSignModal");
159         var placeSignature = wrapper.querySelector("[data-action=place]");
160         var showSignature = wrapper.querySelector("[data-action=show]");
161         var clearButton = wrapper.querySelector("[data-action=clear]");
162         var saveSignatureButton = wrapper.querySelector("[data-action=save-png]");
163         var canvas = wrapper.querySelector("canvas");
164         var signaturePad;
165         var isAdmin = false;
167         $("#openSignModal").on('show.bs.modal', function (e) {
168             let triggeredBy = $(e.relatedTarget);
169             let type = triggeredBy.prop('type');
170             if (type === "admin-signature") {
171                 $("#isAdmin").prop('checked', true);
172                 placeSignature.setAttribute("type", type);
173                 isAdmin = true;
174             }
175             $(this).data('bs.modal').options.backdrop = 'static';
176             $('html').css({
177                 'overflow': 'hidden'
178             });
179             $(this).css({
180                 'padding-right': '0px'
181             });
182             $('body').bind('selectstart', function () {
183                 return false;
184             });
185             $(this).modal('handleUpdate');
186         }).on('shown.bs.modal', function (e) {
187             signaturePad = new SignaturePad(canvas, canvasOptions);
188             resizeCanvas();
189         }).on('hide.bs.modal', function () {
190             $('html').css({
191                 'overflow': 'inherit'
192             });
193             $('body').unbind('selectstart');
194         });
196         clearButton.addEventListener("click", function (event) {
197             signaturePad.clear();
198         });
200         saveSignatureButton.addEventListener("click", function (event) {
201             if (signaturePad.isEmpty()) {
202                 alert("Please provide a signature first.");
203             } else {
204                 let dataURL = signaturePad.toDataURL();
205                 signDoc(encodeURIComponent(dataURL));
206             }
207         });
209         placeSignature.addEventListener("click", function (event) {
210             let thisElement = $(this);
211             getSignature(thisElement);
212         });
214         showSignature.addEventListener("click", function (event) {
215             let thisElement = $(this);
216             let showElement = document.getElementById('signatureModal');
217             getSignature(showElement);
218         });
220         function resizeCanvas() {
221             let ratio = Math.max(window.devicePixelRatio || 1, 1);
222             canvas.width = canvas.offsetWidth * ratio;
223             canvas.height = canvas.offsetHeight * ratio;
224             canvas.getContext("2d").scale(ratio, ratio);
225         }
227         function download(dataURL, filename) {
228             let blob = dataURLToBlob(dataURL);
229             let url = window.URL.createObjectURL(blob);
230             let a = document.createElement("a");
231             a.style = "display: none";
232             a.href = url;
233             a.download = filename;
235             document.body.appendChild(a);
236             a.click();
237             window.URL.revokeObjectURL(url);
238         }
240         function dataURLToBlob(dataURL) {
241             // Code taken from https://github.com/ebidel/filer.js
242             let parts = dataURL.split(';base64,');
243             let contentType = parts[0].split(":")[1];
244             let raw = window.atob(parts[1]);
245             let rawLength = raw.length;
246             let uInt8Array = new Uint8Array(rawLength);
248             for (var i = 0; i < rawLength; ++i) {
249                 uInt8Array[i] = raw.charCodeAt(i);
250             }
252             return new Blob([uInt8Array], {type: contentType});
253         }
255         function drawSignatureLine() {
256             let context = canvas.getContext('2d');
257             context.lineWidth = .4;
258             context.strokeStyle = '#333';
259             context.beginPath();
260             context.moveTo(0, 200);
261             context.lineTo(900, 200);
262             context.stroke();
263         }
265         // resize  event and initial resize
266         window.onresize = resizeCanvas;
267         resizeCanvas();
268     });
271 const signhere = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFQAAABUCAYAAAAcaxDBAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAphJREFUeJzt2j1oE2Ecx/FvMdW+biK+1EVxEnESm0Xcxero6Gqto+iqKHQTcXUQHBTqUKiL0KUWFAQp6KQdRKPopA2+VjHn8L/jee54ckm0zeXq7wOBp/dcycOXa3N5EhAREREREREREREREREREZH1sqnoBfSIHcBpoAp8AOqFrqaktgH9wBEsYBQ/vgHHC1xXKe0EXgDzwGcs5BLwOB6vAhOFra5kkpiR95gHBoEKMIOLeqygNZaGH/M98DMe38NiQjrqJ2C0+8ssBz/ma2APcBIXdYZ01Fp8/Gi3F1oGoZiJUNQq9icfAfu7utIS2I6LWSMdM+FHfYB71Z/r0hpLZRgXtI5dfSEncFEjYCH+XcmYBBq4UHVgvMm5E6RfqPTGJ8OPeQNYJD/qGe/8a11aY2lM4q7KJM4I8BAX9bB3vmLmCMVMjGD/HyNgBYuqmDnyYiaGcVfqFxSzqbO0jgl2X/rSO1cxA/4mZg141OL8/1K7MXeRjrkXGFj31ZXMv8SUjCk6j/kGxQzqJOYyiplLMddQFRdzCehrcl42ZmiXSYD7tL5/HEMx23IQi/Qb2+wIRVXMDtzFQt2Jf75IOqofM7szLxn7sCuzARzwjvtRk512xWzDTSzWbOb4AG73SDHbtBu3k34oPjYKXMC+OpPEfIVituU6FqwBnAMuAx9JX5VT9MD78mb3cJ0YBLZkjv0CvsbjIWBzZn4V+B6PK9imry/5fwiwFQs2FHjuZWAauB0/54ZwhfR9YYS9GiduBeanvfnxwPyKN38pMP8MOEUPfohWaX1K4ca88RPgKvZ5eVTMcvKtRdCFwLHn3ngOeJuZX/TG77BIvh/e+Dy2U/QU+1KXiIiIiIiIiIiIiIiIiIiIiIhsfH8AekL6s5feEc0AAAAASUVORK5CYII=";