Fully responsive globals.php with vertical menu (#2460)
[openemr.git] / library / options.js.php
blob89d69e208fe8b5cb6249e281c802b59838e16214
1 <?php
2 /**
3 * This is the place to put JavaScript functions that are needed to support
4 * options.inc.php. Include this in the <head> section of relevant modules.
5 * It's a .php module so that translation can be supported.
7 * @package OpenEMR
8 * @link https://www.open-emr.org
9 * @author Rod Roark <rod@sunsetsystems.com>
10 * @author Brady Miller <brady.g.miller@gmail.com>
11 * @copyright Copyright (c) 2014-2019 Rod Roark <rod@sunsetsystems.com>
12 * @copyright Copyright (c) 2018 Brady Miller <brady.g.miller@gmail.com>
13 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
16 <script type="text/javascript">
18 // JavaScript support for date types when the A or B edit option is used.
19 // Called to recompute displayed age dynamically when the corresponding date is
20 // changed. Must generate the same age formats as the oeFormatAge() function.
22 function updateAgeString(fieldid, asof, format, description) {
23 var datefld = document.getElementById('form_' + fieldid);
24 var f = datefld.form;
25 var age = '';
26 var date1 = new Date(datefld.value);
27 var date2 = asof ? new Date(asof) : new Date();
28 if (format == 3) {
29 // Gestational age.
30 var msecs = date2.getTime() - date1.getTime();
31 var days = Math.round(msecs / (24 * 60 * 60 * 1000));
32 var weeks = Math.floor(days / 7);
33 days = days % 7;
34 if (description == '') description = <?php echo xlj('Gest age') ?>;
35 age = description + ' ' +
36 weeks + (weeks == 1 ? ' ' + <?php echo xlj('week') ?> : ' ' + <?php echo xlj('weeks') ?>) + ' ' +
37 days + (days == 1 ? ' ' + <?php echo xlj('day') ?> : ' ' + <?php echo xlj('days') ?>);
39 else {
40 // Years or months.
41 var dayDiff = date2.getDate() - date1.getDate();
42 var monthDiff = date2.getMonth() - date1.getMonth();
43 var yearDiff = date2.getFullYear() - date1.getFullYear();
44 var ageInMonths = yearDiff * 12 + monthDiff;
45 if (dayDiff < 0) --ageInMonths;
46 if (format == 1 || (format == 0 && ageInMonths >= 24)) {
47 age = yearDiff;
48 if (monthDiff < 0 || (monthDiff == 0 && dayDiff < 0)) --age;
49 age = '' + age;
51 else {
52 age = '' + ageInMonths;
53 if (format == 0) {
54 age = age + ' ' + (ageInMonths == 1 ? <?php echo xlj('month') ?> : <?php echo xlj('months') ?>);
57 if (description == '') description = <?php echo xlj('Age') ?>;
58 if (age != '') age = description + ' ' + age;
60 document.getElementById('span_' + fieldid).innerHTML = age;
63 // Function to show or hide form fields (and their labels) depending on "skip conditions"
64 // defined in the layout.
66 var cskerror = false; // to avoid repeating error messages
67 function checkSkipConditions() {
68 var myerror = cskerror;
69 var prevandor = '';
70 var prevcond = false;
71 for (var i = 0; i < skipArray.length; ++i) {
72 var target = skipArray[i].target;
73 var id = skipArray[i].id;
74 var itemid = skipArray[i].itemid;
75 var operator = skipArray[i].operator;
76 var value = skipArray[i].value;
77 var is_radio = false;
78 var action = skipArray[i].action;
79 var tofind = id;
81 if (itemid) tofind += '[' + itemid + ']';
82 // Some different source IDs are possible depending on the data type.
83 var srcelem = document.getElementById('check_' + tofind);
84 var radio_id='form_' + tofind + '[' + value + ']';
85 if(typeof document.getElementById(radio_id)!=="undefined"){
86 srcelem = document.getElementById(radio_id);
87 if(srcelem != null){
88 is_radio = true;
91 if (srcelem == null) srcelem = document.getElementById('radio_' + tofind);
92 if (srcelem == null) srcelem = document.getElementById('form_' + tofind) ;
93 if (srcelem == null) srcelem = document.getElementById('text_' + tofind);
95 if (srcelem == null) {
96 // This caters to radio buttons which we treat like droplists.
97 var tmp = document.getElementById('form_' + tofind + '[' + value + ']');
98 if (tmp != null) {
99 srcelem = tmp;
100 if (operator == 'eq') operator = 'se';
101 if (operator == 'ne') operator = 'ns';
105 if (srcelem == null) {
106 if (!cskerror) alert(<?php echo xlj('Cannot find a skip source field for'); ?> + ' "' + tofind + '"');
107 myerror = true;
108 continue;
111 var condition = false;
112 var is_multiple = false;
113 var elem_val;
114 if ( is_radio){
115 for (var k = 0; k < document.getElementsByName('form_' + tofind).length; k++){
116 if (document.getElementsByName('form_' + tofind)[k].checked){
117 elem_val= document.getElementsByName('form_' + tofind)[k].value;
120 }else if( typeof srcelem.options!=="undefined" && srcelem.type == 'select-one' ){
121 elem_val=srcelem.options[srcelem.selectedIndex].value;
123 }else if( srcelem.type == 'select-multiple' ) {
124 elem_val = new Array();
125 is_multiple = true;
126 for (var k = 0; k < srcelem.length; k++) {
127 if (srcelem.options[k].selected) {
128 if( elem_val.indexOf(srcelem.options[k].value)<0) {
129 elem_val.push(srcelem.options[k].value);
133 } else {
134 elem_val=srcelem.value;
136 if(elem_val == null) {
137 elem_val = srcelem.getAttribute("data-value");
138 if( elem_val !== null && elem_val.indexOf("|") !== -1 ) {
139 elem_val = elem_val.split("|");
140 is_multiple = true;
143 if(elem_val == null) elem_val = srcelem.innerText;
145 //this is a feature fix for the multiple select list option
146 //collect all the multiselect control values:
147 if( is_multiple ) {
148 switch(operator) {
149 case 'eq':
150 condition = (-1 !== elem_val.indexOf(value));break;
151 case 'ne':
152 condition = (-1 == elem_val.indexOf(value)); break;
153 case 'se':
154 condition = srcelem.checked ; break; // doesn't make sense?
155 case 'ns':
156 condition = !srcelem.checked; break;
159 } else {
160 if (operator == 'eq') condition = elem_val == value; else
161 if (operator == 'ne') condition = elem_val != value; else
162 if (operator == 'se') condition = srcelem.checked ; else
163 if (operator == 'ns') condition = !srcelem.checked;
166 // Logic to accumulate multiple conditions for the same target.
167 // alert('target = ' + target + ' prevandor = ' + prevandor + ' prevcond = ' + prevcond); // debugging
168 if (prevandor == 'and') condition = condition && prevcond; else
169 if (prevandor == 'or' ) condition = condition || prevcond;
170 prevandor = skipArray[i].andor;
171 prevcond = condition;
172 var j = i + 1;
173 if (j < skipArray.length && skipArray[j].target == target) continue;
175 // At this point condition indicates the target should be hidden or have its value set.
177 if (action == 'skip') {
178 var trgelem1 = document.getElementById('label_id_' + target);
179 var trgelem2 = document.getElementById('value_id_text_' + target);
180 if (trgelem2 == null) {
181 trgelem2 = document.getElementById('value_id_' + target);
184 if (trgelem1 == null && trgelem2 == null) {
185 var trgelem1 = document.getElementById('label_' + target);
186 var trgelem2 = document.getElementById('text_' + target);
187 if(trgelem2 == null){
188 trgelem2 = document.getElementById('form_' + target);
190 if (trgelem1 == null && trgelem2 == null) {
191 if (!cskerror) alert(<?php echo xlj('Cannot find a skip target field for'); ?> + ' "' + target + '"');
192 myerror = true;
193 continue;
197 // Find the target row and count its cells, accounting for colspans.
198 var trgrow = trgelem1 ? trgelem1.parentNode : trgelem2.parentNode;
199 var rowcells = 0;
200 for (var itmp = 0; itmp < trgrow.cells.length; ++itmp) {
201 rowcells += trgrow.cells[itmp].colSpan;
204 // If the item occupies a whole row then undisplay its row, otherwise hide its cells.
205 var colspan = 0;
206 if (trgelem1) colspan += trgelem1.colSpan;
207 if (trgelem2) colspan += trgelem2.colSpan;
208 if (colspan < rowcells) {
209 if (trgelem1) trgelem1.style.visibility = condition ? 'hidden' : 'visible';
210 if (trgelem2) trgelem2.style.visibility = condition ? 'hidden' : 'visible';
212 else {
213 trgrow.style.display = condition ? 'none' : '';
216 else if (condition) { // action starts with "value="
217 var trgelem = document.getElementById('form_' + target);
218 if (trgelem == null) {
219 if (!cskerror) alert('Cannot find a value target field "' + trgelem + '"');
220 myerror = true;
221 continue;
223 var action_value = action.substring(6);
224 if (trgelem.type == 'checkbox') {
225 trgelem.checked = !(action_value == '0' || action_value == '');
227 else {
228 trgelem.value = action_value;
232 // If any errors, all show in the first pass and none in subsequent passes.
233 cskerror = cskerror || myerror;
236 ///////////////////////////////////////////////////////////////////////
237 // Image canvas support starts here.
238 ///////////////////////////////////////////////////////////////////////
240 var lbfCanvases = {}; // contains the LC instance for each canvas.
242 // Initialize the drawing widget.
243 // canid is the id of the div that will contain the canvas, and the image
244 // element used for initialization should have an id of canid + '_img'.
246 function lbfCanvasSetup(canid, canWidth, canHeight) {
247 LC.localize({
248 "stroke" : <?php echo xlj('stroke'); ?>,
249 "fill" : <?php echo xlj('fill'); ?>,
250 "bg" : <?php echo xlj('bg{{image canvas label}}'); ?>,
251 "Clear" : <?php echo xlj('Clear'); ?>,
252 // The following are tooltip translations, however they do not work due to
253 // a bug in LiterallyCanvas 0.4.13. We'll leave them here pending a fix.
254 "Eraser" : <?php echo xlj('Eraser'); ?>,
255 "Pencil" : <?php echo xlj('Pencil'); ?>,
256 "Line" : <?php echo xlj('Line'); ?>,
257 "Rectangle" : <?php echo xlj('Rectangle'); ?>,
258 "Ellipse" : <?php echo xlj('Ellipse'); ?>,
259 "Text" : <?php echo xlj('Text'); ?>,
260 "Polygon" : <?php echo xlj('Polygon'); ?>,
261 "Pan" : <?php echo xlj('Pan'); ?>,
262 "Eyedropper": <?php echo xlj('Eyedropper'); ?>,
263 "Undo" : <?php echo xlj('Undo'); ?>,
264 "Redo" : <?php echo xlj('Redo'); ?>,
265 "Zoom out" : <?php echo xlj('Zoom out'); ?>,
266 "Zoom in" : <?php echo xlj('Zoom in'); ?>,
268 var tmpImage = document.getElementById(canid + '_img');
269 var shape = LC.createShape('Image', {x: 0, y: 0, image: tmpImage});
270 var lc = LC.init(document.getElementById(canid), {
271 imageSize: {width: canWidth, height: canHeight},
272 strokeWidths: [1, 2, 3, 5, 8, 12],
273 defaultStrokeWidth: 2,
274 backgroundShapes: [shape],
275 imageURLPrefix: '<?php echo $GLOBALS['assets_static_relative'] ?>/literallycanvas/img'
277 if (canHeight > 261) {
278 // TBD: Do something to make the widget bigger?
279 // Look for some help with this in the next LC release.
281 // lc.saveShape(shape); // alternative to the above backgroundShapes
282 lbfCanvases[canid] = lc;
285 // This returns a standard "Data URL" string representing the image data.
286 // It will typically be a few kilobytes. Here's a truncated example:
287 // data:image/png;base64,iVBORw0K ...
289 function lbfCanvasGetData(canid) {
290 return lbfCanvases[canid].getImage().toDataURL();
293 // This is invoked when a field with edit option M is changed.
294 // Its purpose is to make the corresponding change to the member fields (edit option m).
296 function checkGroupMembers(elem, groupnumber) {
297 var i = elem.id.indexOf('[');
298 if (i < 0) {
299 alert(<?php echo xlj('Field not suitable for edit option M') ?> + ': ' + elem.name);
300 return;
302 var suffix = elem.id.substring(i);
303 var members = document.getElementsByClassName('lbf_memgroup_' + groupnumber);
304 if (members.length == 0) {
305 alert(<?php echo xlj('No member fields found for') ?> + ': ' + elem.name);
306 return;
308 for (var i = 0; i < members.length; ++i) {
309 if (members[i].id.indexOf(suffix) > 1) {
310 members[i].checked = true;
315 </script>