4 * This is the place to put JavaScript functions that are needed to support
5 * options.inc.php. Include this in the <head> section of relevant modules.
6 * It's a .php module so that translation can be supported.
9 * @link https://www.open-emr.org
10 * @author Rod Roark <rod@sunsetsystems.com>
11 * @author Brady Miller <brady.g.miller@gmail.com>
12 * @author Jerry Padgett <sjpadgett@gmail.com>
13 * @copyright Copyright (c) 2014-2021 Rod Roark <rod@sunsetsystems.com>
14 * @copyright Copyright (c) 2018 Brady Miller <brady.g.miller@gmail.com>
15 * @copyright Copyright (c) 2021 Jerry Padgett <sjpadgett@gmail.com>
16 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
19 use OpenEMR\Common\Csrf\CsrfUtils
;
24 // JavaScript support for date types when the A or B edit option is used.
25 // Called to recompute displayed age dynamically when the corresponding date is
26 // changed. Must generate the same age formats as the oeFormatAge() function.
28 function updateAgeString(fieldid
, asof
, format
, description
) {
29 var datefld
= document
.getElementById('form_' + fieldid
);
32 var date1
= new Date(datefld
.value
);
33 var date2
= asof ?
new Date(asof
) : new Date();
36 var msecs
= date2
.getTime() - date1
.getTime();
37 var days
= Math
.round(msecs
/ (24 * 60 * 60 * 1000));
38 var weeks
= Math
.floor(days
/ 7);
40 if (description
== '') description
= <?php
echo xlj('Gest age') ?
>;
41 age
= description +
' ' +
42 weeks +
(weeks
== 1 ?
' ' +
<?php
echo xlj('week') ?
> : ' ' +
<?php
echo xlj('weeks') ?
>) +
' ' +
43 days +
(days
== 1 ?
' ' +
<?php
echo xlj('day') ?
> : ' ' +
<?php
echo xlj('days') ?
>);
47 var dayDiff
= date2
.getDate() - date1
.getDate();
48 var monthDiff
= date2
.getMonth() - date1
.getMonth();
49 var yearDiff
= date2
.getFullYear() - date1
.getFullYear();
50 var ageInMonths
= yearDiff
* 12 + monthDiff
;
51 if (dayDiff
< 0) --ageInMonths
;
52 if (format
== 1 ||
(format
== 0 && ageInMonths
>= 24)) {
54 if (monthDiff
< 0 ||
(monthDiff
== 0 && dayDiff
< 0)) --age
;
58 age
= '' + ageInMonths
;
60 age
= age +
' ' +
(ageInMonths
== 1 ?
<?php
echo xlj('month') ?
> : <?php
echo xlj('months') ?
>);
63 if (description
== '') description
= <?php
echo xlj('Age') ?
>;
64 if (age
!= '') age
= description +
' ' + age
;
66 document
.getElementById('span_' + fieldid
).innerHTML
= age
;
69 // Function to support datatype 46 - single-selection list with comment support
70 function processCommentField(fieldId
) {
71 if (document
.getElementById("form_" + fieldId
) != null) {
72 if (document
.getElementById("form_" + fieldId
).options
[document
.getElementById("form_" + fieldId
).selectedIndex
].value
.match(/^comment_
/)) {
73 if (document
.getElementById("form_text_" + fieldId
).style
.display
== "none") {
74 document
.getElementById("form_text_" + fieldId
).style
.display
= "inline-block";
77 document
.getElementById("form_text_" + fieldId
).value
= "";
78 document
.getElementById("form_text_" + fieldId
).style
.display
= "none";
83 function myHideOrShow(elem
, hide
) {
84 // elem is a td or bootstrap column div.
85 for (var inp
= elem
.firstChild
; inp
; inp
= inp
.nextSibling
) {
87 inp
.style
.display
= hide ?
'none' : '';
89 // This must be a text node with no tag, so hide/show the parent elem instead.
90 elem
.style
.display
= hide ?
'none' : '';
95 // Function to show or hide form fields (and their labels) depending on "skip conditions"
96 // defined in the layout.
98 var cskerror
= false; // to avoid repeating error messages
99 function checkSkipConditions() {
100 var myerror
= cskerror
;
102 var prevcond
= false;
103 for (var i
= 0; i
< skipArray
.length
; ++i
) {
104 var target
= skipArray
[i
].target
;
105 var id
= skipArray
[i
].id
;
106 var itemid
= skipArray
[i
].itemid
;
107 var operator
= skipArray
[i
].operator
;
108 var value
= skipArray
[i
].value
;
109 var is_radio
= false;
110 var action
= skipArray
[i
].action
;
113 if (itemid
) tofind +
= '[' + itemid +
']';
114 // Some different source IDs are possible depending on the data type.
115 var srcelem
= document
.getElementById('check_' + tofind
);
116 if (srcelem
== null) srcelem
= document
.getElementById('radio_' + tofind
);
117 if (srcelem
== null) srcelem
= document
.getElementById('form_' + tofind
) ;
118 if (srcelem
== null) srcelem
= document
.getElementById('text_' + tofind
);
120 if (srcelem
== null) {
121 // This caters to radio buttons which we treat like droplists.
122 var tmp
= document
.getElementById('form_' + tofind +
'[' + value +
']');
125 if (operator
== 'eq') operator
= 'se';
126 if (operator
== 'ne') operator
= 'ns';
131 if (srcelem
== null) {
132 if (!cskerror
) alert(<?php
echo xlj('Cannot find a skip source field for'); ?
> +
' "' + tofind +
'"');
137 var condition
= false;
138 var is_multiple
= false;
141 for (var k
= 0; k
< document
.getElementsByName('form_' + tofind
).length
; k++
){
142 if (document
.getElementsByName('form_' + tofind
)[k
].checked
){
143 elem_val
= document
.getElementsByName('form_' + tofind
)[k
].value
;
146 }else if( typeof srcelem
.options
!=="undefined" && srcelem
.type
== 'select-one' ){
147 elem_val
=srcelem
.options
[srcelem
.selectedIndex
].value
;
149 }else if( srcelem
.type
== 'select-multiple' ) {
150 elem_val
= new Array();
152 for (var k
= 0; k
< srcelem
.length
; k++
) {
153 if (srcelem
.options
[k
].selected
) {
154 if( elem_val
.indexOf(srcelem
.options
[k
].value
)<0) {
155 elem_val
.push(srcelem
.options
[k
].value
);
160 elem_val
=srcelem
.value
;
162 if(elem_val
== null) {
163 elem_val
= srcelem
.getAttribute("data-value");
164 if( elem_val
!== null && elem_val
.indexOf("|") !== -1 ) {
165 elem_val
= elem_val
.split("|");
169 if(elem_val
== null) elem_val
= srcelem
.innerText
;
171 //this is a feature fix for the multiple select list option
172 //collect all the multiselect control values:
176 condition
= (-1 !== elem_val
.indexOf(value
));break;
178 condition
= (-1 == elem_val
.indexOf(value
)); break;
180 condition
= srcelem
.checked
; break; // doesn't make sense?
182 condition
= !srcelem
.checked
; break;
186 if (operator
== 'eq') condition
= elem_val
== value
; else
187 if (operator
== 'ne') condition
= elem_val
!= value
; else
188 if (operator
== 'se') condition
= srcelem
.checked
; else
189 if (operator
== 'ns') condition
= !srcelem
.checked
;
192 // Logic to accumulate multiple conditions for the same target.
193 // alert('target = ' + target + ' prevandor = ' + prevandor + ' prevcond = ' + prevcond); // debugging
194 if (prevandor
== 'and') condition
= condition
&& prevcond
; else
195 if (prevandor
== 'or' ) condition
= condition || prevcond
;
196 prevandor
= skipArray
[i
].andor
;
197 prevcond
= condition
;
199 if (j
< skipArray
.length
&& skipArray
[j
].target
== target
) continue;
201 // At this point condition indicates the target should be hidden or have its value set.
203 var skip
= condition
;
205 if (action
.substring(0, 5) == 'value') {
208 else if (action
.substring(0, 5) == 'hsval') {
209 // This action means hide if true, set value if false.
211 action
= 'value=' + action
.substring(6);
217 var trgelem1
= document
.getElementById('label_id_' + target
);
218 var trgelem2
= document
.getElementById('value_id_text_' + target
);
219 if (trgelem2
== null) {
220 trgelem2
= document
.getElementById('value_id_' + target
);
222 if (trgelem1
== null && trgelem2
== null) {
223 var trgelem1
= document
.getElementById('label_' + target
);
224 var trgelem2
= document
.getElementById('text_' + target
);
225 if(trgelem2
== null){
226 trgelem2
= document
.getElementById('form_' + target
);
228 if (trgelem1
== null && trgelem2
== null) {
229 if (!cskerror
) alert(<?php
echo xlj('Cannot find a skip target field for'); ?
> +
' "' + target +
'"');
234 if (trgelem1
) myHideOrShow(trgelem1
, skip
);
235 if (trgelem2
) myHideOrShow(trgelem2
, skip
);
238 if (action
.substring(0, 5) == 'value') {
239 var trgelem
= document
.forms
[0]['form_' + target
];
240 if (trgelem
== null) {
241 if (!cskerror
) alert('Cannot find a value target field for "' + target +
'"');
245 var action_value
= action
.substring(6);
246 if (trgelem
.type
== 'checkbox') {
247 trgelem
.checked
= !(action_value
== '0' || action_value
== '');
250 trgelem
.value
= action_value
;
251 // Handle billing code descriptions.
252 var valelem
= document
.forms
[0]['form_' + target +
'__desc'];
253 if (skipArray
[i
].valdesc
&& valelem
) {
254 // alert('Setting ' + valelem.name + ' value to: ' + skipArray[i].valdesc); // debugging
255 valelem
.value
= skipArray
[i
].valdesc
;
260 // If any errors, all show in the first pass and none in subsequent passes.
261 cskerror
= cskerror || myerror
;
264 ///////////////////////////////////////////////////////////////////////
265 // Image canvas support starts here.
266 ///////////////////////////////////////////////////////////////////////
268 var lbfCanvases
= {}; // contains the LC instance for each canvas.
270 // Initialize the drawing widget.
271 // canid is the id of the div that will contain the canvas, and the image
272 // element used for initialization should have an id of canid + '_img'.
274 function lbfCanvasSetup(canid
, canWidth
, canHeight
) {
276 "stroke" : <?php
echo xlj('stroke'); ?
>,
277 "fill" : <?php
echo xlj('fill'); ?
>,
278 "bg" : <?php
echo xlj('bg{{image canvas label}}'); ?
>,
279 "Clear" : <?php
echo xlj('Clear'); ?
>,
280 // The following are tooltip translations, however they do not work due to
281 // a bug in LiterallyCanvas 0.4.13. We'll leave them here pending a fix.
282 "Eraser" : <?php
echo xlj('Eraser'); ?
>,
283 "Pencil" : <?php
echo xlj('Pencil'); ?
>,
284 "Line" : <?php
echo xlj('Line'); ?
>,
285 "Rectangle" : <?php
echo xlj('Rectangle'); ?
>,
286 "Ellipse" : <?php
echo xlj('Ellipse'); ?
>,
287 "Text" : <?php
echo xlj('Text'); ?
>,
288 "Polygon" : <?php
echo xlj('Polygon'); ?
>,
289 "Pan" : <?php
echo xlj('Pan'); ?
>,
290 "Eyedropper": <?php
echo xlj('Eyedropper'); ?
>,
291 "Undo" : <?php
echo xlj('Undo'); ?
>,
292 "Redo" : <?php
echo xlj('Redo'); ?
>,
293 "Zoom out" : <?php
echo xlj('Zoom out'); ?
>,
294 "Zoom in" : <?php
echo xlj('Zoom in'); ?
>,
296 var tmpImage
= document
.getElementById(canid +
'_img');
297 var shape
= LC
.createShape('Image', {x
: 0, y
: 0, image
: tmpImage
});
298 var lc
= LC
.init(document
.getElementById(canid
), {
299 imageSize
: {width
: canWidth
, height
: canHeight
},
300 strokeWidths
: [1, 2, 3, 5, 8, 12],
301 defaultStrokeWidth
: 2,
302 backgroundShapes
: [shape
],
303 imageURLPrefix
: '<?php echo $GLOBALS['assets_static_relative
'] ?>/literallycanvas/img'
305 if (canHeight
> 261) {
306 // TBD: Do something to make the widget bigger?
307 // Look for some help with this in the next LC release.
309 // lc.saveShape(shape); // alternative to the above backgroundShapes
310 lbfCanvases
[canid
] = lc
;
313 // This returns a standard "Data URL" string representing the image data.
314 // It will typically be a few kilobytes. Here's a truncated example:
315 // data:image/png;base64,iVBORw0K ...
317 function lbfCanvasGetData(canid
) {
318 return lbfCanvases
[canid
].getImage().toDataURL();
321 // set signture to hidden element for this img
322 function lbfSetSignature(el
) {
323 let imgel
= el +
"_img";
324 let sign
= $
("#"+ imgel
).attr('src');
325 $
("#"+ el
).val(sign
);
328 // This is invoked when a field with edit option M is changed.
329 // Its purpose is to make the corresponding change to the member fields (edit option m).
331 function checkGroupMembers(elem
, groupnumber
) {
332 var i
= elem
.id
.indexOf('[');
334 alert(<?php
echo xlj('Field not suitable for edit option M') ?
> +
': ' + elem
.name
);
337 var suffix
= elem
.id
.substring(i
);
338 var members
= document
.getElementsByClassName('lbf_memgroup_' + groupnumber
);
339 if (members
.length
== 0) {
340 alert(<?php
echo xlj('No member fields found for') ?
> +
': ' + elem
.name
);
343 for (var i
= 0; i
< members
.length
; ++i
) {
344 if (members
[i
].id
.indexOf(suffix
) > 1) {
345 members
[i
].checked
= true;
350 // Support for patient finder. References to the input elements.
351 var elem_patient_name
;
354 // This is for callback by the find-patient popup.
355 function setpatient(pid
, lname
, fname
, dob
) {
356 elem_patient_name
.value
= lname +
', ' + fname +
' (' + pid +
')';
357 elem_patient_id
.value
= pid
;
360 // This invokes the find-patient popup.
361 function sel_patient(ename
, epid
) {
362 elem_patient_name
= ename
;
363 elem_patient_id
= epid
;
364 dlgopen('<?php echo $GLOBALS['webroot
']; ?>/interface/main/calendar/find_patient_popup.php', '_blank', 500, 400);
367 // This is a wrapper for specialty forms dialog
368 // ajax mode allows calling script to be in the same scope as options.inc.php.
369 function specialtyFormDialog(mode
= 'iframe', size
= 'modal-sm', formHandler
= 'name_history') {
370 event
.preventDefault();
371 let url
= '<?php echo $GLOBALS['webroot
']; ?>/library/specialty_forms.php?';
372 url +
= "form_handler=" +
encodeURIComponent(formHandler
);
373 url +
= "&csrf_token_form=" +
<?php
echo js_escape(CsrfUtils
::collectCsrfToken()); ?
>;
374 let title
= xl("Add to History");
375 dlgopen('', '', size
, 500, '', '', {