Fix LogoService for Windows (#6375)
[openemr.git] / library / options.inc.php
blobf1d9f006697dce66c09db6aa3274f080501a5785
1 <?php
3 // Copyright (C) 2007-2021 Rod Roark <rod@sunsetsystems.com>
4 // Copyright © 2010 by Andrew Moore <amoore@cpan.org>
5 // Copyright © 2010 by "Boyd Stephen Smith Jr." <bss@iguanasuicide.net>
6 // Copyright (c) 2017 - 2021 Jerry Padgett <sjpadgett@gmail.com>
7 // Copyright (c) 2021 Robert Down <robertdown@live.com>
8 // Copyright (c) 2022 David Eschelbacher <psoas@tampabay.rr.com>
9 //
10 // This program is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU General Public License
12 // as published by the Free Software Foundation; either version 2
13 // of the License, or (at your option) any later version.
15 // Functions for managing the lists and layouts
17 // Note: there are translation wrappers for the lists and layout labels
18 // at library/translation.inc.php. The functions are titled
19 // xl_list_label() and xl_layout_label() and are controlled by the
20 // $GLOBALS['translate_lists'] and $GLOBALS['translate_layout']
21 // flags in globals.php
23 // Documentation for layout_options.edit_options:
25 // A = Age as years or "xx month(s)"
26 // B = Gestational age as "xx week(s) y day(s)"
27 // C = Capitalize first letter of each word (text fields)
28 // D = Check for duplicates in New Patient form
29 // G = Graphable (for numeric fields in forms supporting historical data)
30 // H = Read-only field copied from static history (this is obsolete)
31 // J = Jump to Next Row
32 // K = Prepend Blank Row
33 // L = Lab Order ("ord_lab") types only (address book)
34 // M = Radio Group Master (currently for radio buttons only)
35 // m = Radio Group Member (currently for radio buttons only)
36 // N = Show in New Patient form
37 // O = Procedure Order ("ord_*") types only (address book)
38 // P = Default to previous value when current value is not yet set
39 // R = Distributor types only (address book)
40 // T = Use description as default Text
41 // DAP = Use description as placeholder
42 // U = Capitalize all letters (text fields)
43 // V = Vendor types only (address book)
44 // 0 = Read Only - the input element's "disabled" property is set
45 // 1 = Write Once (not editable when not empty) (text fields)
46 // 2 = Show descriptions instead of codes for billing code input
48 // note: isOption() returns true/false
50 // NOTE: All of the magic constants for the data types here are found in library/layout.inc.php
52 require_once("user.inc.php");
53 require_once("patient.inc.php");
54 require_once("lists.inc.php");
55 require_once(dirname(dirname(__FILE__)) . "/custom/code_types.inc.php");
57 use OpenEMR\Common\Acl\AclExtended;
58 use OpenEMR\Common\Acl\AclMain;
59 use OpenEMR\Services\EncounterService;
60 use OpenEMR\Services\FacilityService;
61 use OpenEMR\Services\PatientService;
63 $facilityService = new FacilityService();
65 $date_init = "";
66 $membership_group_number = 0;
68 // Our base Bootstrap column class, referenced here and in some other modules.
69 // Using col-lg allow us to have additional breakpoint at col-md.(992px, 768px)
70 // col-md-auto will let BS decide with col-12 always for sm devices.
71 $BS_COL_CLASS = 'col-12 col-md-auto col-lg';
73 function get_pharmacies()
75 return sqlStatement("SELECT d.id, d.name, a.line1, a.city, " .
76 "p.area_code, p.prefix, p.number FROM pharmacies AS d " .
77 "LEFT OUTER JOIN addresses AS a ON a.foreign_id = d.id " .
78 "LEFT OUTER JOIN phone_numbers AS p ON p.foreign_id = d.id " .
79 "AND p.type = 2 " .
80 "ORDER BY a.state, a.city, d.name, p.area_code, p.prefix, p.number");
83 function optionalAge($frow, $date, &$asof, $description = '')
85 $asof = '';
86 if (empty($date)) {
87 return '';
90 $edit_options = $frow['edit_options'] ?? null;
92 $date = substr($date, 0, 10);
93 if (isOption($edit_options, 'A') !== false) {
94 $format = 0;
95 } elseif (isOption($edit_options, 'B') !== false) {
96 $format = 3;
97 } else {
98 return '';
101 if (isOption($frow['form_id'], 'LBF') === false) {
102 $tmp = sqlQuery(
103 "SELECT date FROM form_encounter WHERE " .
104 "pid = ? AND encounter = ? ORDER BY id DESC LIMIT 1",
105 array($GLOBALS['pid'], $GLOBALS['encounter'])
107 if (!empty($tmp['date'])) {
108 $asof = substr($tmp['date'], 0, 10);
111 if ($description === '') {
112 $prefix = ($format ? xl('Gest age') : xl('Age')) . ' ';
113 } else {
114 $prefix = $description . ' ';
116 return $prefix . oeFormatAge($date, $asof, $format);
119 // Function to generate a drop-list.
121 function generate_select_list(
122 $tag_name,
123 $list_id,
124 $currvalue,
125 $title,
126 $empty_name = ' ',
127 $class = '',
128 $onchange = '',
129 $tag_id = '',
130 $custom_attributes = null,
131 $multiple = false, // new #10
132 $backup_list = '', // new #11
133 $ignore_default = false,
134 $include_inactive = false,
135 $tabIndex = false
137 $s = '';
139 $tag_name_esc = attr($tag_name);
141 if ($multiple) {
142 $tag_name_esc = $tag_name_esc . "[]";
145 $s .= "<select name='$tag_name_esc'";
147 if ($tabIndex !== false) {
148 $s .= " tabindex='" . attr($tabIndex) . "' '";
151 if ($multiple) {
152 $s .= " multiple='multiple'";
155 $tag_id_esc = attr($tag_name);
157 if ($tag_id != '') {
158 $tag_id_esc = attr($tag_id);
161 $s .= " id='$tag_id_esc'";
163 if (!empty($class)) {
164 $class_esc = attr($class);
165 $s .= " class='form-control $class_esc'";
166 } else {
167 $s .= " class='form-control'";
170 if ($onchange) {
171 $s .= " onchange='$onchange'";
174 if ($custom_attributes != null && is_array($custom_attributes)) {
175 foreach ($custom_attributes as $attr => $val) {
176 if (isset($custom_attributes [$attr])) {
177 $s .= " " . attr($attr) . "='" . attr($val) . "'";
182 $selectTitle = attr($title);
183 $s .= " title='$selectTitle'>";
184 $selectEmptyName = xlt($empty_name);
185 if ($empty_name) {
186 $s .= "<option value=''>" . $selectEmptyName . "</option>";
189 $got_selected = false;
191 for ($active = 1; $active == 1 || ($active == 0 && $include_inactive); --$active) {
192 if ($include_inactive) {
193 $s .= "<optgroup label='" . ($active ? xla('Active') : xla('Inactive')) . "'>\n";
196 // List order depends on language translation options.
197 // (Note we do not need to worry about the list order in the algorithm
198 // after the below code block since that is where searches for exceptions
199 // are done which include inactive items or items from a backup
200 // list; note these will always be shown at the bottom of the list no matter the
201 // chosen order.)
202 $lang_id = empty($_SESSION['language_choice']) ? '1' : $_SESSION['language_choice'];
203 // sort by title
204 if (!$GLOBALS['translate_lists']) {
205 // do not translate
206 if ($GLOBALS['gb_how_sort_list'] == '0') {
207 // order by seq
208 $order_by_sql = "seq, title";
209 } else { //$GLOBALS['gb_how_sort_list'] == '1'
210 // order by title
211 $order_by_sql = "title, seq";
213 $lres = sqlStatement(
214 "SELECT * FROM list_options WHERE list_id = ? AND activity = ? ORDER BY "
215 . $order_by_sql,
216 array($list_id, $active)
218 } else {
219 // do translate
220 if ($GLOBALS['gb_how_sort_list'] == '0') {
221 // order by seq
222 $order_by_sql = "lo.seq, title";
223 } else { //$GLOBALS['gb_how_sort_list'] == '1'
224 // order by title
225 $order_by_sql = "title, lo.seq";
227 $lres = sqlStatement(
228 "SELECT lo.option_id, lo.is_default, " .
229 "COALESCE((SELECT ld.definition FROM lang_constants AS lc, lang_definitions AS ld " .
230 "WHERE lc.constant_name = lo.title AND ld.cons_id = lc.cons_id AND ld.lang_id = ? " .
231 "AND ld.definition IS NOT NULL AND ld.definition != '' " .
232 "LIMIT 1), lo.title) AS title " .
233 "FROM list_options AS lo " .
234 "WHERE lo.list_id = ? AND lo.activity = ? " .
235 "ORDER BY " . $order_by_sql,
236 array($lang_id, $list_id, $active)
240 while ($lrow = sqlFetchArray($lres)) {
241 $selectedValues = explode("|", $currvalue ?? '');
243 $optionValue = attr($lrow ['option_id']);
244 $s .= "<option value='$optionValue'";
246 if (
247 (strlen($currvalue ?? '') == 0 && $lrow ['is_default'] && !$ignore_default) ||
248 (strlen($currvalue ?? '') > 0 && in_array($lrow ['option_id'], $selectedValues))
250 $s .= " selected";
251 $got_selected = true;
254 // Already has been translated above (if applicable), so do not need to use
255 // the xl_list_label() function here
256 $optionLabel = text($lrow ['title']);
257 $s .= ">$optionLabel</option>\n";
260 if ($include_inactive) {
261 $s .= "</optgroup>\n";
263 } // end $active loop
266 To show the inactive item in the list if the value is saved to database
268 if (!$got_selected && strlen($currvalue ?? '') > 0) {
269 $lres_inactive = sqlStatement("SELECT * FROM list_options " .
270 "WHERE list_id = ? AND activity = 0 AND option_id = ? ORDER BY seq, title", array($list_id, $currvalue));
271 $lrow_inactive = sqlFetchArray($lres_inactive);
272 if (!empty($lrow_inactive['option_id'])) {
273 $optionValue = htmlspecialchars($lrow_inactive['option_id'], ENT_QUOTES);
274 $s .= "<option value='$optionValue' selected>" . htmlspecialchars(xl_list_label($lrow_inactive['title']), ENT_NOQUOTES) . "</option>\n";
275 $got_selected = true;
279 if (!$got_selected && strlen($currvalue ?? '') > 0 && !$multiple) {
280 $list_id = $backup_list;
281 $lrow = sqlQuery("SELECT title FROM list_options WHERE list_id = ? AND option_id = ?", array($list_id,$currvalue));
283 if ($lrow > 0 && !empty($backup_list)) {
284 $selected = text(xl_list_label($lrow['title']));
285 $s .= "<option value='" . attr($currvalue) . "' selected> $selected </option>";
286 $s .= "</select>";
287 } else {
288 $s .= "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
289 $s .= "</select>";
290 $fontTitle = xlt('Please choose a valid selection from the list.');
291 $fontText = xlt('Fix this');
292 $s .= " <span class='text-danger' title='$fontTitle'>$fontText!</span>";
294 } elseif (!$got_selected && strlen($currvalue ?? '') > 0 && $multiple) {
295 //if not found in main list, display all selected values that exist in backup list
296 $list_id = $backup_list;
298 $got_selected_backup = false;
299 if (!empty($backup_list)) {
300 $lres_backup = sqlStatement("SELECT * FROM list_options WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
301 while ($lrow_backup = sqlFetchArray($lres_backup)) {
302 $selectedValues = explode("|", $currvalue);
304 $optionValue = attr($lrow_backup['option_id']);
306 if (in_array($lrow_backup ['option_id'], $selectedValues)) {
307 $s .= "<option value='$optionValue'";
308 $s .= " selected";
309 $optionLabel = text(xl_list_label($lrow_backup ['title']));
310 $s .= ">$optionLabel</option>\n";
311 $got_selected_backup = true;
316 if (!$got_selected_backup) {
317 $selectedValues = explode("|", $currvalue);
318 foreach ($selectedValues as $selectedValue) {
319 $s .= "<option value='" . attr($selectedValue) . "'";
320 $s .= " selected";
321 $s .= ">* " . text($selectedValue) . " *</option>\n";
324 $s .= "</select>";
325 $fontTitle = xlt('Please choose a valid selection from the list.');
326 $fontText = xlt('Fix this');
327 $s .= " <span class='text-danger' title='$fontTitle'>$fontText!</span>";
329 } else {
330 $s .= "</select>";
333 return $s;
336 // Parsing for data type 31, static text.
337 function parse_static_text($frow, $value_allowed = true)
339 $tmp = str_replace("\r\n", "\n", $frow['description']);
340 // Translate if it does not look like HTML.
341 if (substr($tmp, 0, 1) != '<') {
342 $tmp2 = $frow['description'];
343 $tmp3 = xl_layout_label($tmp);
344 if ($tmp3 == $tmp && $tmp2 != $tmp) {
345 // No translation, try again without the CRLF substitution.
346 $tmp3 = xl_layout_label($tmp2);
348 $tmp = nl2br($tmp3);
350 $s = '';
351 if ($frow['source'] == 'D' || $frow['source'] == 'H') {
352 // Source is demographics or history. This case supports value substitution.
353 while (preg_match('/^(.*?)\{(\w+)\}(.*)$/', $tmp, $matches)) {
354 $s .= $matches[1];
355 if ($value_allowed) {
356 $tmprow = $frow;
357 $tmprow['field_id'] = $matches[2];
358 $s .= lbf_current_value($tmprow, 0, 0);
360 $tmp = $matches[3];
363 $s .= $tmp;
364 return $s;
367 function genLabResultsTextItem($name, $value, $outtype, $size, $maxlength, $disabled = '')
369 $string_maxlength = $maxlength ? ("maxlength='" . attr($maxlength) . "'") : '';
370 $s = "<td align='center'>";
371 if ($outtype == 2) {
372 $s .= text($value);
373 } else {
374 $s .= "<input type='text'";
375 if ($outtype == 0) {
376 $s .= " name='" . attr($name) . "' id='" . attr($name) . "'";
378 $s .= " size='" . attr($size) . "' $string_maxlength" .
379 " value='" . attr($value) . "'" .
380 " $under $disabled />";
382 $s .= "&nbsp;</td>";
383 return $s;
386 // $outtype = 0 for form, 1 for print, 2 for display, 3 for plain text.
387 function genLabResults($frow, $currvalue, $outtype = 0, $disabled = '')
389 $field_id = $frow['field_id'];
390 $list_id = $frow['list_id'];
391 $field_id_esc = text($field_id);
392 $under = $outtype == 1 ? "class='under'" : "";
393 $s = '';
395 $avalue = json_decode($currvalue, true);
396 if (empty($avalue)) {
397 $avalue = array();
399 // $avalue[$option_id][0] : gestation
400 // $avalue[$option_id][1] : radio button value
401 // $avalue[$option_id][2] : test value
402 // $avalue[$option_id][3] : notes
404 $maxlength = $frow['max_length'];
405 $fldlength = empty($frow['fld_length']) ? 20 : $frow['fld_length'];
407 $under = $outtype == 1 ? "class='under'" : "";
409 $s .= "<table cellpadding='0' cellspacing='0'>";
410 if ($outtype < 2) {
411 $s .= "<tr>" .
412 "<td class='bold' align='center'>" . xlt('Test/Screening') . "&nbsp;</td>" .
413 "<td class='bold' align='center'>" . xlt('Gest wks') . "&nbsp;</td>" .
414 "<td class='bold' align='center'>&nbsp;" . xlt('N/A') . "&nbsp;</td>" .
415 "<td class='bold' align='center'>" . xlt('Neg/Nrml') . "</td>" .
416 "<td class='bold' align='center'>&nbsp;" . xlt('Pos/Abn') . "&nbsp;</td>" .
417 "<td class='bold' align='center'>" . xlt('Test Value') . "&nbsp;</td>" .
418 "<td class='bold' align='center'>" . xlt('Date/Notes') . "&nbsp;</td>" .
419 "</tr>";
422 $lres = sqlStatement(
423 "SELECT * FROM list_options WHERE " .
424 "list_id = ? AND activity = 1 ORDER BY seq, title",
425 array($list_id)
428 while ($lrow = sqlFetchArray($lres)) {
429 $option_id = $lrow['option_id'];
430 $option_id_esc = text($option_id);
432 if ($outtype >= 2 && empty($avalue[$option_id][1])) {
433 continue;
436 if ($outtype == 3) {
437 if (isset($avalue[$option_id][1]) && $avalue[$option_id][1] == '2') {
438 if ($s !== '') {
439 $s .= '; ';
441 $s .= text(xl_list_label($lrow['title']));
442 $s .= ':' . text($avalue[$option_id][0]);
443 $s .= ':' . text($avalue[$option_id][2]);
444 $s .= ':' . text($avalue[$option_id][3]);
446 continue;
449 $s .= "<tr>";
450 $s .= $outtype == 2 ? "<td class='bold'>" : "<td>";
451 $s .= text(xl_list_label($lrow['title'])) . "&nbsp;</td>";
453 $s .= genLabResultsTextItem(
454 "form_{$field_id_esc}[$option_id_esc][0]",
455 (isset($avalue[$option_id][0]) ? $avalue[$option_id][0] : ''),
456 $outtype,
459 $disabled,
460 $under
463 if ($outtype == 2) {
464 $tmp = isset($avalue[$option_id][1]) ? $avalue[$option_id][1] : '0';
465 $restype = ($tmp == '1') ? xl('Normal') : (($tmp == '2') ? xl('Abnormal') : xl('N/A'));
466 $s .= "<td>" . text($restype) . "&nbsp;</td>";
467 } else {
468 for ($i = 0; $i < 3; ++$i) {
469 $s .= "<td align='center'>";
470 $s .= "<input type='radio'";
471 if ($outtype == 0) {
472 $s .= " name='radio_{$field_id_esc}[$option_id_esc]'" .
473 " id='radio_{$field_id_esc}[$option_id_esc]'";
475 $s .= " value='$i' $lbfonchange";
476 if (isset($avalue[$option_id][1]) && $avalue[$option_id][1] == "$i") {
477 $s .= " checked";
479 $s .= " $disabled />";
480 $s .= "</td>";
483 $s .= genLabResultsTextItem(
484 "form_{$field_id_esc}[$option_id_esc][2]",
485 (isset($avalue[$option_id][2]) ? $avalue[$option_id][2] : ''),
486 $outtype,
489 $disabled,
490 $under
492 $s .= genLabResultsTextItem(
493 "form_{$field_id_esc}[$option_id_esc][3]",
494 (isset($avalue[$option_id][3]) ? $avalue[$option_id][3] : ''),
495 $outtype,
496 $fldlength,
497 $maxlength,
498 $disabled,
499 $under
501 $s .= "</tr>";
503 if ($outtype != 3) {
504 $s .= "</table>";
507 return $s;
510 // $frow is a row from the layout_options table.
511 // $currvalue is the current value, if any, of the associated item.
513 function generate_form_field($frow, $currvalue)
515 global $rootdir, $date_init, $ISSUE_TYPES, $code_types, $membership_group_number;
517 $currescaped = htmlspecialchars($currvalue ?? '', ENT_QUOTES);
519 $data_type = $frow['data_type'];
520 $field_id = $frow['field_id'];
521 $list_id = $frow['list_id'] ?? null;
522 $backup_list = $frow['list_backup_id'] ?? null;
523 $edit_options = $frow['edit_options'] ?? null;
524 $form_id = $frow['form_id'] ?? null;
526 // 'smallform' can be 'true' if we want a smaller form field, otherwise
527 // can be used to assign arbitrary CSS classes to data entry fields.
528 $smallform = $frow['smallform'] ?? null;
529 if ($smallform === 'true') {
530 $smallform = ' form-control-sm';
533 // escaped variables to use in html
534 $field_id_esc = htmlspecialchars($field_id, ENT_QUOTES);
535 $list_id_esc = htmlspecialchars(($list_id ?? ''), ENT_QUOTES);
537 // Added 5-09 by BM - Translate description if applicable
538 $description = (isset($frow['description']) ? htmlspecialchars(xl_layout_label($frow['description']), ENT_QUOTES) : '');
540 // Support edit option T which assigns the (possibly very long) description as
541 // the default value.
542 if (isOption($edit_options, 'T') !== false) {
543 if (strlen($currescaped) == 0) {
544 $currescaped = $description;
547 // Description used in this way is not suitable as a title.
548 $description = '';
551 // Support using the description as a placeholder
552 $placeholder = (isOption($edit_options, 'DAP') === true) ? " placeholder='{$description}' " : '';
554 // added 5-2009 by BM to allow modification of the 'empty' text title field.
555 // Can pass $frow['empty_title'] with this variable, otherwise
556 // will default to 'Unassigned'.
557 // modified 6-2009 by BM to allow complete skipping of the 'empty' text title
558 // if make $frow['empty_title'] equal to 'SKIP'
559 $showEmpty = true;
560 if (isset($frow['empty_title'])) {
561 if ($frow['empty_title'] == "SKIP") {
562 //do not display an 'empty' choice
563 $showEmpty = false;
564 $empty_title = "Unassigned";
565 } else {
566 $empty_title = $frow['empty_title'];
568 } else {
569 $empty_title = "Unassigned";
572 $disabled = isOption($edit_options, '0') === false ? '' : 'disabled';
574 $lbfchange = (
575 !empty($form_id) &&
577 strpos($form_id, 'LBF') === 0 ||
578 strpos($form_id, 'LBT') === 0 ||
579 strpos($form_id, 'DEM') === 0 ||
580 strpos($form_id, 'HIS') === 0
582 ) ? "checkSkipConditions();" : "";
583 $lbfonchange = $lbfchange ? "onchange='$lbfchange'" : "";
585 // generic single-selection list or single-selection list with search or single-selection list with comment support.
586 // These data types support backup lists.
587 if ($data_type == 1 || $data_type == 43 || $data_type == 46) {
588 if ($data_type == 46) {
589 // support for single-selection list with comment support
590 $lbfchange = "processCommentField(" . attr_js($field_id) . ");" . $lbfchange;
593 echo generate_select_list(
594 "form_$field_id",
595 $list_id,
596 $currvalue,
597 $description,
598 ($showEmpty ? $empty_title : ''),
599 (($data_type == 43) ? "select-dropdown" : $smallform),
600 $lbfchange,
602 ($disabled ? array('disabled' => 'disabled') : null),
603 false,
604 $backup_list
607 if ($data_type == 46) {
608 // support for single-selection list with comment support
609 $selectedValues = explode("|", $currvalue);
610 if (!preg_match('/^comment_/', $currvalue) || (count($selectedValues) == 1)) {
611 $display = "display:none";
612 $comment = "";
613 } else {
614 $display = "display:inline-block";
615 $comment = $selectedValues[count($selectedValues) - 1];
617 echo "<input type='text'" .
618 " name='form_text_" . attr($field_id) . "'" .
619 " id='form_text_" . attr($field_id) . "'" .
620 " size='" . attr($frow['fld_length']) . "'" .
621 " class='form-control'" .
622 $placeholder .
623 " " . ((!empty($frow['max_length'])) ? "maxlength='" . attr($frow['max_length']) . "'" : "") . " " .
624 " style='" . $display . "'" .
625 " value='" . attr($comment) . "'/>";
627 } elseif ($data_type == 2) { // simple text field
628 $fldlength = htmlspecialchars($frow['fld_length'] ?? '', ENT_QUOTES);
629 $maxlength = $frow['max_length'] ?? '';
630 $string_maxlength = "";
631 // if max_length is set to zero, then do not set a maxlength
632 if ($maxlength) {
633 $string_maxlength = "maxlength='" . attr($maxlength) . "'";
636 echo "<input type='text'
637 class='form-control{$smallform}'
638 name='form_{$field_id_esc}'
639 id='form_{$field_id_esc}'
640 size='{$fldlength}'
641 {$string_maxlength}
642 {$placeholder}
643 title='{$description}'
644 value='{$currescaped}'";
645 $tmp = $lbfchange;
646 if (isOption($edit_options, 'C') !== false) {
647 $tmp .= "capitalizeMe(this);";
648 } elseif (isOption($edit_options, 'U') !== false) {
649 $tmp .= "this.value = this.value.toUpperCase();";
652 if ($tmp) {
653 echo " onchange='$tmp'";
656 $tmp = htmlspecialchars($GLOBALS['gbl_mask_patient_id'], ENT_QUOTES);
657 // If mask is for use at save time, treat as no mask.
658 if (strpos($tmp, '^') !== false) {
659 $tmp = '';
661 if ($field_id == 'pubpid' && strlen($tmp) > 0) {
662 echo " onkeyup='maskkeyup(this,\"$tmp\")'";
663 echo " onblur='maskblur(this,\"$tmp\")'";
666 if (isOption($edit_options, '1') !== false && strlen($currescaped) > 0) {
667 echo " readonly";
670 if ($disabled) {
671 echo ' disabled';
674 echo " />";
675 } elseif ($data_type == 3) { // long or multi-line text field
676 $textCols = htmlspecialchars($frow['fld_length'], ENT_QUOTES);
677 $textRows = htmlspecialchars($frow['fld_rows'], ENT_QUOTES);
678 echo "<textarea" .
679 " name='form_$field_id_esc'" .
680 " class='form-control$smallform'" .
681 " id='form_$field_id_esc'" .
682 " title='$description'" .
683 $placeholder .
684 " cols='$textCols'" .
685 " rows='$textRows' $lbfonchange $disabled" .
686 ">" . $currescaped . "</textarea>";
687 } elseif ($data_type == 4) { // date
688 $age_asof_date = ''; // optionalAge() sets this
689 $age_format = isOption($edit_options, 'A') === false ? 3 : 0;
690 $agestr = optionalAge($frow, $currvalue, $age_asof_date, $description);
691 if ($agestr) {
692 echo "<table class='table'><tr><td class='text'>";
695 $onchange_string = '';
696 if (!$disabled && $agestr) {
697 $onchange_string = "onchange=\"if (typeof(updateAgeString) == 'function') " .
698 "updateAgeString('$field_id','$age_asof_date', $age_format, '$description')\"";
700 if ($data_type == 4) {
701 $modtmp = isOption($edit_options, 'F') === false ? 0 : 1;
702 $datetimepickerclass = ($frow['validation'] ?? null) === 'past_date' ? '-past' : ( ($frow['validation'] ?? null) === 'future_date' ? '-future' : '' );
703 if (!$modtmp) {
704 $dateValue = oeFormatShortDate(substr($currescaped, 0, 10));
705 echo "<input type='text' size='10' class='datepicker$datetimepickerclass form-control$smallform' name='form_$field_id_esc' id='form_$field_id_esc'" . " value='" . attr($dateValue) . "'";
706 } else {
707 $dateValue = oeFormatDateTime(substr($currescaped, 0, 20), 0);
708 echo "<input type='text' size='20' class='datetimepicker$datetimepickerclass form-control$smallform' name='form_$field_id_esc' id='form_$field_id_esc'" . " value='" . attr($dateValue) . "'";
711 if (!$agestr) {
712 echo " title='$description'";
715 // help chrome users avoid autocomplete interfere with datepicker widget display
716 if ($frow['field_id'] == 'DOB') {
717 echo " autocomplete='off' $onchange_string $lbfonchange $disabled />";
718 } else {
719 echo " $onchange_string $lbfonchange $disabled />";
722 // Optional display of age or gestational age.
723 if ($agestr) {
724 echo "</td></tr><tr><td id='span_$field_id' class='text'>" . text($agestr) . "</td></tr></table>";
726 } elseif ($data_type == 10) { // provider list, local providers only
727 $ures = sqlStatement("SELECT id, fname, lname, specialty FROM users " .
728 "WHERE active = 1 AND ( info IS NULL OR info NOT LIKE '%Inactive%' ) " .
729 "AND authorized = 1 " .
730 "ORDER BY lname, fname");
731 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' title='$description' $lbfonchange $disabled class='form-control$smallform'>";
732 echo "<option value=''>" . xlt($empty_title) . "</option>";
733 $got_selected = false;
734 while ($urow = sqlFetchArray($ures)) {
735 $uname = text($urow['fname'] . ' ' . $urow['lname']);
736 $optionId = attr($urow['id']);
737 echo "<option value='$optionId'";
738 if ($urow['id'] == $currvalue) {
739 echo " selected";
740 $got_selected = true;
743 echo ">$uname</option>";
746 if (!$got_selected && $currvalue) {
747 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
748 echo "</select>";
749 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
750 } else {
751 echo "</select>";
753 } elseif ($data_type == 11) { // provider list, including address book entries with an NPI number
754 $ures = sqlStatement("SELECT id, fname, lname, specialty FROM users " .
755 "WHERE active = 1 AND ( info IS NULL OR info NOT LIKE '%Inactive%' ) " .
756 "AND ( authorized = 1 OR ( username = '' AND npi != '' ) ) " .
757 "ORDER BY lname, fname");
758 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' title='$description' class='form-control$smallform'";
759 echo " $lbfonchange $disabled>";
760 echo "<option value=''>" . xlt('Unassigned') . "</option>";
761 $got_selected = false;
762 while ($urow = sqlFetchArray($ures)) {
763 $uname = text($urow['fname'] . ' ' . $urow['lname']);
764 $optionId = attr($urow['id']);
765 echo "<option value='$optionId'";
766 if ($urow['id'] == $currvalue) {
767 echo " selected";
768 $got_selected = true;
771 echo ">$uname</option>";
774 if (!$got_selected && $currvalue) {
775 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
776 echo "</select>";
777 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
778 } else {
779 echo "</select>";
781 } elseif ($data_type == 12) { // pharmacy list
782 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' title='$description' class='form-control$smallform'";
783 echo " $lbfonchange $disabled>";
784 echo "<option value='0'></option>";
785 $pres = get_pharmacies();
786 $got_selected = false;
787 $zone = '';
788 while ($prow = sqlFetchArray($pres)) {
789 if ($zone != strtolower(trim($prow['city'] ?? ''))) {
790 if ($zone != '') {
791 echo "</optgroup>";
793 $zone = strtolower(trim($prow['city']));
794 echo "<optgroup label='" . attr($prow['city']) . "'>";
796 $key = $prow['id'];
797 $optionValue = htmlspecialchars($key, ENT_QUOTES);
798 $optionLabel = htmlspecialchars($prow['name'] . ' ' . $prow['area_code'] . '-' .
799 $prow['prefix'] . '-' . $prow['number'] . ' / ' .
800 $prow['line1'] . ' / ' . $prow['city'], ENT_NOQUOTES);
801 echo "<option value='$optionValue'";
802 if ($currvalue == $key) {
803 echo " selected";
804 $got_selected = true;
807 echo ">$optionLabel</option>";
810 if (!$got_selected && $currvalue) {
811 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
812 echo "</select>";
813 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
814 } else {
815 echo "</select>";
817 } elseif ($data_type == 13) { // squads
818 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' title='$description' class='form-control$smallform'";
819 echo " $lbfonchange $disabled>";
820 echo "<option value=''>&nbsp;</option>";
821 $squads = AclExtended::aclGetSquads();
822 if ($squads) {
823 foreach ($squads as $key => $value) {
824 $optionValue = htmlspecialchars($key, ENT_QUOTES);
825 $optionLabel = htmlspecialchars($value[3], ENT_NOQUOTES);
826 echo "<option value='$optionValue'";
827 if ($currvalue == $key) {
828 echo " selected";
831 echo ">$optionLabel</option>\n";
835 echo "</select>";
836 } elseif ($data_type == 14) {
837 // Address book, preferring organization name if it exists and is not in
838 // parentheses, and excluding local users who are not providers.
839 // Supports "referred to" practitioners and facilities.
840 // Alternatively the letter L in edit_options means that abook_type
841 // must be "ord_lab", indicating types used with the procedure
842 // lab ordering system.
843 // Alternatively the letter O in edit_options means that abook_type
844 // must begin with "ord_", indicating types used with the procedure
845 // ordering system.
846 // Alternatively the letter V in edit_options means that abook_type
847 // must be "vendor", indicating the Vendor type.
848 // Alternatively the letter R in edit_options means that abook_type
849 // must be "dist", indicating the Distributor type.
851 if (isOption($edit_options, 'L') !== false) {
852 $tmp = "abook_type = 'ord_lab'";
853 } elseif (isOption($edit_options, 'O') !== false) {
854 $tmp = "abook_type LIKE 'ord\\_%'";
855 } elseif (isOption($edit_options, 'V') !== false) {
856 $tmp = "abook_type LIKE 'vendor%'";
857 } elseif (isOption($edit_options, 'R') !== false) {
858 $tmp = "abook_type LIKE 'dist'";
859 } else {
860 $tmp = "( username = '' OR authorized = 1 )";
863 $ures = sqlStatement("SELECT id, fname, lname, organization, username, npi FROM users " .
864 "WHERE active = 1 AND ( info IS NULL OR info NOT LIKE '%Inactive%' ) " .
865 "AND $tmp " .
866 "ORDER BY organization, lname, fname, npi");
867 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' title='$description' class='form-control$smallform'";
868 echo " $lbfonchange $disabled>";
869 echo "<option value=''>" . htmlspecialchars(xl('Unassigned'), ENT_NOQUOTES) . "</option>";
870 while ($urow = sqlFetchArray($ures)) {
871 $uname = $urow['organization'];
872 if (empty($uname) || substr($uname, 0, 1) == '(') {
873 $uname = $urow['lname'];
874 if ($urow['fname']) {
875 $uname .= ", " . $urow['fname'];
877 if ($urow['npi']) {
878 $uname .= ": " . $urow['npi'];
882 $optionValue = htmlspecialchars($urow['id'], ENT_QUOTES);
883 $optionLabel = htmlspecialchars($uname, ENT_NOQUOTES);
884 echo "<option value='$optionValue'";
885 // Failure to translate Local and External is not an error here;
886 // they are only used as internal flags and must not be translated!
887 $title = $urow['username'] ? 'Local' : 'External';
888 $optionTitle = htmlspecialchars($title, ENT_QUOTES);
889 echo " title='$optionTitle'";
890 if ($urow['id'] == $currvalue) {
891 echo " selected";
894 echo ">$optionLabel</option>";
897 echo "</select>";
898 } elseif ($data_type == 15) { // A billing code. If description matches an existing code type then that type is used.
899 $codetype = '';
900 if (!empty($frow['description']) && isset($code_types[$frow['description']])) {
901 $codetype = $frow['description'];
903 $fldlength = attr($frow['fld_length']);
904 $maxlength = $frow['max_length'];
905 $string_maxlength = "";
906 // if max_length is set to zero, then do not set a maxlength
907 if ($maxlength) {
908 $string_maxlength = "maxlength='" . attr($maxlength) . "'";
910 // Edit option E means allow multiple (Extra) billing codes in a field.
911 // We invent a class name for this because JavaScript needs to know.
912 $className = '';
913 if (strpos($frow['edit_options'], 'E') !== false) {
914 $className = 'EditOptionE';
917 if (isOption($edit_options, '2') !== false) {
918 // Option "2" generates a hidden input for the codes, and a matching visible field
919 // displaying their descriptions. First step is computing the description string.
920 $currdescstring = '';
921 if (!empty($currvalue)) {
922 $relcodes = explode(';', $currvalue);
923 foreach ($relcodes as $codestring) {
924 if ($codestring === '') {
925 continue;
927 if ($currdescstring !== '') {
928 $currdescstring .= '; ';
930 $currdescstring .= getCodeDescription($codestring, $codetype);
934 $currdescstring = attr($currdescstring);
936 echo "<div>"; // wrapper for myHideOrShow()
937 echo "<input type='text'" .
938 " name='form_$field_id_esc'" .
939 " id='form_related_code'" .
940 " class='" . attr($className) . "'" .
941 " size='$fldlength'" .
942 " value='$currescaped'" .
943 " style='display:none'" .
944 " $lbfonchange readonly $disabled />";
945 // Extra readonly input field for optional display of code description(s).
946 echo "<input type='text'" .
947 " name='form_$field_id_esc" . "__desc'" .
948 " size='$fldlength'" .
949 " title='$description'" .
950 " value='$currdescstring'";
951 if (!$disabled) {
952 echo " onclick='sel_related(this," . attr_js($codetype) . ")'";
955 echo "class='form-control$smallform'";
956 echo " readonly $disabled />";
957 echo "</div>";
958 } else {
959 echo "<input type='text'" .
960 " name='form_$field_id_esc'" .
961 " id='form_related_code'" .
962 " class='" . attr($className) . "'" .
963 " size='$fldlength'" .
964 " $string_maxlength" .
965 " title='$description'" .
966 " value='$currescaped'";
967 if (!$disabled) {
968 echo " onclick='sel_related(this," . attr_js($codetype) . ")'";
971 echo "class='form-control$smallform'";
972 echo " $lbfonchange readonly $disabled />";
974 } elseif ($data_type == 16) { // insurance company list
975 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' class='form-control$smallform' title='$description'>";
976 echo "<option value='0'></option>";
977 $insprovs = getInsuranceProviders();
978 $got_selected = false;
979 foreach ($insprovs as $key => $ipname) {
980 $optionValue = htmlspecialchars($key, ENT_QUOTES);
981 $optionLabel = htmlspecialchars($ipname, ENT_NOQUOTES);
982 echo "<option value='$optionValue'";
983 if ($currvalue == $key) {
984 echo " selected";
985 $got_selected = true;
988 echo ">$optionLabel</option>";
991 if (!$got_selected && $currvalue) {
992 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
993 echo "</select>";
994 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
995 } else {
996 echo "</select>";
998 } elseif ($data_type == 17) { // issue types
999 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' class='form-control$smallform' title='$description'>";
1000 echo "<option value='0'></option>";
1001 $got_selected = false;
1002 foreach ($ISSUE_TYPES as $key => $value) {
1003 $optionValue = htmlspecialchars($key, ENT_QUOTES);
1004 $optionLabel = htmlspecialchars($value[1], ENT_NOQUOTES);
1005 echo "<option value='$optionValue'";
1006 if ($currvalue == $key) {
1007 echo " selected";
1008 $got_selected = true;
1011 echo ">$optionLabel</option>";
1014 if (!$got_selected && strlen($currvalue) > 0) {
1015 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
1016 echo "</select>";
1017 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
1018 } else {
1019 echo "</select>";
1021 } elseif ($data_type == 18) { // Visit categories.
1022 $cres = sqlStatement("SELECT pc_catid, pc_catname " .
1023 "FROM openemr_postcalendar_categories ORDER BY pc_catname");
1024 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' class='form-control$smallform' title='$description'" . " $lbfonchange $disabled>";
1025 echo "<option value=''>" . xlt($empty_title) . "</option>";
1026 $got_selected = false;
1027 while ($crow = sqlFetchArray($cres)) {
1028 $catid = $crow['pc_catid'];
1029 if (($catid < 9 && $catid != 5) || $catid == 11) {
1030 continue;
1033 echo "<option value='" . attr($catid) . "'";
1034 if ($catid == $currvalue) {
1035 echo " selected";
1036 $got_selected = true;
1039 echo ">" . text(xl_appt_category($crow['pc_catname'])) . "</option>";
1042 if (!$got_selected && $currvalue) {
1043 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
1044 echo "</select>";
1045 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
1046 } else {
1047 echo "</select>";
1049 } elseif ($data_type == 21) { // a set of labeled checkboxes
1050 // If no list then it's a single checkbox and its value is "Yes" or empty.
1051 if (!$list_id) {
1052 echo "<input type='checkbox' name='form_{$field_id_esc}' " .
1053 "id='form_{$field_id_esc}' value='Yes' $lbfonchange";
1054 if ($currvalue) {
1055 echo " checked";
1057 echo " $disabled />";
1058 } else {
1059 // In this special case, fld_length is the number of columns generated.
1060 $cols = max(1, $frow['fld_length']);
1061 $avalue = explode('|', $currvalue);
1062 $lres = sqlStatement("SELECT * FROM list_options " .
1063 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
1064 echo "<table class='w-100' cellpadding='0' cellspacing='0' title='" . attr($description) . "'>";
1065 $tdpct = (int) (100 / $cols);
1066 for ($count = 0; $lrow = sqlFetchArray($lres); ++$count) {
1067 $option_id = $lrow['option_id'];
1068 $option_id_esc = htmlspecialchars($option_id, ENT_QUOTES);
1069 // if ($count) echo "<br />";
1070 if ($count % $cols == 0) {
1071 if ($count) {
1072 echo "</tr>";
1074 echo "<tr>";
1076 echo "<td width='" . attr($tdpct) . "%' nowrap>";
1077 echo "<input type='checkbox' name='form_{$field_id_esc}[$option_id_esc]'" .
1078 "id='form_{$field_id_esc}[$option_id_esc]' class='form-check-inline' value='1' $lbfonchange";
1079 if (in_array($option_id, $avalue)) {
1080 echo " checked";
1082 // Added 5-09 by BM - Translate label if applicable
1083 echo " $disabled />" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES);
1084 echo "</td>";
1086 if ($count) {
1087 echo "</tr>";
1088 if ($count > $cols) {
1089 // Add some space after multiple rows of checkboxes.
1090 $cols = htmlspecialchars($cols, ENT_QUOTES);
1091 echo "<tr><td colspan='$cols' style='height:0.7rem'></td></tr>";
1094 echo "</table>";
1096 } elseif ($data_type == 22) { // a set of labeled text input fields
1097 $tmp = explode('|', $currvalue);
1098 $avalue = array();
1099 foreach ($tmp as $value) {
1100 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
1101 $avalue[$matches[1]] = $matches[2];
1105 $lres = sqlStatement("SELECT * FROM list_options " .
1106 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
1107 echo "<table class='table'>";
1108 while ($lrow = sqlFetchArray($lres)) {
1109 $option_id = $lrow['option_id'];
1110 $option_id_esc = htmlspecialchars($option_id, ENT_QUOTES);
1111 $maxlength = $frow['max_length'];
1112 $string_maxlength = "";
1113 // if max_length is set to zero, then do not set a maxlength
1114 if ($maxlength) {
1115 $string_maxlength = "maxlength='" . attr($maxlength) . "'";
1118 $fldlength = empty($frow['fld_length']) ? 20 : $frow['fld_length'];
1120 // Added 5-09 by BM - Translate label if applicable
1121 echo "<tr><td>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES) . "&nbsp;</td>";
1122 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES);
1123 $optionValue = htmlspecialchars($avalue[$option_id], ENT_QUOTES);
1124 echo "<td><input type='text'" .
1125 " name='form_{$field_id_esc}[$option_id_esc]'" .
1126 " id='form_{$field_id_esc}[$option_id_esc]'" .
1127 " size='$fldlength'" .
1128 $placeholder .
1129 " class='form-control$smallform'" .
1130 " $string_maxlength" .
1131 " value='$optionValue'";
1132 echo " $lbfonchange $disabled /></td></tr>";
1135 echo "</table>";
1136 } elseif ($data_type == 23) { // a set of exam results; 3 radio buttons and a text field:
1137 $tmp = explode('|', $currvalue);
1138 $avalue = array();
1139 foreach ($tmp as $value) {
1140 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
1141 $avalue[$matches[1]] = $matches[2];
1145 $maxlength = $frow['max_length'];
1146 $string_maxlength = "";
1147 // if max_length is set to zero, then do not set a maxlength
1148 if ($maxlength) {
1149 $string_maxlength = "maxlength='" . attr($maxlength) . "'";
1152 $fldlength = empty($frow['fld_length']) ? 20 : $frow['fld_length'];
1153 $lres = sqlStatement("SELECT * FROM list_options " .
1154 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
1155 echo "<table class='table'>";
1156 echo "<tr><td class='font-weight-bold'>" . htmlspecialchars(xl('Exam or Test'), ENT_NOQUOTES) .
1157 "</td><td class='font-weight-bold'>" . htmlspecialchars(xl('N/A'), ENT_NOQUOTES) .
1158 "&nbsp;</td><td class='font-weight-bold'>" .
1159 htmlspecialchars(xl('Nor'), ENT_NOQUOTES) . "&nbsp;</td>" .
1160 "<td class='font-weight-bold'>" .
1161 htmlspecialchars(xl('Abn'), ENT_NOQUOTES) . "&nbsp;</td><td class='font-weight-bold'>" .
1162 htmlspecialchars(xl('Date/Notes'), ENT_NOQUOTES) . "</td></tr>";
1163 while ($lrow = sqlFetchArray($lres)) {
1164 $option_id = $lrow['option_id'];
1165 $option_id_esc = htmlspecialchars($option_id, ENT_QUOTES);
1166 $restype = substr(($avalue[$option_id] ?? ''), 0, 1);
1167 $resnote = substr(($avalue[$option_id] ?? ''), 2);
1169 // Added 5-09 by BM - Translate label if applicable
1170 echo "<tr><td>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES) . "&nbsp;</td>";
1172 for ($i = 0; $i < 3; ++$i) {
1173 $inputValue = htmlspecialchars($i, ENT_QUOTES);
1174 echo "<td><input type='radio'" .
1175 " name='radio_{$field_id_esc}[$option_id_esc]'" .
1176 " id='radio_{$field_id_esc}[$option_id_esc]'" .
1177 " value='$inputValue' $lbfonchange";
1178 if ($restype === "$i") {
1179 echo " checked";
1182 echo " $disabled /></td>";
1185 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES);
1186 $resnote = htmlspecialchars($resnote, ENT_QUOTES);
1187 echo "<td><input type='text'" .
1188 " name='form_{$field_id_esc}[$option_id_esc]'" .
1189 " id='form_{$field_id_esc}[$option_id_esc]'" .
1190 " size='$fldlength'" .
1191 " class='form-control'" .
1192 " $string_maxlength" .
1193 " value='$resnote' $disabled /></td>";
1194 echo "</tr>";
1197 echo "</table>";
1198 } elseif ($data_type == 24) { // the list of active allergies for the current patient
1199 // this is read-only!
1200 $query = "SELECT title, comments FROM lists WHERE " .
1201 "pid = ? AND type = 'allergy' AND enddate IS NULL " .
1202 "ORDER BY begdate";
1203 // echo "<!-- $query -->\n"; // debugging
1204 $lres = sqlStatement($query, array($GLOBALS['pid']));
1205 $count = 0;
1206 while ($lrow = sqlFetchArray($lres)) {
1207 if ($count++) {
1208 echo "<br />";
1211 echo htmlspecialchars($lrow['title'], ENT_NOQUOTES);
1212 if ($lrow['comments']) {
1213 echo ' (' . htmlspecialchars($lrow['comments'], ENT_NOQUOTES) . ')';
1216 } elseif ($data_type == 25) { // a set of labeled checkboxes, each with a text field:
1217 $tmp = explode('|', $currvalue);
1218 $avalue = array();
1219 foreach ($tmp as $value) {
1220 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
1221 $avalue[$matches[1]] = $matches[2];
1225 $maxlength = $frow['max_length'];
1226 $string_maxlength = "";
1227 // if max_length is set to zero, then do not set a maxlength
1228 if ($maxlength) {
1229 $string_maxlength = "maxlength='" . attr($maxlength) . "'";
1232 $fldlength = empty($frow['fld_length']) ? 20 : $frow['fld_length'];
1233 $lres = sqlStatement("SELECT * FROM list_options " .
1234 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
1235 echo "<table class='table'>";
1236 while ($lrow = sqlFetchArray($lres)) {
1237 $option_id = $lrow['option_id'];
1238 $option_id_esc = htmlspecialchars($option_id, ENT_QUOTES);
1239 $restype = substr($avalue[$option_id], 0, 1);
1240 $resnote = substr($avalue[$option_id], 2);
1242 // Added 5-09 by BM - Translate label if applicable
1243 echo "<tr><td>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES) . "&nbsp;</td>";
1245 $option_id = htmlspecialchars($option_id, ENT_QUOTES);
1246 echo "<td><input type='checkbox' name='check_{$field_id_esc}[$option_id_esc]'" .
1247 " id='check_{$field_id_esc}[$option_id_esc]' class='form-check-inline' value='1' $lbfonchange";
1248 if ($restype) {
1249 echo " checked";
1252 echo " $disabled />&nbsp;</td>";
1253 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES);
1254 $resnote = htmlspecialchars($resnote, ENT_QUOTES);
1255 echo "<td><input type='text'" .
1256 " name='form_{$field_id_esc}[$option_id_esc]'" .
1257 " id='form_{$field_id_esc}[$option_id_esc]'" .
1258 " size='$fldlength'" .
1259 " class='form-control$smallform' " .
1260 " $string_maxlength" .
1261 " value='$resnote' $disabled /></td>";
1262 echo "</tr>";
1265 echo "</table>";
1266 } elseif ($data_type == 26) { // single-selection list with ability to add to it
1267 echo "<div class='input-group'>";
1268 echo generate_select_list(
1269 "form_$field_id",
1270 $list_id,
1271 $currvalue,
1272 $description,
1273 ($showEmpty ? $empty_title : ''),
1274 'addtolistclass_' . $list_id . $smallform,
1275 $lbfchange,
1277 ($disabled ? array('disabled' => 'disabled') : null),
1278 false,
1279 $backup_list
1281 // show the add button if user has access to correct list
1282 $inputValue = htmlspecialchars(xl('Add'), ENT_QUOTES);
1283 $btnSize = ($smallform) ? "btn-sm" : "";
1284 $outputAddButton = "<div class='input-group-append'><input type='button' class='btn btn-secondary $btnSize mb-1 addtolist' id='addtolistid_" . $list_id_esc . "' fieldid='form_" .
1285 $field_id_esc . "' value='$inputValue' $disabled /></div>";
1286 if (AclExtended::acoExist('lists', $list_id)) {
1287 // a specific aco exist for this list, so ensure access
1288 if (AclMain::aclCheckCore('lists', $list_id)) {
1289 echo $outputAddButton;
1291 } else {
1292 // no specific aco exist for this list, so check for access to 'default' list
1293 if (AclMain::aclCheckCore('lists', 'default')) {
1294 echo $outputAddButton;
1297 echo "</div>";
1298 } elseif ($data_type == 27) { // a set of labeled radio buttons
1299 // In this special case, fld_length is the number of columns generated.
1300 $cols = max(1, $frow['fld_length']);
1301 // Support for edit option M.
1302 if (isOption($edit_options, 'M')) {
1303 ++$membership_group_number;
1306 $lres = sqlStatement("SELECT * FROM list_options " .
1307 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
1308 echo "<table class='table w-100'>";
1309 $tdpct = (int) (100 / $cols);
1310 $got_selected = false;
1311 for ($count = 0; $lrow = sqlFetchArray($lres); ++$count) {
1312 $option_id = $lrow['option_id'];
1313 $option_id_esc = htmlspecialchars($option_id, ENT_QUOTES);
1314 if ($count % $cols == 0) {
1315 if ($count) {
1316 echo "</tr>";
1318 echo "<tr>";
1320 echo "<td width='" . attr($tdpct) . "%' nowrap>";
1321 echo "<input type='radio' name='form_{$field_id_esc}' id='form_{$field_id_esc}[$option_id_esc]'" .
1322 " value='$option_id_esc' $lbfonchange";
1323 // Support for edit options M and m.
1324 if (isOption($edit_options, 'M')) {
1325 echo " class='form-check-inline'";
1326 echo " onclick='checkGroupMembers(this, $membership_group_number);'";
1327 } elseif (isOption($edit_options, 'm')) {
1328 echo " class='form-check-inline lbf_memgroup_$membership_group_number'";
1329 } else {
1330 echo " class='form-check-inline'";
1333 if (
1334 (strlen($currvalue) == 0 && $lrow['is_default']) ||
1335 (strlen($currvalue) > 0 && $option_id == $currvalue)
1337 echo " checked";
1338 $got_selected = true;
1340 echo " $disabled />" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES);
1341 echo "</td>";
1344 if ($count) {
1345 echo "</tr>";
1346 if ($count > $cols) {
1347 // Add some space after multiple rows of radio buttons.
1348 $cols = htmlspecialchars($cols, ENT_QUOTES);
1349 echo "<tr><td colspan='$cols' style='height: 0.7rem'></td></tr>";
1353 echo "</table>";
1354 if (!$got_selected && strlen($currvalue) > 0) {
1355 $fontTitle = htmlspecialchars(xl('Please choose a valid selection.'), ENT_QUOTES);
1356 $fontText = htmlspecialchars(xl('Fix this'), ENT_NOQUOTES);
1357 echo "$currescaped <span class='text-danger' title='$fontTitle'>$fontText!</span>";
1359 } elseif ($data_type == 28 || $data_type == 32) { // special case for history of lifestyle status; 3 radio buttons
1360 // and a date text field:
1361 // VicarePlus :: A selection list box for smoking status:
1362 $tmp = explode('|', $currvalue);
1363 switch (count($tmp)) {
1364 case "4":
1365 $resnote = $tmp[0];
1366 $restype = $tmp[1];
1367 $resdate = oeFormatShortDate($tmp[2]);
1368 $reslist = $tmp[3];
1369 break;
1370 case "3":
1371 $resnote = $tmp[0];
1372 $restype = $tmp[1];
1373 $resdate = oeFormatShortDate($tmp[2]);
1374 $reslist = '';
1375 break;
1376 case "2":
1377 $resnote = $tmp[0];
1378 $restype = $tmp[1];
1379 $resdate = "";
1380 $reslist = '';
1381 break;
1382 case "1":
1383 $resnote = $tmp[0];
1384 $resdate = $restype = "";
1385 $reslist = '';
1386 break;
1387 default:
1388 $restype = $resdate = $resnote = "";
1389 $reslist = '';
1390 break;
1393 $maxlength = $frow['max_length'];
1394 $string_maxlength = "";
1395 // if max_length is set to zero, then do not set a maxlength
1396 if ($maxlength) {
1397 $string_maxlength = "maxlength='" . attr($maxlength) . "'";
1400 $fldlength = empty($frow['fld_length']) ? 20 : $frow['fld_length'];
1402 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES);
1403 $resnote = htmlspecialchars($resnote, ENT_QUOTES);
1404 $resdate = htmlspecialchars($resdate, ENT_QUOTES);
1405 echo "<table class='table'>";
1406 echo "<tr>";
1407 if ($data_type == 28) {
1408 // input text
1409 echo "<td><input type='text' class='form-control'" .
1410 " name='form_$field_id_esc'" .
1411 " id='form_$field_id_esc'" .
1412 " size='$fldlength'" .
1413 " class='form-control$smallform'" .
1414 " $string_maxlength" .
1415 " value='$resnote' $disabled />&nbsp;</td>";
1416 echo "<td class='font-weight-bold'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" .
1417 "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" .
1418 htmlspecialchars(xl('Status'), ENT_NOQUOTES) . ":&nbsp;&nbsp;</td>";
1419 } elseif ($data_type == 32) {
1420 // input text
1421 echo "<tr><td><input type='text'" .
1422 " name='form_text_$field_id_esc'" .
1423 " id='form_text_$field_id_esc'" .
1424 " size='$fldlength'" .
1425 " class='form-control$smallform'" .
1426 " $string_maxlength" .
1427 " value='$resnote' $disabled />&nbsp;</td></tr>";
1428 echo "<td>";
1429 //Selection list for smoking status
1430 $onchange = 'radioChange(this.options[this.selectedIndex].value)';//VicarePlus :: The javascript function for selection list.
1431 echo generate_select_list(
1432 "form_$field_id",
1433 $list_id,
1434 $reslist,
1435 $description,
1436 ($showEmpty ? $empty_title : ''),
1437 $smallform,
1438 $onchange,
1440 ($disabled ? array('disabled' => 'disabled') : null)
1442 echo "</td>";
1443 echo "<td class='font-weight-bold'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" . xlt('Status') . ":&nbsp;&nbsp;</td>";
1446 // current
1447 echo "<td class='text'><input type='radio'" .
1448 " name='radio_{$field_id_esc}'" .
1449 " id='radio_{$field_id_esc}[current]'" .
1450 " class='form-check-inline'" .
1451 " value='current" . $field_id_esc . "' $lbfonchange";
1452 if ($restype == "current" . $field_id) {
1453 echo " checked";
1456 if ($data_type == 32) {
1457 echo " onClick='smoking_statusClicked(this)'";
1460 echo " />" . xlt('Current') . "&nbsp;</td>";
1461 // quit
1462 echo "<td class='text'><input type='radio'" .
1463 " name='radio_{$field_id_esc}'" .
1464 " id='radio_{$field_id_esc}[quit]'" .
1465 " class='form-check-inline'" .
1466 " value='quit" . $field_id_esc . "' $lbfonchange";
1467 if ($restype == "quit" . $field_id) {
1468 echo " checked";
1471 if ($data_type == 32) {
1472 echo " onClick='smoking_statusClicked(this)'";
1475 echo " $disabled />" . xlt('Quit') . "&nbsp;</td>";
1476 // quit date
1477 echo "<td class='text'><input type='text' size='6' class='form-control datepicker' name='date_$field_id_esc' id='date_$field_id_esc'" .
1478 " value='$resdate'" .
1479 " title='$description'" .
1480 " $disabled />";
1481 echo "&nbsp;</td>";
1482 // never
1483 echo "<td class='text'><input type='radio'" .
1484 " name='radio_{$field_id_esc}'" .
1485 " class='form-check-inline'" .
1486 " id='radio_{$field_id_esc}[never]'" .
1487 " value='never" . $field_id_esc . "' $lbfonchange";
1488 if ($restype == "never" . $field_id) {
1489 echo " checked";
1492 if ($data_type == 32) {
1493 echo " onClick='smoking_statusClicked(this)'";
1496 echo " />" . xlt('Never') . "&nbsp;</td>";
1497 // Not Applicable
1498 echo "<td class='text'><input type='radio'" .
1499 " class='form-check-inline' " .
1500 " name='radio_{$field_id}'" .
1501 " id='radio_{$field_id}[not_applicable]'" .
1502 " value='not_applicable" . $field_id . "' $lbfonchange";
1503 if ($restype == "not_applicable" . $field_id) {
1504 echo " checked";
1507 if ($data_type == 32) {
1508 echo " onClick='smoking_statusClicked(this)'";
1511 echo " $disabled />" . xlt('N/A') . "&nbsp;</td>";
1513 //Added on 5-jun-2k14 (regarding 'Smoking Status - display SNOMED code description')
1514 echo "<td class='text'><div id='smoke_code'></div></td>";
1515 echo "</tr>";
1516 echo "</table>";
1517 } elseif ($data_type == 31) { // static text. read-only, of course.
1518 echo parse_static_text($frow);
1519 } elseif ($data_type == 34) {
1520 // $data_type == 33
1521 // Race and Ethnicity. After added support for backup lists, this is now the same as datatype 36; so have migrated it there.
1522 // $data_type == 33
1524 $arr = explode("|*|*|*|", $currvalue);
1525 echo "<div>"; // wrapper for myHideOrShow()
1526 echo "<a href='../../../library/custom_template/custom_template.php?type=form_{$field_id}&contextName=" . htmlspecialchars($list_id_esc, ENT_QUOTES) . "' class='iframe_medium text-body text-decoration-none'>";
1527 echo "<div id='form_{$field_id}_div' class='text-area' style='min-width: 133px'>" . $arr[0] . "</div>";
1528 echo "<div style='display: none'><textarea name='form_{$field_id}' id='form_{$field_id}' class='form-control$smallform' style='display: none' $lbfonchange $disabled>" . $currvalue . "</textarea></div>";
1529 echo "</a>";
1530 echo "</div>";
1531 } elseif ($data_type == 35) { //facilities drop-down list
1532 if (empty($currvalue)) {
1533 $currvalue = 0;
1536 dropdown_facility(
1537 $selected = $currvalue,
1538 $name = "form_$field_id_esc",
1539 $allow_unspecified = true,
1540 $allow_allfacilities = false,
1541 $disabled,
1542 $lbfchange,
1543 false,
1544 $smallform
1546 } elseif ($data_type == 36 || $data_type == 33) { //multiple select, supports backup list
1547 echo generate_select_list(
1548 "form_$field_id",
1549 $list_id,
1550 $currvalue,
1551 $description,
1552 $showEmpty ? $empty_title : '',
1553 $smallform,
1554 $lbfchange,
1556 null,
1557 true,
1558 $backup_list
1561 // A set of lab test results; Gestation, 3 radio buttons, test value, notes field:
1562 } elseif ($data_type == 37) {
1563 echo genLabResults($frow, $currvalue, 0, $disabled);
1564 } elseif ($data_type == 40) { // Canvas and related elements for browser-side image drawing.
1565 // Note you must invoke lbf_canvas_head() (below) to use this field type in a form.
1566 // Unlike other field types, width and height are in pixels.
1567 $canWidth = intval($frow['fld_length']);
1568 $canHeight = intval($frow['fld_rows']);
1569 if (empty($currvalue)) {
1570 if (preg_match('/\\bimage=([a-zA-Z0-9._-]*)/', $frow['description'], $matches)) {
1571 // If defined this is the filename of the default starting image.
1572 $currvalue = $GLOBALS['web_root'] . '/sites/' . $_SESSION['site_id'] . '/images/' . $matches[1];
1575 $mywidth = 50 + ($canWidth > 250 ? $canWidth : 250);
1576 $myheight = 31 + ($canHeight > 261 ? $canHeight : 261);
1577 echo "<div>"; // wrapper for myHideOrShow()
1578 echo "<div id='form_$field_id_esc' style='width:{$mywidth}px; height:{$myheight}px;'></div>";
1579 // Hidden form field exists to send updated data to the server at submit time.
1580 echo "<input type='hidden' name='form_$field_id_esc' value='' />";
1581 // Hidden image exists to support initialization of the canvas.
1582 echo "<img src='" . attr($currvalue) . "' id='form_{$field_id_esc}_img' style='display:none'>";
1583 echo "</div>";
1584 // $date_init is a misnomer but it's the place for browser-side setup logic.
1585 $date_init .= " lbfCanvasSetup('form_$field_id_esc', $canWidth, $canHeight);\n";
1586 } elseif ($data_type == 41 || $data_type == 42) {
1587 $datatype = 'patient-signature';
1588 $cpid = $GLOBALS['pid'];
1589 $cuser = $_SESSION['authUserID'];
1590 if ($data_type == 42) {
1591 $datatype = 'admin-signature';
1593 echo "<input type='hidden' id='form_$field_id_esc' name='form_$field_id_esc' value='' />\n";
1594 echo "<img class='signature' id='form_{$field_id_esc}_img' title='$description'
1595 data-pid='$cpid' data-user='$cuser' data-type='$datatype'
1596 data-action='fetch_signature' alt='Get Signature' src='" . attr($currvalue) . "'>\n";
1597 } elseif ($data_type == 44) { //multiple select facility
1598 if (empty($currvalue)) {
1599 $currvalue = 0;
1602 dropdown_facility(
1603 $selected = $currvalue,
1604 $name = "form_$field_id_esc",
1605 $allow_unspecified = false,
1606 $allow_allfacilities = false,
1607 $disabled,
1608 $lbfchange,
1609 true,
1610 $smallform
1612 } elseif ($data_type == 45) { // Multiple provider list, local providers only
1613 $ures = sqlStatement("SELECT id, fname, lname, specialty FROM users " .
1614 "WHERE active = 1 AND ( info IS NULL OR info NOT LIKE '%Inactive%' ) " .
1615 "AND authorized = 1 ORDER BY lname, fname");
1616 echo "<select name='form_$field_id_esc" . "[]'" . " id='form_$field_id_esc' title='$description' $lbfonchange $disabled class='form-control$smallform select-dropdown' style='width:100%;' multiple='multiple'>";
1617 $got_selected = false;
1618 while ($urow = sqlFetchArray($ures)) {
1619 $uname = text($urow['fname'] . ' ' . $urow['lname']);
1620 $optionId = attr($urow['id']);
1621 echo "<option value='$optionId'";
1622 $selectedValues = explode("|", $currvalue);
1624 if (in_array($optionId, $selectedValues)) {
1625 echo " selected";
1626 $got_selected = true;
1629 echo ">$uname</option>";
1632 if (!$got_selected && $currvalue) {
1633 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
1634 echo "</select>";
1635 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
1636 } else {
1637 echo "</select>";
1640 // Patient selector field.
1641 } elseif ($data_type == 51) {
1642 $fldlength = attr($frow['fld_length']);
1643 $currdescstring = '';
1644 if (!empty($currvalue)) {
1645 $currdescstring .= getPatientDescription($currvalue);
1647 $currdescstring = htmlspecialchars($currdescstring, ENT_QUOTES);
1648 echo "<div>"; // wrapper for myHideOrShow()
1649 echo "<input type='text'" .
1650 " name='form_$field_id_esc'" .
1651 " size='$fldlength'" .
1652 " value='$currescaped'" .
1653 " style='display:none'" .
1654 " $lbfonchange readonly $disabled />";
1655 // Extra readonly input field for patient description (name and pid).
1656 echo "<input type='text'" .
1657 " name='form_$field_id_esc" . "__desc'" .
1658 " size='$fldlength'" .
1659 " title='$description'" .
1660 " value='$currdescstring'";
1661 if (!$disabled) {
1662 echo " onclick='sel_patient(this, this.form.form_$field_id_esc)'";
1664 echo " readonly $disabled />";
1665 echo "</div>";
1666 // Previous Patient Names with add. Somewhat mirrors data types 44,45.
1667 } elseif ($data_type == 52) {
1668 global $pid;
1669 $pid = ($frow['blank_form'] ?? null) ? 0 : $pid;
1670 $patientService = new PatientService();
1671 $res = $patientService->getPatientNameHistory($pid);
1672 echo "<div class='input-group w-75'>";
1673 echo "<select name='form_$field_id_esc" . "[]'" . " id='form_$field_id_esc' title='$description' $lbfonchange $disabled class='form-control$smallform select-previous-names' multiple='multiple'>";
1674 foreach ($res as $row) {
1675 $pname = $row['formatted_name']; // esc'ed in fetch.
1676 $optionId = attr($row['id']);
1677 // all names always selected
1678 echo "<option value='$optionId'" . " selected>$pname</option>";
1680 echo "</select>";
1681 echo "<button type='button' class='btn btn-primary btn-sm' id='type_52_add' onclick='return specialtyFormDialog()'>" . xlt('Add') . "</button></div>";
1682 // Patient Encounter List Field
1683 } elseif ($data_type == 53) {
1684 global $pid;
1685 $pid = ($frow['blank_form'] ?? null) ? 0 : $pid;
1686 $encounterService = new EncounterService();
1687 $res = $encounterService->getEncountersForPatientByPid($pid);
1688 echo "<div class='input-group w-75'>";
1689 echo "<select name='form_$field_id_esc'" . " id='form_$field_id_esc' title='$description' $lbfonchange $disabled class='form-control$smallform select-encounters'>";
1690 echo "<option value=''>" . xlt("Select Encounter") . "</option>";
1691 foreach ($res as $row) {
1692 $label = text(date("Y-m-d", strtotime($row['date'])) . " " . ($row['pc_catname'] ?? ''));
1693 $optionId = attr($row['eid']);
1694 // all names always selected
1695 if ($currvalue == $row['eid']) {
1696 echo "<option value='$optionId'" . " selected>$label</option>";
1697 } else {
1698 echo "<option value='$optionId'>$label</option>";
1701 echo "</select>";
1702 } elseif ($data_type == 54) {
1703 include "templates/address_list_form.php";
1707 function generate_print_field($frow, $currvalue, $value_allowed = true)
1709 global $rootdir, $date_init, $ISSUE_TYPES;
1711 $currescaped = htmlspecialchars($currvalue, ENT_QUOTES);
1713 $data_type = $frow['data_type'];
1714 $field_id = $frow['field_id'] ?? null;
1715 $list_id = $frow['list_id'];
1716 $fld_length = $frow['fld_length'] ?? null;
1717 $backup_list = $frow['list_backup_id'] ?? null;
1719 $description = attr(xl_layout_label($frow['description'] ?? ''));
1721 // Can pass $frow['empty_title'] with this variable, otherwise
1722 // will default to 'Unassigned'.
1723 // If it is 'SKIP' then an empty text title is completely skipped.
1724 $showEmpty = true;
1725 if (isset($frow['empty_title'])) {
1726 if ($frow['empty_title'] == "SKIP") {
1727 //do not display an 'empty' choice
1728 $showEmpty = false;
1729 $empty_title = "Unassigned";
1730 } else {
1731 $empty_title = $frow['empty_title'];
1733 } else {
1734 $empty_title = "Unassigned";
1737 // generic single-selection list
1738 // Supports backup lists.
1739 // if (false && ($data_type == 1 || $data_type == 26 || $data_type == 33 || $data_type == 43 || $data_type == 46)) {
1740 // We used to show all the list options but this was undone per CV request 2017-12-07
1741 // (see alternative code below).
1742 if ($data_type == 1 || $data_type == 26 || $data_type == 33 || $data_type == 43 || $data_type == 46) {
1743 if (empty($fld_length)) {
1744 if ($list_id == 'titles') {
1745 $fld_length = 3;
1746 } else {
1747 $fld_length = 10;
1751 $tmp = '';
1752 if ($currvalue) {
1753 if ($data_type == 46) {
1754 // support for single-selection list with comment support
1755 $selectedValues = explode("|", $currvalue);
1756 $currvalue = $selectedValues[0];
1758 $lrow = sqlQuery(
1759 "SELECT title FROM list_options " .
1760 "WHERE list_id = ? AND option_id = ? AND activity = 1",
1761 array($list_id,$currvalue)
1763 // For lists Race and Ethnicity if there is no matching value in the corresponding lists check ethrace list
1764 if (empty($lrow) && $data_type == 33) {
1765 $lrow = sqlQuery(
1766 "SELECT title FROM list_options " .
1767 "WHERE list_id = ? AND option_id = ? AND activity = 1",
1768 array('ethrace', $currvalue)
1772 $tmp = xl_list_label($lrow['title']);
1773 if ($lrow == 0 && !empty($backup_list)) {
1774 // since primary list did not map, try to map to backup list
1775 $lrow = sqlQuery("SELECT title FROM list_options " .
1776 "WHERE list_id = ? AND option_id = ?", array($backup_list,$currvalue));
1777 $tmp = xl_list_label($lrow['title']);
1780 if (empty($tmp)) {
1781 $tmp = "($currvalue)";
1784 if ($data_type == 46) {
1785 // support for single-selection list with comment support
1786 $resnote = $selectedValues[1] ?? null;
1787 if (!empty($resnote)) {
1788 $tmp .= " (" . $resnote . ")";
1793 if ($tmp === '') {
1794 $tmp = '&nbsp;';
1795 } else {
1796 $tmp = htmlspecialchars($tmp, ENT_QUOTES);
1798 echo $tmp;
1799 } elseif ($data_type == 2 || $data_type == 15) { // simple text field
1800 if ($currescaped === '') {
1801 $currescaped = '&nbsp;';
1804 echo $currescaped;
1805 } elseif ($data_type == 3) { // long or multi-line text field
1806 $fldlength = htmlspecialchars($fld_length, ENT_QUOTES);
1807 $maxlength = htmlspecialchars($frow['fld_rows'], ENT_QUOTES);
1808 echo "<textarea" .
1809 " class='form-control' " .
1810 " cols='$fldlength'" .
1811 " rows='$maxlength'>" .
1812 $currescaped . "</textarea>";
1813 } elseif ($data_type == 4) { // date
1814 $age_asof_date = '';
1815 $agestr = optionalAge($frow, $currvalue, $age_asof_date, $description);
1816 if ($currvalue === '') {
1817 echo '&nbsp;';
1818 } else {
1819 $modtmp = isOption($frow['edit_options'], 'F') === false ? 0 : 1;
1820 if (!$modtmp) {
1821 echo text(oeFormatShortDate($currvalue));
1822 } else {
1823 echo text(oeFormatDateTime($currvalue));
1825 if ($agestr) {
1826 echo "&nbsp;(" . text($agestr) . ")";
1829 } elseif ($data_type == 10 || $data_type == 11) { // provider list
1830 $tmp = '';
1831 if ($currvalue) {
1832 $urow = sqlQuery("SELECT fname, lname, specialty FROM users " .
1833 "WHERE id = ?", array($currvalue));
1834 $tmp = ucwords($urow['fname'] . " " . $urow['lname']);
1835 if (empty($tmp)) {
1836 $tmp = "($currvalue)";
1839 if ($tmp === '') {
1840 $tmp = '&nbsp;';
1841 } else {
1842 $tmp = htmlspecialchars($tmp, ENT_QUOTES);
1845 echo $tmp;
1846 } elseif ($data_type == 12) { // pharmacy list
1847 $tmp = '';
1848 if ($currvalue) {
1849 $pres = get_pharmacies();
1850 while ($prow = sqlFetchArray($pres)) {
1851 $key = $prow['id'];
1852 if ($currvalue == $key) {
1853 $tmp = $prow['name'] . ' ' . $prow['area_code'] . '-' .
1854 $prow['prefix'] . '-' . $prow['number'] . ' / ' .
1855 $prow['line1'] . ' / ' . $prow['city'];
1859 if (empty($tmp)) {
1860 $tmp = "($currvalue)";
1863 if ($tmp === '') {
1864 $tmp = '&nbsp;';
1865 } else {
1866 $tmp = htmlspecialchars($tmp, ENT_QUOTES);
1869 echo $tmp;
1870 } elseif ($data_type == 13) { // squads
1871 $tmp = '';
1872 if ($currvalue) {
1873 $squads = AclExtended::aclGetSquads();
1874 if ($squads) {
1875 foreach ($squads as $key => $value) {
1876 if ($currvalue == $key) {
1877 $tmp = $value[3];
1882 if (empty($tmp)) {
1883 $tmp = "($currvalue)";
1886 if ($tmp === '') {
1887 $tmp = '&nbsp;';
1888 } else {
1889 $tmp = htmlspecialchars($tmp, ENT_QUOTES);
1892 echo $tmp;
1893 } elseif ($data_type == 14) { // Address book.
1894 $tmp = '';
1895 if ($currvalue) {
1896 $urow = sqlQuery("SELECT fname, lname, specialty FROM users " .
1897 "WHERE id = ?", array($currvalue));
1898 $uname = $urow['lname'];
1899 if ($urow['fname']) {
1900 $uname .= ", " . $urow['fname'];
1903 $tmp = $uname;
1904 if (empty($tmp)) {
1905 $tmp = "($currvalue)";
1908 if ($tmp === '') {
1909 $tmp = '&nbsp;';
1910 } else {
1911 $tmp = htmlspecialchars($tmp, ENT_QUOTES);
1914 echo $tmp;
1915 } elseif ($data_type == 16) { // insurance company list
1916 $tmp = '';
1917 if ($currvalue) {
1918 $insprovs = getInsuranceProviders();
1919 foreach ($insprovs as $key => $ipname) {
1920 if ($currvalue == $key) {
1921 $tmp = $ipname;
1925 if (empty($tmp)) {
1926 $tmp = "($currvalue)";
1930 if ($tmp === '') {
1931 $tmp = '&nbsp;';
1932 } else {
1933 $tmp = htmlspecialchars($tmp, ENT_QUOTES);
1936 echo $tmp;
1937 } elseif ($data_type == 17) { // issue types
1938 $tmp = '';
1939 if ($currvalue) {
1940 foreach ($ISSUE_TYPES as $key => $value) {
1941 if ($currvalue == $key) {
1942 $tmp = $value[1];
1946 if (empty($tmp)) {
1947 $tmp = "($currvalue)";
1951 if ($tmp === '') {
1952 $tmp = '&nbsp;';
1953 } else {
1954 $tmp = htmlspecialchars($tmp, ENT_QUOTES);
1957 echo $tmp;
1958 } elseif ($data_type == 18) { // Visit categories.
1959 $tmp = '';
1960 if ($currvalue) {
1961 $crow = sqlQuery(
1962 "SELECT pc_catid, pc_catname " .
1963 "FROM openemr_postcalendar_categories WHERE pc_catid = ?",
1964 array($currvalue)
1966 $tmp = xl_appt_category($crow['pc_catname']);
1967 if (empty($tmp)) {
1968 $tmp = "($currvalue)";
1972 if ($tmp === '') {
1973 $tmp = '&nbsp;';
1974 } else {
1975 $tmp = htmlspecialchars($tmp, ENT_QUOTES);
1978 echo $tmp;
1979 } elseif ($data_type == 21) { // a single checkbox or set of labeled checkboxes
1980 if (!$list_id) {
1981 echo "<input type='checkbox'";
1982 if ($currvalue) {
1983 echo " checked";
1985 echo " />";
1986 } else {
1987 // In this special case, fld_length is the number of columns generated.
1988 $cols = max(1, $fld_length);
1989 $avalue = explode('|', $currvalue);
1990 $lres = sqlStatement("SELECT * FROM list_options " .
1991 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
1992 echo "<table class='w-100' cellpadding='0' cellspacing='0'>";
1993 $tdpct = (int) (100 / $cols);
1994 for ($count = 0; $lrow = sqlFetchArray($lres); ++$count) {
1995 $option_id = $lrow['option_id'];
1996 if ($count % $cols == 0) {
1997 if ($count) {
1998 echo "</tr>";
2001 echo "<tr>";
2003 echo "<td width='" . attr($tdpct) . "%' nowrap>";
2004 echo "<input type='checkbox'";
2005 if (in_array($option_id, $avalue)) {
2006 echo " checked";
2008 echo ">" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES);
2009 echo "</td>";
2011 if ($count) {
2012 echo "</tr>";
2013 if ($count > $cols) {
2014 // Add some space after multiple rows of checkboxes.
2015 $cols = htmlspecialchars($cols, ENT_QUOTES);
2016 echo "<tr><td colspan='$cols' style='height:0.7em'></td></tr>";
2019 echo "</table>";
2021 } elseif ($data_type == 22) { // a set of labeled text input fields
2022 $tmp = explode('|', $currvalue);
2023 $avalue = array();
2024 foreach ($tmp as $value) {
2025 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
2026 $avalue[$matches[1]] = $matches[2];
2030 $lres = sqlStatement("SELECT * FROM list_options " .
2031 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2032 echo "<table class='table'>";
2033 while ($lrow = sqlFetchArray($lres)) {
2034 $option_id = $lrow['option_id'];
2035 $fldlength = empty($fld_length) ? 20 : $fld_length;
2036 echo "<tr><td>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES) . "&nbsp;</td>";
2037 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES);
2038 $inputValue = htmlspecialchars($avalue[$option_id], ENT_QUOTES);
2039 echo "<td><input type='text'" .
2040 " class='form-control' " .
2041 " size='$fldlength'" .
2042 " value='$inputValue'" .
2043 " class='under'" .
2044 " /></td></tr>";
2047 echo "</table>";
2048 } elseif ($data_type == 23) { // a set of exam results; 3 radio buttons and a text field:
2049 $tmp = explode('|', $currvalue);
2050 $avalue = array();
2051 foreach ($tmp as $value) {
2052 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
2053 $avalue[$matches[1]] = $matches[2];
2057 $fldlength = empty($fld_length) ? 20 : $fld_length;
2058 $lres = sqlStatement("SELECT * FROM list_options " .
2059 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2060 echo "<table class='table'>";
2061 echo "<tr><td><td class='font-weight-bold'>" .
2062 htmlspecialchars(xl('Exam or Test'), ENT_NOQUOTES) . "</td><td class='font-weight-bold'>" .
2063 htmlspecialchars(xl('N/A'), ENT_NOQUOTES) .
2064 "&nbsp;</td><td class='font-weight-bold'>" .
2065 htmlspecialchars(xl('Nor'), ENT_NOQUOTES) . "&nbsp;</td>" .
2066 "<td class='font-weight-bold'>" .
2067 htmlspecialchars(xl('Abn'), ENT_NOQUOTES) . "&nbsp;</td><td class='font-weight-bold'>" .
2068 htmlspecialchars(xl('Date/Notes'), ENT_NOQUOTES) . "</td></tr>";
2069 while ($lrow = sqlFetchArray($lres)) {
2070 $option_id = $lrow['option_id'];
2071 $restype = substr($avalue[$option_id], 0, 1);
2072 $resnote = substr($avalue[$option_id], 2);
2073 echo "<tr><td>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES) . "&nbsp;</td>";
2074 for ($i = 0; $i < 3; ++$i) {
2075 echo "<td><input type='radio'";
2076 if ($restype === "$i") {
2077 echo " checked";
2080 echo " /></td>";
2083 $resnote = htmlspecialchars($resnote, ENT_QUOTES);
2084 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES);
2085 echo "<td><input type='text'" .
2086 " size='$fldlength'" .
2087 " value='$resnote'" .
2088 " class='under form-control' /></td>" .
2089 "</tr>";
2092 echo "</table>";
2093 } elseif ($data_type == 24) { // the list of active allergies for the current patient
2094 // this is read-only!
2095 $query = "SELECT title, comments FROM lists WHERE " .
2096 "pid = ? AND type = 'allergy' AND enddate IS NULL " .
2097 "ORDER BY begdate";
2098 $lres = sqlStatement($query, array($GLOBALS['pid']));
2099 $count = 0;
2100 while ($lrow = sqlFetchArray($lres)) {
2101 if ($count++) {
2102 echo "<br />";
2105 echo htmlspecialchars($lrow['title'], ENT_QUOTES);
2106 if ($lrow['comments']) {
2107 echo htmlspecialchars(' (' . $lrow['comments'] . ')', ENT_QUOTES);
2110 } elseif ($data_type == 25) { // a set of labeled checkboxes, each with a text field:
2111 $tmp = explode('|', $currvalue);
2112 $avalue = array();
2113 foreach ($tmp as $value) {
2114 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
2115 $avalue[$matches[1]] = $matches[2];
2119 $fldlength = empty($fld_length) ? 20 : $fld_length;
2120 $lres = sqlStatement("SELECT * FROM list_options " .
2121 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2122 echo "<table class='table'>";
2123 while ($lrow = sqlFetchArray($lres)) {
2124 $option_id = $lrow['option_id'];
2125 $restype = substr($avalue[$option_id], 0, 1);
2126 $resnote = substr($avalue[$option_id], 2);
2127 echo "<tr><td>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES) . "&nbsp;</td>";
2128 echo "<td><input type='checkbox'";
2129 if ($restype) {
2130 echo " checked";
2133 echo " />&nbsp;</td>";
2134 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES);
2135 $resnote = htmlspecialchars($resnote, ENT_QUOTES);
2136 echo "<td><input type='text'" .
2137 " size='$fldlength'" .
2138 " class='form-control' " .
2139 " value='$resnote'" .
2140 " class='under'" .
2141 " /></td>" .
2142 "</tr>";
2145 echo "</table>";
2146 } elseif ($data_type == 27) { // Removed: || $data_type == 1 || $data_type == 26 || $data_type == 33
2147 // a set of labeled radio buttons
2148 // In this special case, fld_length is the number of columns generated.
2150 $cols = max(1, ($frow['fld_length'] ?? null));
2151 $lres = sqlStatement("SELECT * FROM list_options " .
2152 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2153 echo "<table class='w-100' cellpadding='0' cellspacing='0'>";
2154 $tdpct = (int) (100 / $cols);
2155 for ($count = 0; $lrow = sqlFetchArray($lres); ++$count) {
2156 $option_id = $lrow['option_id'];
2157 if ($count % $cols == 0) {
2158 if ($count) {
2159 echo "</tr>";
2161 echo "<tr>";
2163 echo "<td width='" . attr($tdpct) . "%' nowrap>";
2164 echo "<input type='radio'";
2165 if (strlen($currvalue) > 0 && $option_id == $currvalue) {
2166 // Do not use defaults for these printable forms.
2167 echo " checked";
2169 echo ">" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES);
2170 echo "</td>";
2172 if ($count) {
2173 echo "</tr>";
2174 if ($count > $cols) {
2175 // Add some space after multiple rows of radio buttons.
2176 $cols = htmlspecialchars($cols, ENT_QUOTES);
2177 echo "<tr><td colspan='$cols' style='height:0.7em'></td></tr>";
2180 echo "</table>";
2182 // special case for history of lifestyle status; 3 radio buttons and a date text field:
2183 } elseif ($data_type == 28 || $data_type == 32) {
2184 $tmp = explode('|', $currvalue);
2185 switch (count($tmp)) {
2186 case "4":
2187 $resnote = $tmp[0];
2188 $restype = $tmp[1];
2189 $resdate = oeFormatShortDate($tmp[2]) ;
2190 $reslist = $tmp[3];
2191 break;
2192 case "3":
2193 $resnote = $tmp[0];
2194 $restype = $tmp[1];
2195 $resdate = oeFormatShortDate($tmp[2]);
2196 $reslist = '';
2197 break;
2198 case "2":
2199 $resnote = $tmp[0];
2200 $restype = $tmp[1];
2201 $resdate = "";
2202 $reslist = '';
2203 break;
2204 case "1":
2205 $resnote = $tmp[0];
2206 $resdate = $restype = "";
2207 $reslist = '';
2208 break;
2209 default:
2210 $restype = $resdate = $resnote = "";
2211 $reslist = '';
2212 break;
2215 $fldlength = empty($frow['fld_length']) ? 20 : $frow['fld_length'];
2216 echo "<table class='table'>";
2217 echo "<tr>";
2218 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES);
2219 $resnote = htmlspecialchars($resnote, ENT_QUOTES);
2220 $resdate = htmlspecialchars($resdate, ENT_QUOTES);
2221 if ($data_type == 28) {
2222 echo "<td><input type='text'" .
2223 " size='$fldlength'" .
2224 " class='under'" .
2225 " value='$resnote' /></td>";
2226 echo "<td class='font-weight-bold'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" .
2227 "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" .
2228 htmlspecialchars(xl('Status'), ENT_NOQUOTES) . ":&nbsp;</td>";
2229 } elseif ($data_type == 32) {
2230 echo "<tr><td><input type='text'" .
2231 " size='$fldlength'" .
2232 " class='under form-control'" .
2233 " value='$resnote' /></td></tr>";
2234 $fldlength = 30;
2235 $smoking_status_title = generate_display_field(array('data_type' => '1','list_id' => $list_id), $reslist);
2236 echo "<td><input type='text'" .
2237 " size='$fldlength'" .
2238 " class='under form-control'" .
2239 " value='$smoking_status_title' /></td>";
2240 echo "<td class='font-weight-bold'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" . htmlspecialchars(xl('Status'), ENT_NOQUOTES) . ":&nbsp;&nbsp;</td>";
2243 echo "<td><input type='radio' class='form-check-inline'";
2244 if ($restype == "current" . $field_id) {
2245 echo " checked";
2248 echo "/>" . htmlspecialchars(xl('Current'), ENT_NOQUOTES) . "&nbsp;</td>";
2250 echo "<td><input type='radio' class='form-check-inline'";
2251 if ($restype == "current" . $field_id) {
2252 echo " checked";
2255 echo "/>" . htmlspecialchars(xl('Quit'), ENT_NOQUOTES) . "&nbsp;</td>";
2257 echo "<td><input type='text' size='6'" .
2258 " value='$resdate'" .
2259 " class='under form-control'" .
2260 " /></td>";
2262 echo "<td><input type='radio' class='form-check-inline'";
2263 if ($restype == "current" . $field_id) {
2264 echo " checked";
2267 echo " />" . htmlspecialchars(xl('Never'), ENT_NOQUOTES) . "</td>";
2269 echo "<td><input type='radio' class='form-check-inline'";
2270 if ($restype == "not_applicable" . $field_id) {
2271 echo " checked";
2274 echo " />" . htmlspecialchars(xl('N/A'), ENT_NOQUOTES) . "&nbsp;</td>";
2275 echo "</tr>";
2276 echo "</table>";
2277 } elseif ($data_type == 31) { // static text. read-only, of course.
2278 echo parse_static_text($frow, $value_allowed);
2279 } elseif ($data_type == 34) {
2280 echo "<a href='../../../library/custom_template/custom_template.php?type=form_{$field_id}&contextName=" . htmlspecialchars($list_id_esc, ENT_QUOTES) . "' class='iframe_medium text-body text-decoration-none'>";
2281 echo "<div id='form_{$field_id}_div' class='text-area'></div>";
2282 echo "<div style='display: none'><textarea name='form_{$field_id}' class='form-control' id='form_{$field_id}' style='display: none'></textarea></div>";
2283 echo "</a>";
2285 // Facilities. Changed 2017-12-15 to not show the choices.
2286 } elseif ($data_type == 35) {
2287 $urow = sqlQuery(
2288 "SELECT id, name FROM facility WHERE id = ?",
2289 array($currvalue)
2291 echo empty($urow['id']) ? '&nbsp;' : text($urow['name']);
2292 } elseif ($data_type == 36) { //Multi-select. Supports backup lists.
2293 if (empty($fld_length)) {
2294 if ($list_id == 'titles') {
2295 $fld_length = 3;
2296 } else {
2297 $fld_length = 10;
2301 $tmp = '';
2303 $values_array = explode("|", $currvalue);
2305 $i = 0;
2306 foreach ($values_array as $value) {
2307 if ($value) {
2308 $lrow = sqlQuery("SELECT title FROM list_options " .
2309 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($list_id,$value));
2310 $tmp = xl_list_label($lrow['title']);
2311 if ($lrow == 0 && !empty($backup_list)) {
2312 // since primary list did not map, try to map to backup list
2313 $lrow = sqlQuery("SELECT title FROM list_options " .
2314 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($backup_list,$currvalue));
2315 $tmp = xl_list_label($lrow['title']);
2318 if (empty($tmp)) {
2319 $tmp = "($value)";
2323 if ($tmp === '') {
2324 $tmp = '&nbsp;';
2325 } else {
2326 $tmp = htmlspecialchars($tmp, ENT_QUOTES);
2329 if ($i != 0 && $tmp != '&nbsp;') {
2330 echo ",";
2333 echo $tmp;
2334 $i++;
2337 // A set of lab test results; Gestation, 3 radio buttons, test value, notes field:
2338 } elseif ($data_type == 37) {
2339 echo genLabResults($frow, $currvalue, 1, $disabled);
2340 } elseif ($data_type == 40) { // Image from canvas drawing
2341 if (empty($currvalue)) {
2342 if (preg_match('/\\bimage=([a-zA-Z0-9._-]*)/', $frow['description'], $matches)) {
2343 $currvalue = $GLOBALS['web_root'] . '/sites/' . $_SESSION['site_id'] . '/images/' . $matches[1];
2346 if ($currvalue) {
2347 echo "<img src='" . attr($currvalue) . "'>";
2349 } elseif ($data_type == 41 || $data_type == 42) {
2350 if ($currvalue) {
2351 echo "<img class='w-auto' style='height: 70px;' src='" . attr($currvalue) . "'>";
2353 } elseif ($data_type == 44 || $data_type == 45) {
2354 $tmp = '';
2356 $values_array = explode("|", $currvalue);
2358 $i = 0;
2359 foreach ($values_array as $value) {
2360 if ($value) {
2361 if ($data_type == 44) {
2362 $lrow = sqlQuery("SELECT name as name FROM facility WHERE id = ?", array($value));
2364 if ($data_type == 45) {
2365 $lrow = sqlQuery("SELECT CONCAT(fname,' ',lname) as name FROM users WHERE id = ?", array($value));
2367 $tmp = $lrow['name'];
2370 if ($tmp === '') {
2371 $tmp = '&nbsp;';
2372 } else {
2373 $tmp = htmlspecialchars($tmp, ENT_QUOTES);
2376 if ($i != 0 && $tmp != '&nbsp;') {
2377 echo ",";
2380 echo $tmp;
2381 $i++;
2384 // Patient selector field.
2385 } elseif ($data_type == 51) {
2386 if (!empty($currvalue)) {
2387 $tmp = text(getPatientDescription($currvalue));
2388 } else {
2389 echo '&nbsp;';
2395 * @param $list_id
2396 * @param bool $translate
2397 * @return array
2399 * Generate a key-value array containing each row of the specified list,
2400 * with the option ID as the index, and the title as the element
2402 * Pass in the list_id to specify this list.
2404 * Use the translate flag to run the title element through the translator
2406 function generate_list_map($list_id, $translate = false)
2408 $result = sqlStatement("SELECT option_id, title FROM list_options WHERE list_id = ?", [$list_id]);
2409 $map = [];
2410 while ($row = sqlFetchArray($result)) {
2411 if ($translate === true) {
2412 $title = xl_list_label($row['title']);
2413 } else {
2414 $title = $row['title'];
2416 $map[$row['option_id']] = $title;
2419 return $map;
2422 function generate_display_field($frow, $currvalue)
2424 global $ISSUE_TYPES, $facilityService;
2426 $data_type = $frow['data_type'];
2427 $field_id = isset($frow['field_id']) ? $frow['field_id'] : null;
2428 $list_id = $frow['list_id'];
2429 $backup_list = isset($frow['list_backup_id']) ? $frow['list_backup_id'] : null;
2430 $show_unchecked_arr = array();
2431 getLayoutProperties($frow['form_id'] ?? null, $show_unchecked_arr, 'grp_unchecked', "1");
2432 $show_unchecked = strval($show_unchecked_arr['']['grp_unchecked'] ?? null) == "0" ? false : true;
2434 $s = '';
2436 // generic selection list or the generic selection list with add on the fly
2437 // feature
2438 if ($data_type == 1 || $data_type == 26 || $data_type == 43 || $data_type == 46) {
2439 if ($data_type == 46) {
2440 // support for single-selection list with comment support
2441 $selectedValues = explode("|", $currvalue);
2442 $currvalue = $selectedValues[0];
2445 $lrow = sqlQuery("SELECT title FROM list_options " .
2446 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($list_id,$currvalue));
2447 $s = htmlspecialchars(xl_list_label($lrow['title'] ?? ''), ENT_NOQUOTES);
2448 //if there is no matching value in the corresponding lists check backup list
2449 // only supported in data types 1,26,43,46
2450 if ($lrow == 0 && !empty($backup_list) && ($data_type == 1 || $data_type == 26 || $$data_type == 43 || $data_type == 46)) {
2451 $lrow = sqlQuery("SELECT title FROM list_options " .
2452 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($backup_list,$currvalue));
2453 $s = htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES);
2456 // If match is not found in main and backup lists, return the key with exclamation mark
2457 if ($s == '') {
2458 $s = nl2br(text(xl_list_label($currvalue))) .
2459 '<span> <i class="fa fas fa-exclamation-circle ml-1"></i></span>';
2462 if ($data_type == 46) {
2463 // support for single-selection list with comment support
2464 $resnote = $selectedValues[1] ?? null;
2465 if (!empty($resnote)) {
2466 $s .= " (" . text($resnote) . ")";
2469 } elseif ($data_type == 2) { // simple text field
2470 $s = nl2br(htmlspecialchars($currvalue, ENT_NOQUOTES));
2471 } elseif ($data_type == 3) { // long or multi-line text field
2472 $s = nl2br(htmlspecialchars($currvalue, ENT_NOQUOTES));
2473 } elseif ($data_type == 4) { // date
2474 $asof = ''; //not used here, but set to prevent a php warning when call optionalAge
2475 $s = '';
2476 $description = (isset($frow['description']) ? htmlspecialchars(xl_layout_label($frow['description']), ENT_QUOTES) : '');
2477 $age_asof_date = '';
2478 $agestr = optionalAge($frow, $currvalue, $age_asof_date, $description);
2479 if ($currvalue === '') {
2480 $s .= '&nbsp;';
2481 } else {
2482 $modtmp = isOption($frow['edit_options'], 'F') === false ? 0 : 1;
2483 if (!$modtmp) {
2484 $s .= text(oeFormatShortDate($currvalue));
2485 } else {
2486 $s .= text(oeFormatDateTime($currvalue));
2488 if ($agestr) {
2489 $s .= "&nbsp;(" . text($agestr) . ")";
2492 } elseif ($data_type == 10 || $data_type == 11) { // provider
2493 $urow = sqlQuery("SELECT fname, lname, specialty FROM users " .
2494 "WHERE id = ?", array($currvalue));
2495 $s = text(ucwords(($urow['fname'] ?? '') . " " . ($urow['lname'] ?? '')));
2496 } elseif ($data_type == 12) { // pharmacy list
2497 $pres = get_pharmacies();
2498 while ($prow = sqlFetchArray($pres)) {
2499 $key = $prow['id'];
2500 if ($currvalue == $key) {
2501 $s .= htmlspecialchars($prow['name'] . ' ' . $prow['area_code'] . '-' .
2502 $prow['prefix'] . '-' . $prow['number'] . ' / ' .
2503 $prow['line1'] . ' / ' . $prow['city'], ENT_NOQUOTES);
2506 } elseif ($data_type == 13) { // squads
2507 $squads = AclExtended::aclGetSquads();
2508 if ($squads) {
2509 foreach ($squads as $key => $value) {
2510 if ($currvalue == $key) {
2511 $s .= htmlspecialchars($value[3], ENT_NOQUOTES);
2515 } elseif ($data_type == 14) { // address book
2516 $urow = sqlQuery("SELECT fname, lname, specialty, organization FROM users " .
2517 "WHERE id = ?", array($currvalue));
2518 //ViSolve: To display the Organization Name if it exist. Else it will display the user name.
2519 if (!empty($urow['organization'])) {
2520 $uname = $urow['organization'];
2521 } else {
2522 $uname = $urow['lname'] ?? '';
2523 if (!empty($urow['fname'])) {
2524 $uname .= ", " . $urow['fname'];
2528 $s = htmlspecialchars($uname, ENT_NOQUOTES);
2529 } elseif ($data_type == 15) { // billing code
2530 $s = '';
2531 if (!empty($currvalue)) {
2532 $relcodes = explode(';', $currvalue);
2533 foreach ($relcodes as $codestring) {
2534 if ($codestring === '') {
2535 continue;
2537 $tmp = lookup_code_descriptions($codestring);
2538 if ($s !== '') {
2539 $s .= '; ';
2541 if (!empty($tmp)) {
2542 $s .= text($tmp);
2543 } else {
2544 $s .= text($codestring) . ' (' . xlt('not found') . ')';
2548 } elseif ($data_type == 16) { // insurance company list
2549 $insprovs = getInsuranceProviders();
2550 foreach ($insprovs as $key => $ipname) {
2551 if ($currvalue == $key) {
2552 $s .= htmlspecialchars($ipname, ENT_NOQUOTES);
2555 } elseif ($data_type == 17) { // issue types
2556 foreach ($ISSUE_TYPES as $key => $value) {
2557 if ($currvalue == $key) {
2558 $s .= htmlspecialchars($value[1], ENT_NOQUOTES);
2561 } elseif ($data_type == 18) { // visit category
2562 $crow = sqlQuery(
2563 "SELECT pc_catid, pc_catname " .
2564 "FROM openemr_postcalendar_categories WHERE pc_catid = ?",
2565 array($currvalue)
2567 $s = htmlspecialchars($crow['pc_catname'], ENT_NOQUOTES);
2568 } elseif ($data_type == 21) { // a single checkbox or set of labeled checkboxes
2569 if (!$list_id) {
2570 $s .= $currvalue ? '&#9745;' : '&#9744;';
2571 } else {
2572 // In this special case, fld_length is the number of columns generated.
2573 $cols = max(1, $frow['fld_length']);
2574 $avalue = explode('|', $currvalue);
2575 $lres = sqlStatement("SELECT * FROM list_options " .
2576 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2577 $s .= "<table cellspacing='0' cellpadding='0'>";
2578 for ($count = 0; $lrow = sqlFetchArray($lres); ++$count) {
2579 $option_id = $lrow['option_id'];
2580 $option_id_esc = text($option_id);
2581 if ($count % $cols == 0) {
2582 if ($count) {
2583 $s .= "</tr>";
2585 $s .= "<tr>";
2587 $checked = in_array($option_id, $avalue);
2588 if (!$show_unchecked && $checked) {
2589 $s .= "<td nowrap>";
2590 $s .= text(xl_list_label($lrow['title'])) . '&nbsp;&nbsp;';
2591 $s .= "</td>";
2592 } elseif ($show_unchecked) {
2593 $s .= "<td nowrap>";
2594 $s .= $checked ? '&#9745;' : '&#9744;';
2595 $s .= '&nbsp;' . text(xl_list_label($lrow['title'])) . '&nbsp;&nbsp;';
2596 $s .= "</td>";
2599 if ($count) {
2600 $s .= "</tr>";
2602 $s .= "</table>";
2604 } elseif ($data_type == 22) { // a set of labeled text input fields
2605 $tmp = explode('|', $currvalue);
2606 $avalue = array();
2607 foreach ($tmp as $value) {
2608 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
2609 $avalue[$matches[1]] = $matches[2];
2613 $lres = sqlStatement("SELECT * FROM list_options " .
2614 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2615 $s .= "<table class='table'>";
2616 while ($lrow = sqlFetchArray($lres)) {
2617 $option_id = $lrow['option_id'];
2618 if (empty($avalue[$option_id])) {
2619 continue;
2622 // Added 5-09 by BM - Translate label if applicable
2623 $s .= "<tr><td class='font-weight-bold align-top'>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES) . ":&nbsp;</td>";
2625 $s .= "<td class='text align-top'>" . htmlspecialchars($avalue[$option_id], ENT_NOQUOTES) . "</td></tr>";
2628 $s .= "</table>";
2629 } elseif ($data_type == 23) { // a set of exam results; 3 radio buttons and a text field:
2630 $tmp = explode('|', $currvalue);
2631 $avalue = array();
2632 foreach ($tmp as $value) {
2633 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
2634 $avalue[$matches[1]] = $matches[2];
2638 $lres = sqlStatement("SELECT * FROM list_options " .
2639 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2640 $s .= "<table class='table'>";
2641 while ($lrow = sqlFetchArray($lres)) {
2642 $option_id = $lrow['option_id'];
2643 $restype = substr(($avalue[$option_id] ?? ''), 0, 1);
2644 $resnote = substr(($avalue[$option_id] ?? ''), 2);
2645 if (empty($restype) && empty($resnote)) {
2646 continue;
2649 // Added 5-09 by BM - Translate label if applicable
2650 $s .= "<tr><td class='font-weight-bold align-top'>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES) . "&nbsp;</td>";
2652 $restype = ($restype == '1') ? xl('Normal') : (($restype == '2') ? xl('Abnormal') : xl('N/A'));
2653 // $s .= "<td class='text align-top'>$restype</td></tr>";
2654 // $s .= "<td class='text align-top'>$resnote</td></tr>";
2655 $s .= "<td class='text align-top'>" . htmlspecialchars($restype, ENT_NOQUOTES) . "&nbsp;</td>";
2656 $s .= "<td class='text align-top'>" . htmlspecialchars($resnote, ENT_NOQUOTES) . "</td>";
2657 $s .= "</tr>";
2660 $s .= "</table>";
2661 } elseif ($data_type == 24) { // the list of active allergies for the current patient
2662 $query = "SELECT title, comments FROM lists WHERE " .
2663 "pid = ? AND type = 'allergy' AND enddate IS NULL " .
2664 "ORDER BY begdate";
2665 // echo "<!-- $query -->\n"; // debugging
2666 $lres = sqlStatement($query, array($GLOBALS['pid']));
2667 $count = 0;
2668 while ($lrow = sqlFetchArray($lres)) {
2669 if ($count++) {
2670 $s .= "<br />";
2673 $s .= htmlspecialchars($lrow['title'], ENT_NOQUOTES);
2674 if ($lrow['comments']) {
2675 $s .= ' (' . htmlspecialchars($lrow['comments'], ENT_NOQUOTES) . ')';
2678 } elseif ($data_type == 25) { // a set of labeled checkboxes, each with a text field:
2679 $tmp = explode('|', $currvalue);
2680 $avalue = array();
2681 foreach ($tmp as $value) {
2682 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
2683 $avalue[$matches[1]] = $matches[2];
2687 $lres = sqlStatement("SELECT * FROM list_options " .
2688 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2689 $s .= "<table class='table'>";
2690 while ($lrow = sqlFetchArray($lres)) {
2691 $option_id = $lrow['option_id'];
2692 $restype = substr($avalue[$option_id], 0, 1);
2693 $resnote = substr($avalue[$option_id], 2);
2694 if (empty($restype) && empty($resnote)) {
2695 continue;
2698 // Added 5-09 by BM - Translate label if applicable
2699 $s .= "<tr><td class='font-weight-bold align-top'>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES) . "&nbsp;</td>";
2701 $restype = $restype ? xl('Yes') : xl('No');
2702 $s .= "<td class='text align-top'>" . htmlspecialchars($restype, ENT_NOQUOTES) . "&nbsp;</td>";
2703 $s .= "<td class='text align-top'>" . htmlspecialchars($resnote, ENT_NOQUOTES) . "</td>";
2704 $s .= "</tr>";
2707 $s .= "</table>";
2708 } elseif ($data_type == 27) { // a set of labeled radio buttons
2709 // In this special case, fld_length is the number of columns generated.
2710 $cols = max(1, $frow['fld_length']);
2711 $lres = sqlStatement("SELECT * FROM list_options " .
2712 "WHERE list_id = ? ORDER BY seq, title", array($list_id));
2713 $s .= "<table cellspacing='0' cellpadding='0'>";
2714 for ($count = 0; $lrow = sqlFetchArray($lres); ++$count) {
2715 $option_id = $lrow['option_id'];
2716 $option_id_esc = text($option_id);
2717 if ($count % $cols == 0) {
2718 if ($count) {
2719 $s .= "</tr>";
2721 $s .= "<tr>";
2723 $checked = ((strlen($currvalue) == 0 && $lrow['is_default']) ||
2724 (strlen($currvalue) > 0 && $option_id == $currvalue));
2725 if (!$show_unchecked && $checked) {
2726 $s .= "<td nowrap>";
2727 $s .= text(xl_list_label($lrow['title'])) . '&nbsp;&nbsp;';
2728 $s .= "</td>";
2729 } elseif ($show_unchecked) {
2730 $s .= "<td nowrap>";
2731 $s .= $checked ? '&#9745;' : '&#9744;';
2732 $s .= '&nbsp;' . text(xl_list_label($lrow['title'])) . '&nbsp;&nbsp;';
2733 $s .= "</td>";
2736 if ($count) {
2737 $s .= "</tr>";
2739 $s .= "</table>";
2740 } elseif ($data_type == 28 || $data_type == 32) { // special case for history of lifestyle status; 3 radio buttons
2741 // and a date text field:
2742 // VicarePlus :: A selection list for smoking status.
2743 $tmp = explode('|', $currvalue);
2744 switch (count($tmp)) {
2745 case "4":
2746 $resnote = $tmp[0];
2747 $restype = $tmp[1];
2748 $resdate = oeFormatShortDate($tmp[2]);
2749 $reslist = $tmp[3];
2750 break;
2751 case "3":
2752 $resnote = $tmp[0];
2753 $restype = $tmp[1];
2754 $resdate = oeFormatShortDate($tmp[2]);
2755 $reslist = '';
2756 break;
2757 case "2":
2758 $resnote = $tmp[0];
2759 $restype = $tmp[1];
2760 $resdate = "";
2761 $reslist = '';
2762 break;
2763 case "1":
2764 $resnote = $tmp[0];
2765 $resdate = $restype = "";
2766 $reslist = '';
2767 break;
2768 default:
2769 $restype = $resdate = $resnote = "";
2770 $reslist = '';
2771 break;
2774 $s .= "<table class='table'>";
2776 $s .= "<tr>";
2777 $res = "";
2778 if ($restype == "current" . $field_id) {
2779 $res = xl('Current');
2782 if ($restype == "quit" . $field_id) {
2783 $res = xl('Quit');
2786 if ($restype == "never" . $field_id) {
2787 $res = xl('Never');
2790 if ($restype == "not_applicable" . $field_id) {
2791 $res = xl('N/A');
2794 // $s .= "<td class='text align-top'>$restype</td></tr>";
2795 // $s .= "<td class='text align-top'>$resnote</td></tr>";
2796 if ($data_type == 28) {
2797 if (!empty($resnote)) {
2798 $s .= "<td class='text align-top'>" . htmlspecialchars($resnote, ENT_NOQUOTES) . "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>";
2800 } elseif ($data_type == 32) { //VicarePlus :: Tobacco field has a listbox, text box, date field and 3 radio buttons.
2801 // changes on 5-jun-2k14 (regarding 'Smoking Status - display SNOMED code description')
2802 $smoke_codes = getSmokeCodes();
2803 if (!empty($reslist)) {
2804 if ($smoke_codes[$reslist] != "") {
2805 $code_desc = "( " . $smoke_codes[$reslist] . " )";
2808 $s .= "<td class='text align-top'>" . generate_display_field(array('data_type' => '1','list_id' => $list_id), $reslist) . "&nbsp;" . text($code_desc) . "&nbsp;&nbsp;&nbsp;&nbsp;</td>";
2811 if (!empty($resnote)) {
2812 $s .= "<td class='text align-top'>" . htmlspecialchars($resnote, ENT_NOQUOTES) . "&nbsp;&nbsp;</td>";
2816 if (!empty($res)) {
2817 $s .= "<td class='text align-top'><strong>" . htmlspecialchars(xl('Status'), ENT_NOQUOTES) . "</strong>:&nbsp;" . htmlspecialchars($res, ENT_NOQUOTES) . "&nbsp;</td>";
2820 if ($restype == "quit" . $field_id) {
2821 $s .= "<td class='text align-top'>" . htmlspecialchars($resdate, ENT_NOQUOTES) . "&nbsp;</td>";
2824 $s .= "</tr>";
2825 $s .= "</table>";
2826 } elseif ($data_type == 31) { // static text. read-only, of course.
2827 $s .= parse_static_text($frow);
2828 } elseif ($data_type == 34) {
2829 $arr = explode("|*|*|*|", $currvalue);
2830 for ($i = 0; $i < sizeof($arr); $i++) {
2831 $s .= $arr[$i];
2833 } elseif ($data_type == 35) { // facility
2834 $urow = $facilityService->getById($currvalue);
2835 $s = htmlspecialchars($urow['name'] ?? '', ENT_NOQUOTES);
2836 } elseif ($data_type == 36 || $data_type == 33) { // Multi select. Supports backup lists
2837 $values_array = explode("|", $currvalue);
2838 $i = 0;
2839 foreach ($values_array as $value) {
2840 $lrow = sqlQuery("SELECT title FROM list_options " .
2841 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($list_id,$value));
2842 if ($lrow == 0 && !empty($backup_list)) {
2843 //use back up list
2844 $lrow = sqlQuery("SELECT title FROM list_options " .
2845 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($backup_list,$value));
2848 $title = $lrow['title'] ?? '';
2849 if ($i > 0) {
2850 $s = $s . ", " . text(xl_list_label($title));
2851 } else {
2852 $s = text(xl_list_label($title));
2855 $i++;
2858 // A set of lab test results; Gestation, 3 radio buttons, test value, notes field:
2859 } elseif ($data_type == 37) {
2860 $s .= genLabResults($frow, $currvalue, 2, '');
2861 } elseif ($data_type == 40) { // Image from canvas drawing
2862 if (empty($currvalue)) {
2863 if (preg_match('/\\bimage=([a-zA-Z0-9._-]*)/', $frow['description'], $matches)) {
2864 $currvalue = $GLOBALS['web_root'] . '/sites/' . $_SESSION['site_id'] . '/images/' . $matches[1];
2867 if ($currvalue) {
2868 $s .= "<img src='" . attr($currvalue) . "'>";
2870 } elseif ($data_type == 41 || $data_type == 42) {
2871 if ($currvalue) {
2872 $s .= "<img class='w-auto' style='height: 70px;' src='" . attr($currvalue) . "'>";
2874 } elseif ($data_type == 44 || $data_type == 45) { // Multiple select facility and provider
2875 $values_array = explode("|", $currvalue);
2876 $i = 0;
2877 foreach ($values_array as $value) {
2878 if ($data_type == 44) {
2879 $lrow = sqlQuery("SELECT name as name FROM facility WHERE id = ?", array($value));
2881 if ($data_type == 45) {
2882 $lrow = sqlQuery("SELECT CONCAT(fname,' ',lname) as name FROM users WHERE id = ?", array($value));
2884 if ($i > 0) {
2885 $s = $s . ", " . htmlspecialchars($lrow['name'], ENT_NOQUOTES);
2886 } else {
2887 $s = text($lrow['name'] ?? '');
2889 $i++;
2892 // Patient selector field.
2893 } elseif ($data_type == 51) {
2894 if (!empty($currvalue)) {
2895 $s .= text(getPatientDescription($currvalue));
2897 } elseif ($data_type == 52) {
2898 global $pid;
2899 $patientService = new PatientService();
2900 $rows = $patientService->getPatientNameHistory($pid);
2901 $i = 0;
2902 foreach ($rows as $row) {
2903 // name escaped in fetch
2904 if ($i > 0) {
2905 $s .= ", " . $row['formatted_name'];
2906 } else {
2907 $s = $row['formatted_name'] ?? '';
2909 $i++;
2911 // now that we've concatenated everything, let's escape it.
2912 $s = text($s);
2913 } elseif ($data_type == 53) {
2914 $service = new EncounterService();
2915 if (!empty($currvalue)) {
2916 $encounterResult = $service->getEncounterById($currvalue);
2917 if (!empty($encounterResult) && $encounterResult->hasData()) {
2918 $encounter = reset($encounterResult->getData());
2919 $s = text($encounter['date'] ?? '');
2922 } elseif ($data_type == 54) {
2923 include "templates/address_list_display.php";
2926 return $s;
2929 // Generate plain text versions of selected LBF field types.
2930 // Currently used by interface/patient_file/download_template.php and interface/main/finder/dynamic_finder_ajax.php.
2931 // More field types might need to be supported here in the future.
2933 function generate_plaintext_field($frow, $currvalue)
2935 global $ISSUE_TYPES;
2937 $data_type = $frow['data_type'];
2938 $field_id = isset($frow['field_id']) ? $frow['field_id'] : null;
2939 $list_id = $frow['list_id'];
2940 $backup_list = $frow['backup_list'] ?? null;
2941 $edit_options = $frow['edit_options'] ?? null;
2942 $s = '';
2944 // generic selection list or the generic selection list with add on the fly
2945 // feature, or radio buttons
2946 // Supports backup lists (for datatypes 1,26,43)
2947 if ($data_type == 1 || $data_type == 26 || $data_type == 27 || $data_type == 43 || $data_type == 46) {
2948 if ($data_type == 46) {
2949 // support for single-selection list with comment support
2950 $selectedValues = explode("|", $currvalue);
2951 $currvalue = $selectedValues[0];
2954 $lrow = sqlQuery(
2955 "SELECT title FROM list_options " .
2956 "WHERE list_id = ? AND option_id = ? AND activity = 1",
2957 array($list_id, $currvalue)
2959 $s = xl_list_label($lrow['title'] ?? '');
2960 //if there is no matching value in the corresponding lists check backup list
2961 // only supported in data types 1,26,43
2962 if ($lrow == 0 && !empty($backup_list) && ($data_type == 1 || $data_type == 26 || $data_type == 43 || $data_type == 46)) {
2963 $lrow = sqlQuery("SELECT title FROM list_options " .
2964 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($backup_list, $currvalue));
2965 $s = xl_list_label($lrow['title']);
2968 if ($data_type == 46) {
2969 // support for single-selection list with comment support
2970 $resnote = $selectedValues[1] ?? null;
2971 if (!empty($resnote)) {
2972 $s .= " (" . $resnote . ")";
2975 } elseif ($data_type == 2 || $data_type == 3 || $data_type == 15) { // simple or long text field
2976 $s = $currvalue;
2977 } elseif ($data_type == 4) { // date
2978 $modtmp = isOption($edit_options, 'F') === false ? 0 : 1;
2979 if (!$modtmp) {
2980 $s = text(oeFormatShortDate($currvalue));
2981 } else {
2982 $s = text(oeFormatDateTime($currvalue));
2984 $description = (isset($frow['description']) ? htmlspecialchars(xl_layout_label($frow['description']), ENT_QUOTES) : '');
2985 $age_asof_date = '';
2986 // Optional display of age or gestational age.
2987 $tmp = optionalAge($frow, $currvalue, $age_asof_date, $description);
2988 if ($tmp) {
2989 $s .= ' ' . $tmp;
2991 } elseif ($data_type == 10 || $data_type == 11) { // provider
2992 $urow = sqlQuery("SELECT fname, lname, specialty FROM users " .
2993 "WHERE id = ?", array($currvalue));
2994 $s = ucwords($urow['fname'] . " " . $urow['lname']);
2995 } elseif ($data_type == 12) { // pharmacy list
2996 $pres = get_pharmacies();
2997 while ($prow = sqlFetchArray($pres)) {
2998 $key = $prow['id'];
2999 if ($currvalue == $key) {
3000 $s .= $prow['name'] . ' ' . $prow['area_code'] . '-' .
3001 $prow['prefix'] . '-' . $prow['number'] . ' / ' .
3002 $prow['line1'] . ' / ' . $prow['city'];
3005 } elseif ($data_type == 14) { // address book
3006 $urow = sqlQuery("SELECT fname, lname, specialty FROM users " .
3007 "WHERE id = ?", array($currvalue));
3008 $uname = $urow['lname'];
3009 if ($urow['fname']) {
3010 $uname .= ", " . $urow['fname'];
3013 $s = $uname;
3014 } elseif ($data_type == 16) { // insurance company list
3015 $insprovs = getInsuranceProviders();
3016 foreach ($insprovs as $key => $ipname) {
3017 if ($currvalue == $key) {
3018 $s .= $ipname;
3021 } elseif ($data_type == 17) { // issue type
3022 foreach ($ISSUE_TYPES as $key => $value) {
3023 if ($currvalue == $key) {
3024 $s .= $value[1];
3027 } elseif ($data_type == 18) { // visit category
3028 $crow = sqlQuery(
3029 "SELECT pc_catid, pc_catname " .
3030 "FROM openemr_postcalendar_categories WHERE pc_catid = ?",
3031 array($currvalue)
3033 $s = $crow['pc_catname'];
3034 } elseif ($data_type == 21) { // a set of labeled checkboxes
3035 if (!$list_id) {
3036 $s .= $currvalue ? xlt('Yes') : xlt('No');
3037 } else {
3038 $avalue = explode('|', $currvalue);
3039 $lres = sqlStatement("SELECT * FROM list_options " .
3040 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
3041 $count = 0;
3042 while ($lrow = sqlFetchArray($lres)) {
3043 $option_id = $lrow['option_id'];
3044 if (in_array($option_id, $avalue)) {
3045 if ($count++) {
3046 $s .= "; ";
3048 $s .= xl_list_label($lrow['title']);
3052 } elseif ($data_type == 22) { // a set of labeled text input fields
3053 $tmp = explode('|', $currvalue);
3054 $avalue = array();
3055 foreach ($tmp as $value) {
3056 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
3057 $avalue[$matches[1]] = $matches[2];
3061 $lres = sqlStatement("SELECT * FROM list_options " .
3062 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
3063 while ($lrow = sqlFetchArray($lres)) {
3064 $option_id = $lrow['option_id'];
3065 if (empty($avalue[$option_id])) {
3066 continue;
3069 if ($s !== '') {
3070 $s .= '; ';
3073 $s .= xl_list_label($lrow['title']) . ': ';
3074 $s .= $avalue[$option_id];
3076 } elseif ($data_type == 23) { // A set of exam results; 3 radio buttons and a text field.
3077 // This shows abnormal results only.
3078 $tmp = explode('|', $currvalue);
3079 $avalue = array();
3080 foreach ($tmp as $value) {
3081 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
3082 $avalue[$matches[1]] = $matches[2];
3086 $lres = sqlStatement("SELECT * FROM list_options " .
3087 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
3088 while ($lrow = sqlFetchArray($lres)) {
3089 $option_id = $lrow['option_id'];
3090 $restype = substr($avalue[$option_id], 0, 1);
3091 $resnote = substr($avalue[$option_id], 2);
3092 if (empty($restype) && empty($resnote)) {
3093 continue;
3096 if ($restype != '2') {
3097 continue; // show abnormal results only
3100 if ($s !== '') {
3101 $s .= '; ';
3104 $s .= xl_list_label($lrow['title']);
3105 if (!empty($resnote)) {
3106 $s .= ': ' . $resnote;
3109 } elseif ($data_type == 24) { // the list of active allergies for the current patient
3110 $query = "SELECT title, comments FROM lists WHERE " .
3111 "pid = ? AND type = 'allergy' AND enddate IS NULL " .
3112 "ORDER BY begdate";
3113 $lres = sqlStatement($query, array($GLOBALS['pid']));
3114 $count = 0;
3115 while ($lrow = sqlFetchArray($lres)) {
3116 if ($count++) {
3117 $s .= "; ";
3120 $s .= $lrow['title'];
3121 if ($lrow['comments']) {
3122 $s .= ' (' . $lrow['comments'] . ')';
3125 } elseif ($data_type == 25) { // a set of labeled checkboxes, each with a text field:
3126 $tmp = explode('|', $currvalue);
3127 $avalue = array();
3128 foreach ($tmp as $value) {
3129 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
3130 $avalue[$matches[1]] = $matches[2];
3134 $lres = sqlStatement("SELECT * FROM list_options " .
3135 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
3136 while ($lrow = sqlFetchArray($lres)) {
3137 $option_id = $lrow['option_id'];
3138 $restype = substr($avalue[$option_id], 0, 1);
3139 $resnote = substr($avalue[$option_id], 2);
3140 if (empty($restype) && empty($resnote)) {
3141 continue;
3144 if ($s !== '') {
3145 $s .= '; ';
3148 $s .= xl_list_label($lrow['title']);
3149 $restype = $restype ? xl('Yes') : xl('No');
3150 $s .= $restype;
3151 if ($resnote) {
3152 $s .= ' ' . $resnote;
3155 } elseif ($data_type == 28 || $data_type == 32) { // special case for history of lifestyle status; 3 radio buttons and a date text field:
3156 // VicarePlus :: A selection list for smoking status.
3157 $tmp = explode('|', $currvalue);
3158 $resnote = count($tmp) > 0 ? $tmp[0] : '';
3159 $restype = count($tmp) > 1 ? $tmp[1] : '';
3160 $resdate = count($tmp) > 2 ? oeFormatShortDate($tmp[2]) : '';
3161 $reslist = count($tmp) > 3 ? $tmp[3] : '';
3162 $res = "";
3163 if ($restype == "current" . $field_id) {
3164 $res = xl('Current');
3167 if ($restype == "quit" . $field_id) {
3168 $res = xl('Quit');
3171 if ($restype == "never" . $field_id) {
3172 $res = xl('Never');
3175 if ($restype == "not_applicable" . $field_id) {
3176 $res = xl('N/A');
3179 if ($data_type == 28) {
3180 if (!empty($resnote)) {
3181 $s .= $resnote;
3183 } elseif ($data_type == 32) { // Tobacco field has a listbox, text box, date field and 3 radio buttons.
3184 if (!empty($reslist)) {
3185 $s .= generate_plaintext_field(array('data_type' => '1','list_id' => $list_id), $reslist);
3188 if (!empty($resnote)) {
3189 $s .= ' ' . $resnote;
3193 if (!empty($res)) {
3194 if ($s !== '') {
3195 $s .= ' ';
3198 $s .= xl('Status') . ' ' . $res;
3201 if ($restype == "quit" . $field_id) {
3202 if ($s !== '') {
3203 $s .= ' ';
3206 $s .= $resdate;
3208 } elseif ($data_type == 35) { // Facility, so facility can be listed in plain-text, as in patient finder column
3209 $facilityService = new FacilityService();
3210 $facility = $facilityService->getById($currvalue);
3211 $s = $facility['name'];
3212 } elseif ($data_type == 36 || $data_type == 33) { // Multi select. Supports backup lists
3213 $values_array = explode("|", $currvalue);
3215 $i = 0;
3216 foreach ($values_array as $value) {
3217 $lrow = sqlQuery("SELECT title FROM list_options " .
3218 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($list_id,$value));
3220 if ($lrow == 0 && !empty($backup_list)) {
3221 //use back up list
3222 $lrow = sqlQuery("SELECT title FROM list_options " .
3223 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($backup_list,$value));
3226 if ($i > 0) {
3227 $s = $s . ", " . xl_list_label($lrow['title']);
3228 } else {
3229 $s = xl_list_label($lrow['title']);
3232 $i++;
3235 // A set of lab test results; Gestation, 3 radio buttons, test value, notes field:
3236 } elseif ($data_type == 37) {
3237 $s .= genLabResults($frow, $currvalue, 3, '');
3238 } elseif ($data_type == 44 || $data_type == 45) {
3239 $values_array = explode("|", $currvalue);
3241 $i = 0;
3242 foreach ($values_array as $value) {
3243 if ($data_type == 44) {
3244 $lrow = sqlQuery("SELECT name as name FROM facility WHERE id = ?", array($value));
3246 if ($data_type == 45) {
3247 $lrow = sqlQuery("SELECT CONCAT(fname,' ',lname) as name FROM users WHERE id = ?", array($value));
3250 if ($i > 0) {
3251 $s = $s . ", " . $lrow['name'];
3252 } else {
3253 $s = $lrow['name'];
3256 $i++;
3259 // Patient selector field.
3260 } elseif ($data_type == 51) {
3261 if (!empty($currvalue)) {
3262 $s .= getPatientDescription($currvalue);
3266 return $s;
3269 $CPR = 4; // cells per row of generic data
3270 $last_group = '';
3271 $cell_count = 0;
3272 $item_count = 0;
3274 function disp_end_cell()
3276 global $item_count, $cell_count;
3277 if ($item_count > 0) {
3278 echo "</td>";
3279 $item_count = 0;
3283 function disp_end_row()
3285 global $cell_count, $CPR;
3286 disp_end_cell();
3287 if ($cell_count > 0) {
3288 for (; $cell_count < $CPR; ++$cell_count) {
3289 echo "<td></td>";
3292 echo "</tr>\n";
3293 $cell_count = 0;
3297 function disp_end_group()
3299 global $last_group;
3300 if (strlen($last_group) > 0) {
3301 disp_end_row();
3305 // Bootstrapped versions of disp_end_* functions:
3307 function bs_disp_end_cell()
3309 global $item_count;
3310 if ($item_count > 0) {
3311 echo "</div>"; // end BS column
3312 $item_count = 0;
3316 function bs_disp_end_row()
3318 global $cell_count, $CPR, $BS_COL_CLASS;
3319 bs_disp_end_cell();
3320 if ($cell_count > 0 && $cell_count < $CPR) {
3321 // Create a cell occupying the remaining bootstrap columns.
3322 // BS columns will be less than 12 if $CPR is not 2, 3, 4, 6 or 12.
3323 $bs_cols_remaining = ($CPR - $cell_count) * intval(12 / $CPR);
3324 echo "<div class='$BS_COL_CLASS-$bs_cols_remaining'></div>";
3326 if ($cell_count > 0) {
3327 echo "</div><!-- End BS row -->\n";
3328 $cell_count = 0;
3332 function bs_disp_end_group()
3334 global $last_group;
3335 if (strlen($last_group) > 0) {
3336 bs_disp_end_row();
3342 function getPatientDescription($pid)
3344 $prow = sqlQuery("SELECT lname, fname FROM patient_data WHERE pid = ?", array($pid));
3345 if ($prow) {
3346 return $prow['lname'] . ", " . $prow['fname'] . " ($pid)";
3348 return xl('Unknown') . " ($pid)";
3351 // Accumulate action conditions into a JSON expression for the browser side.
3352 function accumActionConditions(&$frow, &$condition_str)
3354 $field_id = $frow['field_id'];
3355 $conditions = empty($frow['conditions']) ? array() : unserialize($frow['conditions'], ['allowed_classes' => false]);
3356 $action = 'skip';
3357 foreach ($conditions as $key => $condition) {
3358 if ($key === 'action') {
3359 // If specified this should be the first array item.
3360 if ($condition) {
3361 $action = $condition;
3363 continue;
3365 if (empty($condition['id'])) {
3366 continue;
3368 $andor = empty($condition['andor']) ? '' : $condition['andor'];
3369 if ($condition_str) {
3370 $condition_str .= ",\n";
3372 $condition_str .= "{" .
3373 "target:" . js_escape($field_id) . ", " .
3374 "action:" . js_escape($action) . ", " .
3375 "id:" . js_escape($condition['id']) . ", " .
3376 "itemid:" . js_escape($condition['itemid']) . ", " .
3377 "operator:" . js_escape($condition['operator']) . ", " .
3378 "value:" . js_escape($condition['value']) . ", ";
3379 if ($frow['data_type'] == 15 && strpos($frow['edit_options'], '2') !== false) {
3380 // For billing codes handle requirement to display its description.
3381 $tmp = explode('=', $action, 2);
3382 if (!empty($tmp[1])) {
3383 $condition_str .= "valdesc:" . js_escape(getCodeDescription($tmp[1])) . ", ";
3386 $condition_str .= "andor:" . js_escape($andor) . "}";
3390 function getCodeDescription($codestring, $defaulttype = 'ICD10')
3392 if ($codestring === '') {
3393 return '';
3395 list($ctype, $code) = explode(':', $codestring);
3396 if (empty($code)) {
3397 $code = $ctype;
3398 $ctype = $defaulttype;
3400 $desc = lookup_code_descriptions("$ctype:$code");
3401 if (!empty($desc)) {
3402 return $desc;
3403 } else {
3404 return $codestring;
3408 // This checks if the given field with the given value should have an action applied.
3409 // Originally the only action was skip, but now you can also set the field to a
3410 // specified value, or "skip and otherwise set a value".
3411 // It somewhat mirrors the checkSkipConditions function in options.js.php.
3412 // If you use this for multiple layouts in the same script, you should
3413 // clear $sk_layout_items before each layout.
3414 function isSkipped(&$frow, $currvalue)
3416 global $sk_layout_items;
3418 // Accumulate an array of the encountered fields and their values.
3419 // It is assumed that fields appear before they are tested by another field.
3420 // TBD: Bad assumption?
3421 $field_id = $frow['field_id'];
3422 if (!is_array($sk_layout_items)) {
3423 $sk_layout_items = array();
3425 $sk_layout_items[$field_id] = array('row' => $frow, 'value' => $currvalue);
3427 if (empty($frow['conditions'])) {
3428 return false;
3431 $skiprows = unserialize($frow['conditions'], ['allowed_classes' => false]);
3432 $prevandor = '';
3433 $prevcond = false;
3434 $datatype = $frow['data_type'];
3435 $action = 'skip'; // default action if none specified
3437 foreach ($skiprows as $key => $skiprow) {
3438 // id referenced field id
3439 // itemid referenced array key if applicable
3440 // operator "eq", "ne", "se" or "ns"
3441 // value if eq or ne, some string to compare with
3442 // andor "and", "or" or empty
3444 if ($key === 'action') {
3445 // Action value is a string. It can be "skip", or "value=" or "hsval=" followed by a value.
3446 $action = $skiprow;
3447 continue;
3450 if (empty($skiprow['id'])) {
3451 continue;
3454 $id = $skiprow['id'];
3455 if (!isset($sk_layout_items[$id])) {
3456 error_log("Function isSkipped() cannot find skip source field '" . errorLogEscape($id) . "'.");
3457 continue;
3459 $itemid = $skiprow['itemid'];
3460 $operator = $skiprow['operator'];
3461 $skipval = $skiprow['value'];
3462 $srcvalue = $sk_layout_items[$id]['value'];
3463 $src_datatype = $sk_layout_items[$id]['row']['data_type'];
3464 $src_list_id = $sk_layout_items[$id]['row']['list_id'];
3466 // Some data types use itemid and we have to dig for their value.
3467 if ($src_datatype == 21 && $src_list_id) { // array of checkboxes
3468 $tmp = explode('|', $srcvalue);
3469 $srcvalue = in_array($itemid, $tmp);
3470 } elseif ($src_datatype == 22 || $src_datatype == 23 || $src_datatype == 25) {
3471 $tmp = explode('|', $srcvalue);
3472 $srcvalue = '';
3473 foreach ($tmp as $tmp2) {
3474 if (strpos($tmp2, "$itemid:") === 0) {
3475 if ($datatype == 22) {
3476 $srcvalue = substr($tmp2, strlen($itemid) + 1);
3477 } else {
3478 $srcvalue = substr($tmp2, strlen($itemid) + 1, 1);
3484 // Compute the result of the test for this condition row.
3485 // PHP's looseness with variable type conversion helps us here.
3486 $condition = false;
3487 if ($operator == 'eq') {
3488 $condition = $srcvalue == $skipval;
3489 } elseif ($operator == 'ne') {
3490 $condition = $srcvalue != $skipval;
3491 } elseif ($operator == 'se') {
3492 $condition = $srcvalue == true;
3493 } elseif ($operator == 'ns') {
3494 $condition = $srcvalue != true;
3495 } else {
3496 error_log("Unknown skip operator '" . errorLogEscape($operator) . "' for field '" . errorLogEscape($field_id) . "'.");
3499 // Logic to accumulate multiple conditions for the same target.
3500 if ($prevandor == 'and') {
3501 $condition = $condition && $prevcond;
3502 } elseif ($prevandor == 'or') {
3503 $condition = $condition || $prevcond;
3505 $prevandor = $skiprow['andor'];
3506 $prevcond = $condition;
3509 if (substr($action, 0, 6) == 'hsval=') {
3510 return $prevcond ? 'skip' : ('value=' . substr($action, 6));
3512 return $prevcond ? $action : '';
3515 // Load array of names of the given layout and its groups.
3516 function getLayoutProperties($formtype, &$grparr, $sel = "grp_title", $limit = null)
3518 if ($sel != '*' && strpos($sel, 'grp_group_id') === false) {
3519 $sel = "grp_group_id, $sel";
3521 $gres = sqlStatement("SELECT $sel FROM layout_group_properties WHERE grp_form_id = ? " .
3522 " ORDER BY grp_group_id " .
3523 ($limit ? "LIMIT " . escape_limit($limit) : ""), array($formtype));
3524 while ($grow = sqlFetchArray($gres)) {
3525 // TBD: Remove this after grp_init_open column is implemented.
3526 if ($sel == '*' && !isset($grow['grp_init_open'])) {
3527 $tmprow = sqlQuery(
3528 "SELECT form_id FROM layout_options " .
3529 "WHERE form_id = ? AND group_id LIKE ? AND uor > 0 AND edit_options LIKE '%I%' " .
3530 "LIMIT 1",
3531 array($formtype, $grow['grp_group_id'] . '%')
3533 $grow['grp_init_open'] = !empty($tmprow['form_id']);
3535 $grparr[$grow['grp_group_id']] = $grow;
3539 function display_layout_rows($formtype, $result1, $result2 = '')
3541 global $item_count, $cell_count, $last_group, $CPR;
3543 if ('HIS' == $formtype) {
3544 $formtype .= '%'; // TBD: DEM also?
3546 $pres = sqlStatement(
3547 "SELECT grp_form_id, grp_seq, grp_title " .
3548 "FROM layout_group_properties " .
3549 "WHERE grp_form_id LIKE ? AND grp_group_id = '' " .
3550 "ORDER BY grp_seq, grp_title, grp_form_id",
3551 array("$formtype")
3553 while ($prow = sqlFetchArray($pres)) {
3554 $formtype = $prow['grp_form_id'];
3555 $last_group = '';
3556 $cell_count = 0;
3557 $item_count = 0;
3559 $grparr = array();
3560 getLayoutProperties($formtype, $grparr, '*');
3562 $TOPCPR = empty($grparr['']['grp_columns']) ? 4 : $grparr['']['grp_columns'];
3564 $fres = sqlStatement("SELECT * FROM layout_options " .
3565 "WHERE form_id = ? AND uor > 0 " .
3566 "ORDER BY group_id, seq", array($formtype));
3568 while ($frow = sqlFetchArray($fres)) {
3569 $this_group = $frow['group_id'];
3570 $titlecols = $frow['titlecols'];
3571 $datacols = $frow['datacols'];
3572 $data_type = $frow['data_type'];
3573 $field_id = $frow['field_id'];
3574 $list_id = $frow['list_id'];
3575 $currvalue = '';
3576 $jump_new_row = isOption($frow['edit_options'], 'J');
3577 $prepend_blank_row = isOption($frow['edit_options'], 'K');
3578 $portal_exclude = (!empty($_SESSION["patient_portal_onsite_two"]) && isOption($frow['edit_options'], 'EP')) ?? null;
3579 $span_col_row = isOption($frow['edit_options'], 'SP');
3581 if (!empty($portal_exclude)) {
3582 continue;
3585 $CPR = empty($grparr[$this_group]['grp_columns']) ? $TOPCPR : $grparr[$this_group]['grp_columns'];
3587 if ($formtype == 'DEM') {
3588 if (strpos($field_id, 'em_') === 0) {
3589 // Skip employer related fields, if it's disabled.
3590 if ($GLOBALS['omit_employers']) {
3591 continue;
3594 $tmp = substr($field_id, 3);
3595 if (isset($result2[$tmp])) {
3596 $currvalue = $result2[$tmp];
3598 } else {
3599 if (isset($result1[$field_id])) {
3600 $currvalue = $result1[$field_id];
3603 } else {
3604 if (isset($result1[$field_id])) {
3605 $currvalue = $result1[$field_id];
3609 // Handle a data category (group) change.
3610 if (strcmp($this_group, $last_group) != 0) {
3611 $group_name = $grparr[$this_group]['grp_title'];
3612 // totally skip generating the employer category, if it's disabled.
3613 if ($group_name === 'Employer' && $GLOBALS['omit_employers']) {
3614 continue;
3617 disp_end_group();
3618 $last_group = $this_group;
3621 // filter out all the empty field data from the patient report.
3622 if (!empty($currvalue) && !($currvalue == '0000-00-00 00:00:00')) {
3623 // Handle starting of a new row.
3624 if (($titlecols > 0 && $cell_count >= $CPR) || $cell_count == 0 || $prepend_blank_row || $jump_new_row) {
3625 disp_end_row();
3626 if ($prepend_blank_row) {
3627 echo "<tr><td class='label' colspan='" . ($CPR + 1) . "'>&nbsp;</td></tr>\n";
3629 echo "<tr>";
3630 if ($group_name) {
3631 echo "<td class='groupname'>";
3632 echo text(xl_layout_label($group_name));
3633 $group_name = '';
3634 } else {
3635 echo "<td class='align-top'>&nbsp;";
3638 echo "</td>";
3641 if ($item_count == 0 && $titlecols == 0) {
3642 $titlecols = 1;
3645 // Handle starting of a new label cell.
3646 if ($titlecols > 0 || $span_col_row) {
3647 disp_end_cell();
3648 $titlecols = $span_col_row ? 0 : $titlecols;
3649 $titlecols_esc = htmlspecialchars($titlecols, ENT_QUOTES);
3650 if (!$span_col_row) {
3651 echo "<td class='label_custom' colspan='$titlecols_esc' ";
3652 echo ">";
3654 $cell_count += $titlecols;
3657 ++$item_count;
3659 // Prevent title write if span entire row.
3660 if (!$span_col_row) {
3661 // Added 5-09 by BM - Translate label if applicable
3662 if ($frow['title']) {
3663 $tmp = xl_layout_label($frow['title']);
3664 echo text($tmp);
3665 // Append colon only if label does not end with punctuation.
3666 if (strpos('?!.,:-=', substr($tmp, -1, 1)) === false) {
3667 echo ':';
3669 } else {
3670 echo "&nbsp;";
3673 // Handle starting of a new data cell.
3674 if ($datacols > 0) {
3675 disp_end_cell();
3676 $datacols = $span_col_row ? $CPR : $datacols;
3677 $datacols_esc = htmlspecialchars($datacols, ENT_QUOTES);
3678 echo "<td class='text data' colspan='$datacols_esc'";
3679 echo ">";
3680 $cell_count += $datacols;
3683 ++$item_count;
3684 echo generate_display_field($frow, $currvalue);
3687 disp_end_group();
3688 } // End this layout, there may be more in the case of history.
3691 // This generates the tabs for a form.
3693 function display_layout_tabs($formtype, $result1, $result2 = '')
3695 global $item_count, $cell_count, $last_group, $CPR;
3697 if ('HIS' == $formtype) {
3698 $formtype .= '%'; // TBD: DEM also?
3700 $pres = sqlStatement(
3701 "SELECT grp_form_id, grp_seq, grp_title " .
3702 "FROM layout_group_properties " .
3703 "WHERE grp_form_id LIKE ? AND grp_group_id = '' " .
3704 "ORDER BY grp_seq, grp_title, grp_form_id",
3705 array("$formtype")
3707 $first = true;
3708 while ($prow = sqlFetchArray($pres)) {
3709 $formtype = $prow['grp_form_id'];
3710 $last_group = '';
3711 $cell_count = 0;
3712 $item_count = 0;
3714 $grparr = array();
3715 getLayoutProperties($formtype, $grparr);
3717 $fres = sqlStatement("SELECT distinct group_id FROM layout_options " .
3718 "WHERE form_id = ? AND uor > 0 " .
3719 "ORDER BY group_id", array($formtype));
3721 $prev_group = '';
3722 while ($frow = sqlFetchArray($fres)) {
3723 $this_group = $frow['group_id'];
3724 if (substr($prev_group, 0, 1) === substr($this_group, 0, 1)) {
3725 // Skip sub-groups, they will not start a new tab.
3726 continue;
3728 $prev_group = $this_group;
3729 $group_name = $grparr[$this_group]['grp_title'];
3730 if ($group_name === 'Employer' && $GLOBALS['omit_employers']) {
3731 continue;
3734 <li <?php echo $first ? 'class="current"' : '' ?>>
3735 <a href="#" id="header_tab_<?php echo attr($group_name); ?>">
3736 <?php echo text(xl_layout_label($group_name)); ?></a>
3737 </li>
3738 <?php
3739 $first = false;
3741 } // End this layout, there may be more in the case of history.
3744 // This generates the tab contents of the display version of a form.
3746 function display_layout_tabs_data($formtype, $result1, $result2 = '')
3748 global $item_count, $cell_count, $last_group, $CPR;
3750 if ('HIS' == $formtype) {
3751 $formtype .= '%'; // TBD: DEM also?
3753 $pres = sqlStatement(
3754 "SELECT grp_form_id, grp_seq, grp_title " .
3755 "FROM layout_group_properties " .
3756 "WHERE grp_form_id LIKE ? AND grp_group_id = '' " .
3757 "ORDER BY grp_seq, grp_title, grp_form_id",
3758 array("$formtype")
3760 $first = true;
3762 // This loops once per layout. Only Patient History can have multiple layouts.
3763 while ($prow = sqlFetchArray($pres)) {
3764 $formtype = $prow['grp_form_id'];
3765 $last_group = '';
3766 $cell_count = 0;
3767 $item_count = 0;
3769 $grparr = array();
3770 getLayoutProperties($formtype, $grparr, '*');
3772 $TOPCPR = empty($grparr['']['grp_columns']) ? 4 : $grparr['']['grp_columns'];
3774 // By selecting distinct group_id from layout_options we avoid empty groups.
3775 $fres = sqlStatement("SELECT distinct group_id FROM layout_options " .
3776 "WHERE form_id = ? AND uor > 0 " .
3777 "ORDER BY group_id", array($formtype));
3779 $prev_group = '';
3781 // This loops once per group within a given layout.
3782 while ($frow = sqlFetchArray($fres)) {
3783 $this_group = isset($frow['group_id']) ? $frow['group_id'] : "" ;
3785 if ($grparr[$this_group]['grp_title'] === 'Employer' && $GLOBALS['omit_employers']) {
3786 continue;
3788 $CPR = empty($grparr[$this_group]['grp_columns']) ? $TOPCPR : $grparr[$this_group]['grp_columns'];
3789 $subtitle = empty($grparr[$this_group]['grp_subtitle']) ? '' : xl_layout_label($grparr[$this_group]['grp_subtitle']);
3791 $group_fields_query = sqlStatement(
3792 "SELECT * FROM layout_options " .
3793 "WHERE form_id = ? AND uor > 0 AND group_id = ? " .
3794 "ORDER BY seq",
3795 array($formtype, $this_group)
3798 if (substr($this_group, 0, 1) !== substr($prev_group, 0, 1)) {
3799 // Each new top level group gets its own tab div.
3800 if (!$first) {
3801 echo "</div>\n";
3803 echo "<div class='tab" . ($first ? ' current' : '') . "'>\n";
3805 echo "<table border='0' cellpadding='0'>\n";
3807 // This loops once per field within a given group.
3808 while ($group_fields = sqlFetchArray($group_fields_query)) {
3809 $titlecols = $group_fields['titlecols'];
3810 $datacols = $group_fields['datacols'];
3811 $data_type = $group_fields['data_type'];
3812 $field_id = $group_fields['field_id'];
3813 $list_id = $group_fields['list_id'];
3814 $currvalue = '';
3815 $edit_options = $group_fields['edit_options'];
3816 $jump_new_row = isOption($edit_options, 'J');
3817 $prepend_blank_row = isOption($edit_options, 'K');
3818 $span_col_row = isOption($edit_options, 'SP');
3820 if ($formtype == 'DEM') {
3821 if (strpos($field_id, 'em_') === 0) {
3822 // Skip employer related fields, if it's disabled.
3823 if ($GLOBALS['omit_employers']) {
3824 continue;
3827 $tmp = substr($field_id, 3);
3828 if (isset($result2[$tmp])) {
3829 $currvalue = $result2[$tmp];
3831 } else {
3832 if (isset($result1[$field_id])) {
3833 $currvalue = $result1[$field_id];
3836 } else {
3837 if (isset($result1[$field_id])) {
3838 $currvalue = $result1[$field_id];
3842 // Skip this field if action conditions call for that.
3843 // Note this also accumulates info for subsequent skip tests.
3844 $skip_this_field = isSkipped($group_fields, $currvalue) == 'skip';
3846 // Skip this field if its do-not-print option is set.
3847 if (isOption($edit_options, 'X') !== false) {
3848 $skip_this_field = true;
3851 // Handle a data category (group) change.
3852 if (strcmp($this_group, $last_group) != 0) {
3853 $group_name = $grparr[$this_group]['grp_title'];
3854 // totally skip generating the employer category, if it's disabled.
3855 if ($group_name === 'Employer' && $GLOBALS['omit_employers']) {
3856 continue;
3858 $last_group = $this_group;
3861 // Handle starting of a new row.
3862 if (($titlecols > 0 && $cell_count >= $CPR) || $cell_count == 0 || $prepend_blank_row || $jump_new_row) {
3863 disp_end_row();
3864 if ($subtitle) {
3865 // Group subtitle exists and is not displayed yet.
3866 echo "<tr><td class='label' style='background-color: var(--gray300); padding: 4px' colspan='$CPR'>" . text($subtitle) . "</td></tr>\n";
3867 echo "<tr><td class='label' style='height: 5px' colspan='$CPR'></td></tr>\n";
3868 $subtitle = '';
3870 if ($prepend_blank_row) {
3871 echo "<tr><td class='label' style='font-size:25%' colspan='$CPR'>&nbsp;</td></tr>\n";
3873 echo "<tr>";
3876 if ($item_count == 0 && $titlecols == 0) {
3877 $titlecols = 1;
3880 // Handle starting of a new label cell.
3881 if ($titlecols > 0 || $span_col_row) {
3882 disp_end_cell();
3883 $titlecols = $span_col_row ? 0 : $titlecols;
3884 $titlecols_esc = htmlspecialchars($titlecols, ENT_QUOTES);
3885 $field_id_label = 'label_' . $group_fields['field_id'];
3886 if (!$span_col_row) {
3887 echo "<td class='label_custom' colspan='$titlecols_esc' id='" . attr($field_id_label) . "'";
3888 echo ">";
3890 $cell_count += $titlecols;
3893 ++$item_count;
3895 if ($datacols == 0) {
3896 // Data will be in the same cell, so prevent wrapping to a new line.
3897 echo "<span class='text-nowrap mr-2'>";
3900 $field_id_label = 'label_' . $group_fields['field_id'];
3901 if (!$span_col_row) {
3902 echo "<span id='" . attr($field_id_label) . "'>";
3903 if ($skip_this_field) {
3904 // No label because skipping
3905 } elseif ($group_fields['title']) {
3906 $tmp = xl_layout_label($group_fields['title']);
3907 echo text($tmp);
3908 // Append colon only if label does not end with punctuation.
3909 if (!str_contains('?!.,:-=', $tmp[strlen($tmp) - 1])) {
3910 echo ':';
3912 } else {
3913 echo "&nbsp;";
3915 echo "</span>";
3918 // Handle starting of a new data cell.
3919 if ($datacols > 0) {
3920 disp_end_cell();
3921 $datacols = $span_col_row ? $CPR : $datacols;
3922 $datacols_esc = htmlspecialchars($datacols, ENT_QUOTES);
3923 $field_id = 'text_' . $group_fields['field_id'];
3924 echo "<td class='text data' colspan='$datacols_esc' id='" . attr($field_id) . "' data-value='" . attr($currvalue) . "'";
3925 if (!$skip_this_field && $data_type == 3) {
3926 // Textarea gets a light grey border.
3927 echo " style='border: 1px solid var(--gray400)'";
3929 echo ">";
3930 $cell_count += $datacols;
3931 } else {
3932 $field_id = 'text_' . $group_fields['field_id'];
3933 echo "<span id='" . attr($field_id) . "' style='display: none'>" . text($currvalue) . "</span>";
3936 ++$item_count;
3937 if (!$skip_this_field) {
3938 if ($item_count > 1) {
3939 echo "&nbsp;";
3941 echo generate_display_field($group_fields, $currvalue);
3943 if ($datacols == 0) {
3944 // End nowrap
3945 echo "</span> "; // space to allow wrap between spans
3947 } // end field
3949 disp_end_row();
3951 // End table for the group.
3952 echo "</table>\n";
3954 $prev_group = $this_group;
3955 $first = false;
3956 } // End this group.
3957 } // End this layout, there may be more in the case of history.
3959 if (!$first) {
3960 echo "</div>\n";
3964 // This generates the tab contents of the data entry version of a form.
3966 function display_layout_tabs_data_editable($formtype, $result1, $result2 = '')
3968 global $item_count, $cell_count, $last_group, $CPR, $condition_str, $BS_COL_CLASS;
3970 if ('HIS' == $formtype) {
3971 $formtype .= '%'; // TBD: DEM also?
3973 $pres = sqlStatement(
3974 "SELECT grp_form_id, grp_seq, grp_title " .
3975 "FROM layout_group_properties " .
3976 "WHERE grp_form_id LIKE ? AND grp_group_id = '' " .
3977 "ORDER BY grp_seq, grp_title, grp_form_id",
3978 array("$formtype")
3980 $first = true;
3981 $condition_str = '';
3983 // This loops once per layout. Only Patient History can have multiple layouts.
3984 while ($prow = sqlFetchArray($pres)) {
3985 $formtype = $prow['grp_form_id'];
3986 $last_group = '';
3987 $cell_count = 0;
3988 $item_count = 0;
3990 $grparr = array();
3991 getLayoutProperties($formtype, $grparr, '*');
3993 $TOPCPR = empty($grparr['']['grp_columns']) ? 4 : $grparr['']['grp_columns'];
3995 // Check the children of each top-level group to see if any of them are initially open.
3996 // If not, make the first such child initially open.
3997 foreach ($grparr as $tmprow1) {
3998 if (strlen($tmprow1['grp_group_id']) == 1) {
3999 $got_init_open = false;
4000 $keyfirst = false;
4001 foreach ($grparr as $key2 => $tmprow2) {
4002 if (substr($tmprow2['grp_group_id'], 0, 1) == $tmprow1['grp_group_id'] && strlen($tmprow2['grp_group_id']) == 2) {
4003 if (!$keyfirst) {
4004 $keyfirst = $key2;
4006 if ($tmprow2['grp_init_open']) {
4007 $got_init_open = true;
4011 if (!$got_init_open && $keyfirst) {
4012 $grparr[$keyfirst]['grp_init_open'] = 1;
4017 // Variables $gs_* are context for the group set in the current tab.
4018 $gs_display_style = 'block';
4019 // This string is the active group levels representing the current display state.
4020 // Each leading substring represents an instance of nesting.
4021 // As each new group is encountered, groups will be closed and opened as needed
4022 // until the display state matches the new group.
4023 $gs_group_levels = '';
4025 // By selecting distinct group_id from layout_options we avoid empty groups.
4026 $fres = sqlStatement("SELECT distinct group_id FROM layout_options " .
4027 "WHERE form_id = ? AND uor > 0 " .
4028 "ORDER BY group_id", array($formtype));
4030 // This loops once per group within a given layout.
4031 while ($frow = sqlFetchArray($fres)) {
4032 $this_group = $frow['group_id'];
4033 $group_name = $grparr[$this_group]['grp_title'];
4034 $group_name_esc = text($group_name);
4036 if ($grparr[$this_group]['grp_title'] === 'Employer' && $GLOBALS['omit_employers']) {
4037 continue;
4039 $CPR = empty($grparr[$this_group]['grp_columns']) ? $TOPCPR : $grparr[$this_group]['grp_columns'];
4040 $subtitle = empty($grparr[$this_group]['grp_subtitle']) ? '' : xl_layout_label($grparr[$this_group]['grp_subtitle']);
4042 $group_fields_query = sqlStatement("SELECT * FROM layout_options " .
4043 "WHERE form_id = ? AND uor > 0 AND group_id = ? " .
4044 "ORDER BY seq", array($formtype, $this_group));
4046 $gs_this_levels = $this_group;
4047 // Compute $gs_i as the number of initial matching levels.
4048 $gs_i = 0;
4049 $tmp = min(strlen($gs_this_levels), strlen($gs_group_levels));
4050 while ($gs_i < $tmp && $gs_this_levels[$gs_i] == $gs_group_levels[$gs_i]) {
4051 ++$gs_i;
4054 // Close any groups that we are done with.
4055 while (strlen($gs_group_levels) > $gs_i) {
4056 $gs_group_name = $grparr[$gs_group_levels]['grp_title'];
4057 if (strlen($gs_group_levels) > 1) {
4058 // No div for an empty sub-group name.
4059 if (strlen($gs_group_name)) {
4060 echo "</div>\n";
4062 } else {
4063 // This is the top group level so ending this tab and will start a new one.
4064 echo "</div>\n";
4066 $gs_group_levels = substr($gs_group_levels, 0, -1); // remove last character
4069 // If there are any new groups, open them.
4070 while ($gs_i < strlen($gs_this_levels)) {
4071 $gs_group_levels .= $gs_this_levels[$gs_i++];
4072 $gs_group_name = $grparr[substr($gs_group_levels, 0, $gs_i)]['grp_title'];
4073 $gs_init_open = $grparr[substr($gs_group_levels, 0, $gs_i)]['grp_init_open'];
4074 // Compute a short unique identifier for this group.
4075 $gs_group_seq = "grp-$formtype-$gs_group_levels";
4076 if ($gs_i <= 1) {
4077 // Top level group so new tab.
4078 echo "<div class='tab" . ($first ? ' current' : '') . "' id='tab_$group_name_esc'>\n";
4079 } else {
4080 // Not a new tab so start the group inline.
4081 // If group name is blank, no checkbox or div.
4082 if (strlen($gs_group_name)) {
4083 echo "<br /><span class='bold'><input type='checkbox' name='form_cb_" .
4084 attr($gs_group_seq) . "' value='1' " .
4085 "onclick='return divclick(this," . attr_js('div_' . $gs_group_seq) . ");'";
4086 $gs_display_style = $gs_init_open ? 'block' : 'none';
4087 if ($gs_display_style == 'block') {
4088 echo " checked";
4090 echo " /><b>" . text(xl_layout_label($gs_group_name)) . "</b></span>\n";
4091 echo "<div id='div_" . attr($gs_group_seq) .
4092 "' class='section' style='display:" . attr($gs_display_style) . ";'>\n";
4097 // Each group or subgroup has its own separate container.
4098 $gs_group_table_active = true;
4099 echo "<div class='container-fluid lbfdata'>\n";
4100 if ($subtitle) {
4101 // There is a group subtitle so show it.
4102 $bs_cols = $CPR * intval(12 / $CPR);
4103 echo "<div class='row mb-2'>";
4104 echo "<div class='$BS_COL_CLASS-$bs_cols' style='color:#0000ff'>" . text($subtitle) . "</div>";
4105 echo "</div>\n";
4108 // This loops once per field within a given group.
4109 while ($group_fields = sqlFetchArray($group_fields_query)) {
4110 $titlecols = $group_fields['titlecols'];
4111 $datacols = $group_fields['datacols'];
4112 $data_type = $group_fields['data_type'];
4113 $field_id = $group_fields['field_id'];
4114 $list_id = $group_fields['list_id'];
4115 $backup_list = $group_fields['list_backup_id'];
4116 $currvalue = '';
4117 $action = 'skip';
4118 $jump_new_row = isOption($group_fields['edit_options'], 'J');
4119 $prepend_blank_row = isOption($group_fields['edit_options'], 'K');
4120 $span_col_row = isOption($group_fields['edit_options'], 'SP');
4122 // Accumulate action conditions into a JSON expression for the browser side.
4123 accumActionConditions($group_fields, $condition_str);
4125 if ($formtype == 'DEM') {
4126 if (strpos($field_id, 'em_') === 0) {
4127 // Skip employer related fields, if it's disabled.
4128 if ($GLOBALS['omit_employers']) {
4129 continue;
4132 $tmp = substr($field_id, 3);
4133 if (isset($result2[$tmp])) {
4134 $currvalue = $result2[$tmp];
4136 } else {
4137 if (isset($result1[$field_id])) {
4138 $currvalue = $result1[$field_id];
4141 } else {
4142 if (isset($result1[$field_id])) {
4143 $currvalue = $result1[$field_id];
4147 // Handle a data category (group) change.
4148 if (strcmp($this_group, $last_group) != 0) {
4149 // totally skip generating the employer category, if it's disabled.
4150 if ($group_name === 'Employer' && $GLOBALS['omit_employers']) {
4151 continue;
4154 $last_group = $this_group;
4157 // Handle starting of a new row.
4158 if (($titlecols > 0 && $cell_count >= $CPR) || $cell_count == 0 || $prepend_blank_row || $jump_new_row) {
4159 bs_disp_end_row();
4160 $bs_cols = $CPR * intval(12 / $CPR);
4161 if ($subtitle) {
4162 // Group subtitle exists and is not displayed yet.
4163 echo "<div class='form-row mb-2'>";
4164 echo "<div class='$BS_COL_CLASS-$bs_cols p-2 label' style='background-color: var(--gray300)'>" . text($subtitle) . "</div>";
4165 echo "</div>\n";
4166 $subtitle = '';
4168 if ($prepend_blank_row) {
4169 echo "<div class='form-row'>";
4170 echo "<div class='$BS_COL_CLASS-$bs_cols label' style='font-size: 25%'>&nbsp;</div>";
4171 echo "</div>\n";
4173 echo "<div class='form-row'>";
4176 if ($item_count == 0 && $titlecols == 0) {
4177 $titlecols = 1;
4180 // Handle starting of a new label cell.
4181 if ($titlecols > 0 || $span_col_row) {
4182 bs_disp_end_cell();
4183 $titlecols = $span_col_row ? 0 : $titlecols;
4184 $bs_cols = $titlecols * intval(12 / $CPR);
4185 echo "<div class='$BS_COL_CLASS-$bs_cols pt-1 label_custom' ";
4186 echo "id='label_id_" . attr($field_id) . "'";
4187 echo ">";
4188 $cell_count += $titlecols;
4191 // $item_count is the number of title and data items in the current cell.
4192 ++$item_count;
4194 if ($datacols == 0) {
4195 // Data will be in the same cell, so prevent wrapping to a new line.
4196 echo "<span class='text-nowrap mr-2'>";
4199 if (!$span_col_row) {
4200 if ($group_fields['title']) {
4201 $tmp = xl_layout_label($group_fields['title']);
4202 echo text($tmp);
4203 // Append colon only if label does not end with punctuation.
4204 if (strpos('?!.,:-=', substr($tmp, -1, 1)) === false) {
4205 echo ':';
4207 } else {
4208 echo "&nbsp;";
4212 // Handle starting of a new data cell.
4213 if ($datacols > 0) {
4214 bs_disp_end_cell();
4215 $field_id = 'text_' . $group_fields['field_id'];
4216 $datacols = $span_col_row ? $CPR : $datacols;
4217 $bs_cols = $datacols * intval(12 / $CPR);
4218 echo "<div class='$BS_COL_CLASS-$bs_cols'";
4219 echo " id='value_id_" . attr($field_id) . "'";
4220 echo ">";
4221 $cell_count += $datacols;
4224 ++$item_count;
4225 if ($item_count > 1) {
4226 echo "&nbsp;";
4228 // 'smallform' can be used to add arbitrary CSS classes. Note the leading space.
4229 $group_fields['smallform'] = ' form-control-sm mb-1 mw-100';
4230 echo generate_form_field($group_fields, $currvalue);
4231 if ($datacols == 0) {
4232 // End nowrap
4233 echo "</span> "; // space to allow wrap between spans
4235 } // End of fields for this group.
4237 bs_disp_end_row(); // TBD: Does this belong here?
4238 echo "</div>\n"; // end container-fluid
4239 $first = false;
4240 } // End this group.
4242 // Close any groups still open.
4243 while (strlen($gs_group_levels) > 0) {
4244 $gs_group_name = $grparr[$gs_group_levels]['grp_title'];
4245 if (strlen($gs_group_levels) > 1) {
4246 // No div for an empty sub-group name.
4247 if (strlen($gs_group_name)) {
4248 echo "</div>\n";
4250 } else {
4251 // This is the top group level so ending this tab and will start a new one.
4252 echo "</div>\n";
4254 $gs_group_levels = substr($gs_group_levels, 0, -1); // remove last character
4256 } // End this layout, there may be more in the case of history.
4259 // From the currently posted HTML form, this gets the value of the
4260 // field corresponding to the provided layout_options table row.
4262 function get_layout_form_value($frow, $prefix = 'form_')
4264 $maxlength = empty($frow['max_length']) ? 0 : intval($frow['max_length']);
4265 $data_type = $frow['data_type'];
4266 $field_id = $frow['field_id'];
4267 $value = '';
4268 if (isset($_POST["$prefix$field_id"])) {
4269 if ($data_type == 4) {
4270 $modtmp = isOption($frow['edit_options'], 'F') === false ? 0 : 1;
4271 if (!$modtmp) {
4272 $value = DateToYYYYMMDD($_POST["$prefix$field_id"]);
4273 } else {
4274 $value = DateTimeToYYYYMMDDHHMMSS($_POST["$prefix$field_id"]);
4276 } elseif ($data_type == 21) {
4277 if (!$frow['list_id']) {
4278 if (!empty($_POST["form_$field_id"])) {
4279 $value = xlt('Yes');
4281 } else {
4282 // $_POST["$prefix$field_id"] is an array of checkboxes and its keys
4283 // must be concatenated into a |-separated string.
4284 foreach ($_POST["$prefix$field_id"] as $key => $val) {
4285 if (strlen($value)) {
4286 $value .= '|';
4288 $value .= $key;
4291 } elseif ($data_type == 22) {
4292 // $_POST["$prefix$field_id"] is an array of text fields to be imploded
4293 // into "key:value|key:value|...".
4294 foreach ($_POST["$prefix$field_id"] as $key => $val) {
4295 $val = str_replace('|', ' ', $val);
4296 if (strlen($value)) {
4297 $value .= '|';
4300 $value .= "$key:$val";
4302 } elseif ($data_type == 23) {
4303 // $_POST["$prefix$field_id"] is an array of text fields with companion
4304 // radio buttons to be imploded into "key:n:notes|key:n:notes|...".
4305 foreach ($_POST["$prefix$field_id"] as $key => $val) {
4306 $restype = $_POST["radio_{$field_id}"][$key] ?? null;
4307 if (empty($restype)) {
4308 $restype = '0';
4311 $val = str_replace('|', ' ', $val);
4312 if (strlen($value)) {
4313 $value .= '|';
4316 $value .= "$key:$restype:$val";
4318 } elseif ($data_type == 25) {
4319 // $_POST["$prefix$field_id"] is an array of text fields with companion
4320 // checkboxes to be imploded into "key:n:notes|key:n:notes|...".
4321 foreach ($_POST["$prefix$field_id"] as $key => $val) {
4322 $restype = empty($_POST["check_{$field_id}"][$key]) ? '0' : '1';
4323 $val = str_replace('|', ' ', $val);
4324 if (strlen($value)) {
4325 $value .= '|';
4328 $value .= "$key:$restype:$val";
4330 } elseif ($data_type == 28 || $data_type == 32) {
4331 // $_POST["$prefix$field_id"] is an date text fields with companion
4332 // radio buttons to be imploded into "notes|type|date".
4333 $restype = $_POST["radio_{$field_id}"] ?? '';
4334 if (empty($restype)) {
4335 $restype = '0';
4338 $resdate = DateToYYYYMMDD(str_replace('|', ' ', $_POST["date_$field_id"]));
4339 $resnote = str_replace('|', ' ', $_POST["$prefix$field_id"]);
4340 if ($data_type == 32) {
4341 //VicarePlus :: Smoking status data is imploded into "note|type|date|list".
4342 $reslist = str_replace('|', ' ', $_POST["$prefix$field_id"]);
4343 $res_text_note = str_replace('|', ' ', $_POST["{$prefix}text_$field_id"]);
4344 $value = "$res_text_note|$restype|$resdate|$reslist";
4345 } else {
4346 $value = "$resnote|$restype|$resdate";
4348 } elseif ($data_type == 37) {
4349 // $_POST["form_$field_id"] is an array of arrays of 3 text fields with companion
4350 // radio button set to be encoded as json.
4351 $tmparr = array();
4352 foreach ($_POST["form_$field_id"] as $key => $valarr) {
4353 // Each $key here is a list item ID. $valarr has 3 text field values keyed on 0, 2 and 3.
4354 $tmparr[$key][0] = $valarr['0'];
4355 $tmparr[$key][1] = $_POST["radio_{$field_id}"][$key];
4356 $tmparr[$key][2] = $valarr['2'];
4357 $tmparr[$key][3] = $valarr['3'];
4359 $value .= json_encode($tmparr);
4360 } elseif ($data_type == 36 || $data_type == 44 || $data_type == 45 || $data_type == 33) {
4361 $value_array = $_POST["form_$field_id"];
4362 $i = 0;
4363 foreach ($value_array as $key => $valueofkey) {
4364 if ($i == 0) {
4365 $value = $valueofkey;
4366 } else {
4367 $value = $value . "|" . $valueofkey;
4370 $i++;
4372 } elseif ($data_type == 46) {
4373 $reslist = trim($_POST["$prefix$field_id"]);
4374 if (preg_match('/^comment_/', $reslist)) {
4375 $res_comment = str_replace('|', ' ', $_POST["{$prefix}text_$field_id"]);
4376 $value = $reslist . "|" . $res_comment;
4377 } else {
4378 $value = $_POST["$prefix$field_id"];
4380 } elseif ($data_type == 52) {
4381 $value_array = $_POST["form_$field_id"];
4382 $i = 0;
4383 foreach ($value_array as $key => $valueofkey) {
4384 if ($i == 0) {
4385 $value = $valueofkey;
4386 } else {
4387 $value = $value . "|" . $valueofkey;
4390 $i++;
4392 } else {
4393 $value = $_POST["$prefix$field_id"];
4397 // Better to die than to silently truncate data!
4398 if ($maxlength && $maxlength != 0 && strlen(trim($value)) > $maxlength && !$frow['list_id']) {
4399 die(htmlspecialchars(xl('ERROR: Field') . " '$field_id' " . xl('is too long'), ENT_NOQUOTES) .
4400 ":<br />&nbsp;<br />" . htmlspecialchars($value, ENT_NOQUOTES));
4403 if (is_string($value)) {
4404 return trim($value);
4405 } else {
4406 return $value;
4410 // Generate JavaScript validation logic for the required fields.
4412 function generate_layout_validation($form_id)
4414 if ('HIS' == $form_id) {
4415 $form_id .= '%'; // TBD: DEM also?
4417 $pres = sqlStatement(
4418 "SELECT grp_form_id, grp_seq, grp_title " .
4419 "FROM layout_group_properties " .
4420 "WHERE grp_form_id LIKE ? AND grp_group_id = '' " .
4421 "ORDER BY grp_seq, grp_title, grp_form_id",
4422 array("$form_id")
4424 while ($prow = sqlFetchArray($pres)) {
4425 $form_id = $prow['grp_form_id'];
4427 $fres = sqlStatement("SELECT * FROM layout_options " .
4428 "WHERE form_id = ? AND uor > 0 AND field_id != '' " .
4429 "ORDER BY group_id, seq", array($form_id));
4431 while ($frow = sqlFetchArray($fres)) {
4432 $data_type = $frow['data_type'];
4433 $field_id = $frow['field_id'];
4434 $fldtitle = $frow['title'];
4435 if (!$fldtitle) {
4436 $fldtitle = $frow['description'];
4439 $fldname = attr("form_$field_id");
4441 if ($data_type == 40) {
4442 $fldid = "form_" . $field_id;
4443 // Move canvas image data to its hidden form field so the server will get it.
4444 echo
4445 " var canfld = f[" . js_escape($fldid) . "];\n" .
4446 " if (canfld) canfld.value = lbfCanvasGetData(" . js_escape($fldid) . ");\n";
4447 continue;
4449 if ($data_type == 41 || $data_type == 42) {
4450 $fldid = "form_" . $field_id;
4451 // Move canvas image data to its hidden form field so the server will get it.
4452 echo " lbfSetSignature(" . js_escape($fldid) . ");\n";
4453 continue;
4455 if ($frow['uor'] < 2) {
4456 continue;
4459 echo " if (f.$fldname && !f.$fldname.disabled) {\n";
4460 switch ($data_type) {
4461 case 1:
4462 case 11:
4463 case 12:
4464 case 13:
4465 case 14:
4466 case 26:
4467 echo
4468 " if (f.$fldname.selectedIndex <= 0) {\n" .
4469 " alert(" . xlj('Please choose a value for') . " + " .
4470 "\":\\n\" + " . js_escape(xl_layout_label($fldtitle)) . ");\n" .
4471 " if (f.$fldname.focus) f.$fldname.focus();\n" .
4472 " return false;\n" .
4473 " }\n";
4474 break;
4475 case 33:
4476 echo
4477 " if (f.$fldname.selectedIndex <= 0) {\n" .
4478 " if (f.$fldname.focus) f.$fldname.focus();\n" .
4479 " errMsgs[errMsgs.length] = " . js_escape(xl_layout_label($fldtitle)) . "; \n" .
4480 " }\n";
4481 break;
4482 case 27: // radio buttons
4483 echo
4484 " var i = 0;\n" .
4485 " for (; i < f.$fldname.length; ++i) if (f.{$fldname}[i].checked) break;\n" .
4486 " if (i >= f.$fldname.length) {\n" .
4487 " alert(" . xlj('Please choose a value for') . " + " .
4488 "\":\\n\" + " . js_escape(xl_layout_label($fldtitle)) . ");\n" .
4489 " return false;\n" .
4490 " }\n";
4491 break;
4492 case 2:
4493 case 3:
4494 case 4:
4495 case 15:
4496 echo
4497 " if (trimlen(f.$fldname.value) == 0) {\n" .
4498 " if (f.$fldname.focus) f.$fldname.focus();\n" .
4499 " $('#" . $fldname . "').parents('div.tab').each( function(){ var tabHeader = $('#header_' + $(this).attr('id') ); tabHeader.css('color','var(--danger)'); } ); " .
4500 " $('#" . $fldname . "').attr('style','background: var(--danger)'); \n" .
4501 " errMsgs[errMsgs.length] = " . js_escape(xl_layout_label($fldtitle)) . "; \n" .
4502 " } else { " .
4503 " $('#" . $fldname . "').attr('style',''); " .
4504 " $('#" . $fldname . "').parents('div.tab').each( function(){ var tabHeader = $('#header_' + $(this).attr('id') ); tabHeader.css('color',''); } ); " .
4505 " } \n";
4506 break;
4507 case 36: // multi select
4508 echo
4509 " var multi_select=f['$fldname" . "[]']; \n " .
4510 " var multi_choice_made=false; \n" .
4511 " for (var options_index=0; options_index < multi_select.length; options_index++) { " .
4512 " multi_choice_made=multi_choice_made || multi_select.options[options_index].selected; \n" .
4513 " } \n" .
4514 " if(!multi_choice_made)
4515 errMsgs[errMsgs.length] = " . js_escape(xl_layout_label($fldtitle)) . "; \n" .
4517 break;
4519 echo " }\n";
4521 } // End this layout, there may be more in the case of history.
4525 * DROPDOWN FOR FACILITIES
4527 * build a dropdown with all facilities
4529 * @param string $selected - name of the currently selected facility
4530 * use '0' for "unspecified facility"
4531 * use '' for "All facilities" (the default)
4532 * @param string $name - the name/id for select form (defaults to "form_facility")
4533 * @param boolean $allow_unspecified - include an option for "unspecified" facility
4534 * defaults to true
4535 * @return void - just echo the html encoded string
4537 * Note: This should become a data-type at some point, according to Brady
4539 function dropdown_facility(
4540 $selected = '',
4541 $name = 'form_facility',
4542 $allow_unspecified = true,
4543 $allow_allfacilities = true,
4544 $disabled = '',
4545 $onchange = '',
4546 $multiple = false,
4547 $class = ''
4549 global $facilityService;
4551 $have_selected = false;
4552 $fres = $facilityService->getAllFacility();
4553 $id = $name;
4555 if ($multiple) {
4556 $name = $name . "[]";
4558 echo " <select class='form-control$class";
4559 if ($multiple) {
4560 echo " select-dropdown";
4562 echo "' name='" . attr($name) . "' id='" . attr($id) . "'";
4563 if ($onchange) {
4564 echo " onchange='$onchange'";
4567 if ($multiple) {
4568 echo " multiple='multiple'";
4571 echo " $disabled>\n";
4573 if ($allow_allfacilities) {
4574 $option_value = '';
4575 $option_selected_attr = '';
4576 if ($selected == '') {
4577 $option_selected_attr = ' selected="selected"';
4578 $have_selected = true;
4581 $option_content = '-- ' . xl('All Facilities') . ' --';
4582 echo " <option value='" . attr($option_value) . "' $option_selected_attr>" . text($option_content) . "</option>\n";
4583 } elseif ($allow_unspecified) {
4584 $option_value = '0';
4585 $option_selected_attr = '';
4586 if ($selected == '0') {
4587 $option_selected_attr = ' selected="selected"';
4588 $have_selected = true;
4591 $option_content = '-- ' . xl('Unspecified') . ' --';
4592 echo " <option value='" . attr($option_value) . "' $option_selected_attr>" . text($option_content) . "</option>\n";
4595 foreach ($fres as $frow) {
4596 $facility_id = $frow['id'];
4597 $option_value = $facility_id;
4598 $option_selected_attr = '';
4599 if ($multiple) {
4600 $selectedValues = explode("|", $selected);
4602 if (in_array($facility_id, $selectedValues)) {
4603 $option_selected_attr = ' selected="selected"';
4604 $have_selected = true;
4606 } else {
4607 if ($selected == $facility_id) {
4608 $option_selected_attr = ' selected="selected"';
4609 $have_selected = true;
4613 $option_content = $frow['name'];
4614 echo " <option value='" . attr($option_value) . "' $option_selected_attr>" . text($option_content) . "</option>\n";
4617 if ($allow_unspecified && $allow_allfacilities) {
4618 $option_value = '0';
4619 $option_selected_attr = '';
4620 if ($selected == '0') {
4621 $option_selected_attr = ' selected="selected"';
4622 $have_selected = true;
4625 $option_content = '-- ' . xl('Unspecified') . ' --';
4626 echo " <option value='" . attr($option_value) . "' $option_selected_attr>" . text($option_content) . "</option>\n";
4629 if (!$have_selected && !$multiple) {
4630 $option_value = $selected;
4631 $option_label = '(' . xl('Do not change') . ')';
4632 $option_content = xl('Missing or Invalid');
4633 echo " <option value='" . attr($option_value) . "' label='" . attr($option_label) . "' selected='selected'>" . text($option_content) . "</option>\n";
4636 echo " </select>\n";
4640 * Expand Collapse Widget
4641 * This forms the header and functionality component of the widget. The information that is displayed
4642 * then follows this function followed by a closing div tag
4644 * @var $title is the title of the section (already translated)
4645 * @var $label is identifier used in the tag id's and sql columns
4646 * @var $buttonLabel is the button label text (already translated)
4647 * @var $buttonLink is the button link information
4648 * @var $buttonClass is any additional needed class elements for the button tag
4649 * @var $linkMethod is the button link method ('javascript' vs 'html')
4650 * @var $bodyClass is to set class(es) of the body
4651 * @var $auth is a flag to decide whether to show the button
4652 * @var $fixedWidth is to flag whether width is fixed
4653 * @var $forceExpandAlways is a flag to force the widget to always be expanded
4655 * @todo Convert to a modern layout
4657 function expand_collapse_widget($title, $label, $buttonLabel, $buttonLink, $buttonClass, $linkMethod, $bodyClass, $auth, $fixedWidth, $forceExpandAlways = false)
4659 if ($fixedWidth) {
4660 echo "<div class='section-header'>";
4661 } else {
4662 echo "<div class='section-header-dynamic'>";
4665 echo "<table><tr>";
4666 if ($auth) {
4667 // show button, since authorized
4668 // first prepare class string
4669 if ($buttonClass) {
4670 $class_string = "btn btn-primary btn-sm " . $buttonClass;
4671 } else {
4672 $class_string = "btn btn-primary btn-sm";
4675 // next, create the link
4676 if ($linkMethod == "javascript") {
4677 echo "<td><a class='" . attr($class_string) . "' href='javascript:;' onclick='" . $buttonLink . "'";
4678 } else {
4679 echo "<td><a class='" . attr($class_string) . "' href='" . $buttonLink . "'";
4680 if (!isset($_SESSION['patient_portal_onsite_two'])) {
4681 // prevent an error from occuring when calling the function from the patient portal
4682 echo " onclick='top.restoreSession()'";
4686 echo "><span>" .
4687 text($buttonLabel) . "</span></a></td>";
4690 if ($forceExpandAlways) {
4691 // Special case to force the widget to always be expanded
4692 echo "<td><span class='text font-weight-bold'>" . text($title) . "</span>";
4693 $indicatorTag = "style='display: none'";
4696 $indicatorTag = isset($indicatorTag) ? $indicatorTag : "";
4697 echo "<td><a " . $indicatorTag . " href='javascript:;' class='small' onclick='toggleIndicator(this," .
4698 attr_js($label . "_ps_expand") . ")'><span class='text font-weight-bold'>";
4699 echo text($title) . "</span>";
4701 if (isset($_SESSION['patient_portal_onsite_two'])) {
4702 // collapse all entries in the patient portal
4703 $text = xl('expand');
4704 } elseif (getUserSetting($label . "_ps_expand")) {
4705 $text = xl('collapse');
4706 } else {
4707 $text = xl('expand');
4710 echo " (<span class='indicator'>" . text($text) .
4711 "</span>)</a></td>";
4712 echo "</tr></table>";
4713 echo "</div>";
4714 if ($forceExpandAlways) {
4715 // Special case to force the widget to always be expanded
4716 $styling = "";
4717 } elseif (isset($_SESSION['patient_portal_onsite_two'])) {
4718 // collapse all entries in the patient portal
4719 $styling = "style='display: none'";
4720 } elseif (getUserSetting($label . "_ps_expand")) {
4721 $styling = "";
4722 } else {
4723 $styling = "style='display: none'";
4726 if ($bodyClass) {
4727 $styling .= " class='" . attr($bodyClass) . "'";
4730 //next, create the first div tag to hold the information
4731 // note the code that calls this function will then place the ending div tag after the data
4732 echo "<div id='" . attr($label) . "_ps_expand' " . $styling . ">";
4735 //billing_facility fuction will give the dropdown list which contain billing faciliies.
4736 function billing_facility($name, $select)
4738 global $facilityService;
4740 $fres = $facilityService->getAllBillingLocations();
4741 echo " <select id='" . htmlspecialchars($name, ENT_QUOTES) . "' class='form-control' name='" . htmlspecialchars($name, ENT_QUOTES) . "'>";
4742 foreach ($fres as $facrow) {
4743 $selected = ( $facrow['id'] == $select ) ? 'selected="selected"' : '' ;
4744 echo "<option value=" . htmlspecialchars($facrow['id'], ENT_QUOTES) . " $selected>" . htmlspecialchars($facrow['name'], ENT_QUOTES) . "</option>";
4747 echo "</select>";
4750 // Generic function to get the translated title value for a particular list option.
4752 function getListItemTitle($list, $option)
4754 $row = sqlQuery("SELECT title FROM list_options WHERE " .
4755 "list_id = ? AND option_id = ? AND activity = 1", array($list, $option));
4756 if (empty($row['title'])) {
4757 return $option;
4760 return xl_list_label($row['title']);
4763 //function to get the translated title value in Patient Transactions
4764 function getLayoutTitle($list, $option)
4766 $row = sqlQuery("SELECT grp_title FROM layout_group_properties " .
4767 "WHERE grp_mapping = ? AND grp_form_id = ? ", array($list, $option));
4769 if (empty($row['grp_title'])) {
4770 return $option;
4772 return xl_list_label($row['grp_title']);
4774 //Added on 5-jun-2k14 (regarding get the smoking code descriptions)
4775 function getSmokeCodes()
4777 $smoking_codes_arr = array();
4778 $smoking_codes = sqlStatement("SELECT option_id,codes FROM list_options WHERE list_id='smoking_status' AND activity = 1");
4779 while ($codes_row = sqlFetchArray($smoking_codes)) {
4780 $smoking_codes_arr[$codes_row['option_id']] = $codes_row['codes'];
4783 return $smoking_codes_arr;
4786 // Get the current value for a layout based form field.
4787 // Depending on options this might come from lbf_data, patient_data,
4788 // form_encounter, shared_attributes or elsewhere.
4789 // Returns FALSE if the field ID is invalid (layout error).
4791 function lbf_current_value($frow, $formid, $encounter)
4793 global $pid;
4794 $formname = $frow['form_id'];
4795 $field_id = $frow['field_id'];
4796 $source = $frow['source'];
4797 $currvalue = '';
4798 $deffname = $formname . '_default_' . $field_id;
4799 if ($source == 'D' || $source == 'H') {
4800 // Get from patient_data, employer_data or history_data.
4801 if ($source == 'H') {
4802 $table = 'history_data';
4803 $orderby = 'ORDER BY date DESC LIMIT 1';
4804 } elseif (strpos($field_id, 'em_') === 0) {
4805 $field_id = substr($field_id, 3);
4806 $table = 'employer_data';
4807 $orderby = 'ORDER BY date DESC LIMIT 1';
4808 } else {
4809 $table = 'patient_data';
4810 $orderby = '';
4813 // It is an error if the field does not exist, but don't crash.
4814 $tmp = sqlQuery("SHOW COLUMNS FROM " . escape_table_name($table) . " WHERE Field = ?", array($field_id));
4815 if (empty($tmp)) {
4816 return '*?*';
4819 $pdrow = sqlQuery("SELECT `$field_id` AS field_value FROM " . escape_table_name($table) . " WHERE pid = ? $orderby", array($pid));
4820 if (isset($pdrow)) {
4821 $currvalue = $pdrow['field_value'];
4823 } elseif ($source == 'E') {
4824 $sarow = false;
4825 if ($encounter) {
4826 // Get value from shared_attributes of the current encounter.
4827 $sarow = sqlQuery(
4828 "SELECT field_value FROM shared_attributes WHERE " .
4829 "pid = ? AND encounter = ? AND field_id = ?",
4830 array($pid, $encounter, $field_id)
4832 if (!empty($sarow)) {
4833 $currvalue = $sarow['field_value'];
4835 } elseif ($formid) {
4836 // Get from shared_attributes of the encounter that this form is linked to.
4837 // Note the importance of having an index on forms.form_id.
4838 $sarow = sqlQuery(
4839 "SELECT sa.field_value " .
4840 "FROM forms AS f, shared_attributes AS sa WHERE " .
4841 "f.form_id = ? AND f.formdir = ? AND f.deleted = 0 AND " .
4842 "sa.pid = f.pid AND sa.encounter = f.encounter AND sa.field_id = ?",
4843 array($formid, $formname, $field_id)
4845 if (!empty($sarow)) {
4846 $currvalue = $sarow['field_value'];
4848 } else {
4849 // New form and encounter not available, this should not happen.
4851 if (empty($sarow) && !$formid) {
4852 // New form, see if there is a custom default from a plugin.
4853 if (function_exists($deffname)) {
4854 $currvalue = call_user_func($deffname);
4857 } elseif ($source == 'V') {
4858 if ($encounter) {
4859 // Get value from the current encounter's form_encounter.
4860 $ferow = sqlQuery(
4861 "SELECT * FROM form_encounter WHERE " .
4862 "pid = ? AND encounter = ?",
4863 array($pid, $encounter)
4865 if (isset($ferow[$field_id])) {
4866 $currvalue = $ferow[$field_id];
4868 } elseif ($formid) {
4869 // Get value from the form_encounter that this form is linked to.
4870 $ferow = sqlQuery(
4871 "SELECT fe.* " .
4872 "FROM forms AS f, form_encounter AS fe WHERE " .
4873 "f.form_id = ? AND f.formdir = ? AND f.deleted = 0 AND " .
4874 "fe.pid = f.pid AND fe.encounter = f.encounter",
4875 array($formid, $formname)
4877 if (isset($ferow[$field_id])) {
4878 $currvalue = $ferow[$field_id];
4880 } else {
4881 // New form and encounter not available, this should not happen.
4883 } elseif ($formid) {
4884 // This is a normal form field.
4885 $ldrow = sqlQuery("SELECT field_value FROM lbf_data WHERE " .
4886 "form_id = ? AND field_id = ?", array($formid, $field_id));
4887 if (!empty($ldrow)) {
4888 $currvalue = $ldrow['field_value'];
4890 } else {
4891 // New form, see if there is a custom default from a plugin.
4892 if (function_exists($deffname)) {
4893 $currvalue = call_user_func($deffname);
4897 return $currvalue;
4900 function signer_head()
4902 return <<<EOD
4903 <link href="{$GLOBALS['web_root']}/portal/sign/css/signer_modal.css?v={$GLOBALS['v_js_includes']}" rel="stylesheet"/>
4904 <script src="{$GLOBALS['web_root']}/portal/sign/assets/signature_pad.umd.js?v={$GLOBALS['v_js_includes']}"></script>
4905 <script src="{$GLOBALS['web_root']}/portal/sign/assets/signer_api.js?v={$GLOBALS['v_js_includes']}"></script>
4906 EOD;
4909 // This returns stuff that needs to go into the <head> section of a caller using
4910 // the drawable image field type in a form.
4911 // A TRUE argument makes the widget controls smaller.
4913 function lbf_canvas_head($small = true)
4915 $s = <<<EOD
4916 <link href="{$GLOBALS['assets_static_relative']}/literallycanvas/css/literallycanvas.css" rel="stylesheet" />
4917 <script src="{$GLOBALS['assets_static_relative']}/react/build/react-with-addons.min.js"></script>
4918 <script src="{$GLOBALS['assets_static_relative']}/react/build/react-dom.min.js"></script>
4919 <script src="{$GLOBALS['assets_static_relative']}/literallycanvas/js/literallycanvas.min.js"></script>
4920 EOD;
4921 if ($small) {
4922 $s .= <<<EOD
4923 <style>
4924 /* Custom LiterallyCanvas styling.
4925 * This makes the widget 25% less tall and adjusts some other things accordingly.
4927 .literally {
4928 min-height: 100%;
4929 min-width: 300px; /* Was 400, unspecified */
4931 .literally .lc-picker .toolbar-button {
4932 width: 20px;
4933 height: 20px;
4934 line-height: 20px; /* Was 26, 26, 26 */
4936 .literally .color-well {
4937 font-size: 8px;
4938 width: 49px; /* Was 10, 60 */
4940 .literally .color-well-color-container {
4941 width: 21px;
4942 height: 21px; /* Was 28, 28 */
4944 .literally .lc-picker {
4945 width: 50px; /* Was 61 */
4947 .literally .lc-drawing.with-gui {
4948 left: 50px; /* Was 61 */
4950 .literally .lc-options {
4951 left: 50px; /* Was 61 */
4953 .literally .color-picker-popup {
4954 left: 49px;
4955 bottom: 0px; /* Was 60, 31 */
4957 </style>
4958 EOD;
4961 return $s;
4965 * Test if modifier($test) is in array of options for data type.
4967 * @param json array $options ["G","P","T"], ["G"] or could be legacy string with form "GPT", "G", "012"
4968 * @param string $test
4969 * @return boolean
4971 function isOption($options, string $test): bool
4973 if (empty($options) || !isset($test) || $options == "null") {
4974 return false; // why bother?
4976 if (strpos($options, ',') === false) { // not json array of modifiers.
4977 // could be string of char's or single element of json ["RO"] or "TP" or "P" e.t.c.
4978 json_decode($options, true); // test if options json. json_last_error() will return JSON_ERROR_SYNTAX if not.
4979 // if of form ["RO"] (single modifier) means not legacy so continue on.
4980 if (is_string($options) && (json_last_error() !== JSON_ERROR_NONE)) { // nope, it's string.
4981 $t = str_split(trim($options)); // very good chance it's legacy modifier string.
4982 $options = json_encode($t); // make it json array to convert from legacy to new modifier json schema.
4986 $options = json_decode($options, true); // all should now be json
4988 return is_array($options) && in_array($test, $options, true); // finally the truth!