Fixes #5048 - Add Encounter to Transaction Form (#5049)
[openemr.git] / library / options.inc.php
blob10a0b078ddc7af79339fb20c15eee3e9834dd544
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 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
14 // Functions for managing the lists and layouts
16 // Note: there are translation wrappers for the lists and layout labels
17 // at library/translation.inc.php. The functions are titled
18 // xl_list_label() and xl_layout_label() and are controlled by the
19 // $GLOBALS['translate_lists'] and $GLOBALS['translate_layout']
20 // flags in globals.php
22 // Documentation for layout_options.edit_options:
24 // A = Age as years or "xx month(s)"
25 // B = Gestational age as "xx week(s) y day(s)"
26 // C = Capitalize first letter of each word (text fields)
27 // D = Check for duplicates in New Patient form
28 // G = Graphable (for numeric fields in forms supporting historical data)
29 // H = Read-only field copied from static history (this is obsolete)
30 // J = Jump to Next Row
31 // K = Prepend Blank Row
32 // L = Lab Order ("ord_lab") types only (address book)
33 // M = Radio Group Master (currently for radio buttons only)
34 // m = Radio Group Member (currently for radio buttons only)
35 // N = Show in New Patient form
36 // O = Procedure Order ("ord_*") types only (address book)
37 // P = Default to previous value when current value is not yet set
38 // R = Distributor types only (address book)
39 // T = Use description as default Text
40 // DAP = Use description as placeholder
41 // U = Capitalize all letters (text fields)
42 // V = Vendor types only (address book)
43 // 0 = Read Only - the input element's "disabled" property is set
44 // 1 = Write Once (not editable when not empty) (text fields)
45 // 2 = Show descriptions instead of codes for billing code input
47 // note: isOption() returns true/false
49 // NOTE: All of the magic constants for the data types here are found in library/layout.inc.php
51 require_once("user.inc");
52 require_once("patient.inc");
53 require_once("lists.inc");
54 require_once(dirname(dirname(__FILE__)) . "/custom/code_types.inc.php");
56 use OpenEMR\Common\Acl\AclExtended;
57 use OpenEMR\Common\Acl\AclMain;
58 use OpenEMR\Services\EncounterService;
59 use OpenEMR\Services\FacilityService;
60 use OpenEMR\Services\PatientService;
62 $facilityService = new FacilityService();
64 $date_init = "";
65 $membership_group_number = 0;
67 // Our base Bootstrap column class, referenced here and in some other modules.
68 // Using col-lg allow us to have additional breakpoint at col-md.(992px, 768px)
69 // col-md-auto will let BS decide with col-12 always for sm devices.
70 $BS_COL_CLASS = 'col-12 col-md-auto col-lg';
72 function get_pharmacies()
74 return sqlStatement("SELECT d.id, d.name, a.line1, a.city, " .
75 "p.area_code, p.prefix, p.number FROM pharmacies AS d " .
76 "LEFT OUTER JOIN addresses AS a ON a.foreign_id = d.id " .
77 "LEFT OUTER JOIN phone_numbers AS p ON p.foreign_id = d.id " .
78 "AND p.type = 2 " .
79 "ORDER BY a.state, a.city, d.name, p.area_code, p.prefix, p.number");
82 function optionalAge($frow, $date, &$asof, $description = '')
84 $asof = '';
85 if (empty($date)) {
86 return '';
89 $edit_options = $frow['edit_options'] ?? null;
91 $date = substr($date, 0, 10);
92 if (isOption($edit_options, 'A') !== false) {
93 $format = 0;
94 } elseif (isOption($edit_options, 'B') !== false) {
95 $format = 3;
96 } else {
97 return '';
100 if (isOption($frow['form_id'], 'LBF') === false) {
101 $tmp = sqlQuery(
102 "SELECT date FROM form_encounter WHERE " .
103 "pid = ? AND encounter = ? ORDER BY id DESC LIMIT 1",
104 array($GLOBALS['pid'], $GLOBALS['encounter'])
106 if (!empty($tmp['date'])) {
107 $asof = substr($tmp['date'], 0, 10);
110 if ($description === '') {
111 $prefix = ($format ? xl('Gest age') : xl('Age')) . ' ';
112 } else {
113 $prefix = $description . ' ';
115 return $prefix . oeFormatAge($date, $asof, $format);
118 // Function to generate a drop-list.
120 function generate_select_list(
121 $tag_name,
122 $list_id,
123 $currvalue,
124 $title,
125 $empty_name = ' ',
126 $class = '',
127 $onchange = '',
128 $tag_id = '',
129 $custom_attributes = null,
130 $multiple = false, // new #10
131 $backup_list = '', // new #11
132 $ignore_default = false,
133 $include_inactive = false
135 $s = '';
137 $tag_name_esc = attr($tag_name);
139 if ($multiple) {
140 $tag_name_esc = $tag_name_esc . "[]";
143 $s .= "<select name='$tag_name_esc'";
145 if ($multiple) {
146 $s .= " multiple='multiple'";
149 $tag_id_esc = attr($tag_name);
151 if ($tag_id != '') {
152 $tag_id_esc = attr($tag_id);
155 $s .= " id='$tag_id_esc'";
157 if (!empty($class)) {
158 $class_esc = attr($class);
159 $s .= " class='form-control $class_esc'";
160 } else {
161 $s .= " class='form-control'";
164 if ($onchange) {
165 $s .= " onchange='$onchange'";
168 if ($custom_attributes != null && is_array($custom_attributes)) {
169 foreach ($custom_attributes as $attr => $val) {
170 if (isset($custom_attributes [$attr])) {
171 $s .= " " . attr($attr) . "='" . attr($val) . "'";
176 $selectTitle = attr($title);
177 $s .= " title='$selectTitle'>";
178 $selectEmptyName = xlt($empty_name);
179 if ($empty_name) {
180 $s .= "<option value=''>" . $selectEmptyName . "</option>";
183 $got_selected = false;
185 for ($active = 1; $active == 1 || ($active == 0 && $include_inactive); --$active) {
186 if ($include_inactive) {
187 $s .= "<optgroup label='" . ($active ? xla('Active') : xla('Inactive')) . "'>\n";
190 // List order depends on language translation options.
191 // (Note we do not need to worry about the list order in the algorithm
192 // after the below code block since that is where searches for exceptions
193 // are done which include inactive items or items from a backup
194 // list; note these will always be shown at the bottom of the list no matter the
195 // chosen order.)
196 $lang_id = empty($_SESSION['language_choice']) ? '1' : $_SESSION['language_choice'];
197 // sort by title
198 if (!$GLOBALS['translate_lists']) {
199 // do not translate
200 if ($GLOBALS['gb_how_sort_list'] == '0') {
201 // order by seq
202 $order_by_sql = "seq, title";
203 } else { //$GLOBALS['gb_how_sort_list'] == '1'
204 // order by title
205 $order_by_sql = "title, seq";
207 $lres = sqlStatement(
208 "SELECT * FROM list_options WHERE list_id = ? AND activity = ? ORDER BY "
209 . $order_by_sql,
210 array($list_id, $active)
212 } else {
213 // do translate
214 if ($GLOBALS['gb_how_sort_list'] == '0') {
215 // order by seq
216 $order_by_sql = "lo.seq, title";
217 } else { //$GLOBALS['gb_how_sort_list'] == '1'
218 // order by title
219 $order_by_sql = "title, lo.seq";
221 $lres = sqlStatement(
222 "SELECT lo.option_id, lo.is_default, " .
223 "COALESCE((SELECT ld.definition FROM lang_constants AS lc, lang_definitions AS ld " .
224 "WHERE lc.constant_name = lo.title AND ld.cons_id = lc.cons_id AND ld.lang_id = ? " .
225 "AND ld.definition IS NOT NULL AND ld.definition != '' " .
226 "LIMIT 1), lo.title) AS title " .
227 "FROM list_options AS lo " .
228 "WHERE lo.list_id = ? AND lo.activity = ? " .
229 "ORDER BY " . $order_by_sql,
230 array($lang_id, $list_id, $active)
234 while ($lrow = sqlFetchArray($lres)) {
235 $selectedValues = explode("|", $currvalue ?? '');
237 $optionValue = attr($lrow ['option_id']);
238 $s .= "<option value='$optionValue'";
240 if (
241 (strlen($currvalue ?? '') == 0 && $lrow ['is_default'] && !$ignore_default) ||
242 (strlen($currvalue ?? '') > 0 && in_array($lrow ['option_id'], $selectedValues))
244 $s .= " selected";
245 $got_selected = true;
248 // Already has been translated above (if applicable), so do not need to use
249 // the xl_list_label() function here
250 $optionLabel = text($lrow ['title']);
251 $s .= ">$optionLabel</option>\n";
254 if ($include_inactive) {
255 $s .= "</optgroup>\n";
257 } // end $active loop
260 To show the inactive item in the list if the value is saved to database
262 if (!$got_selected && strlen($currvalue ?? '') > 0) {
263 $lres_inactive = sqlStatement("SELECT * FROM list_options " .
264 "WHERE list_id = ? AND activity = 0 AND option_id = ? ORDER BY seq, title", array($list_id, $currvalue));
265 $lrow_inactive = sqlFetchArray($lres_inactive);
266 if (!empty($lrow_inactive['option_id'])) {
267 $optionValue = htmlspecialchars($lrow_inactive['option_id'], ENT_QUOTES);
268 $s .= "<option value='$optionValue' selected>" . htmlspecialchars(xl_list_label($lrow_inactive['title']), ENT_NOQUOTES) . "</option>\n";
269 $got_selected = true;
273 if (!$got_selected && strlen($currvalue ?? '') > 0 && !$multiple) {
274 $list_id = $backup_list;
275 $lrow = sqlQuery("SELECT title FROM list_options WHERE list_id = ? AND option_id = ?", array($list_id,$currvalue));
277 if ($lrow > 0 && !empty($backup_list)) {
278 $selected = text(xl_list_label($lrow['title']));
279 $s .= "<option value='" . attr($currvalue) . "' selected> $selected </option>";
280 $s .= "</select>";
281 } else {
282 $s .= "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
283 $s .= "</select>";
284 $fontTitle = xlt('Please choose a valid selection from the list.');
285 $fontText = xlt('Fix this');
286 $s .= " <span class='text-danger' title='$fontTitle'>$fontText!</span>";
288 } elseif (!$got_selected && strlen($currvalue ?? '') > 0 && $multiple) {
289 //if not found in main list, display all selected values that exist in backup list
290 $list_id = $backup_list;
292 $got_selected_backup = false;
293 if (!empty($backup_list)) {
294 $lres_backup = sqlStatement("SELECT * FROM list_options WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
295 while ($lrow_backup = sqlFetchArray($lres_backup)) {
296 $selectedValues = explode("|", $currvalue);
298 $optionValue = attr($lrow_backup['option_id']);
300 if (in_array($lrow_backup ['option_id'], $selectedValues)) {
301 $s .= "<option value='$optionValue'";
302 $s .= " selected";
303 $optionLabel = text(xl_list_label($lrow_backup ['title']));
304 $s .= ">$optionLabel</option>\n";
305 $got_selected_backup = true;
310 if (!$got_selected_backup) {
311 $selectedValues = explode("|", $currvalue);
312 foreach ($selectedValues as $selectedValue) {
313 $s .= "<option value='" . attr($selectedValue) . "'";
314 $s .= " selected";
315 $s .= ">* " . text($selectedValue) . " *</option>\n";
318 $s .= "</select>";
319 $fontTitle = xlt('Please choose a valid selection from the list.');
320 $fontText = xlt('Fix this');
321 $s .= " <span class='text-danger' title='$fontTitle'>$fontText!</span>";
323 } else {
324 $s .= "</select>";
327 return $s;
330 // Parsing for data type 31, static text.
331 function parse_static_text($frow, $value_allowed = true)
333 $tmp = str_replace("\r\n", "\n", $frow['description']);
334 // Translate if it does not look like HTML.
335 if (substr($tmp, 0, 1) != '<') {
336 $tmp2 = $frow['description'];
337 $tmp3 = xl_layout_label($tmp);
338 if ($tmp3 == $tmp && $tmp2 != $tmp) {
339 // No translation, try again without the CRLF substitution.
340 $tmp3 = xl_layout_label($tmp2);
342 $tmp = nl2br($tmp3);
344 $s = '';
345 if ($frow['source'] == 'D' || $frow['source'] == 'H') {
346 // Source is demographics or history. This case supports value substitution.
347 while (preg_match('/^(.*?)\{(\w+)\}(.*)$/', $tmp, $matches)) {
348 $s .= $matches[1];
349 if ($value_allowed) {
350 $tmprow = $frow;
351 $tmprow['field_id'] = $matches[2];
352 $s .= lbf_current_value($tmprow, 0, 0);
354 $tmp = $matches[3];
357 $s .= $tmp;
358 return $s;
361 function genLabResultsTextItem($name, $value, $outtype, $size, $maxlength, $disabled = '')
363 $string_maxlength = $maxlength ? ("maxlength='" . attr($maxlength) . "'") : '';
364 $s = "<td align='center'>";
365 if ($outtype == 2) {
366 $s .= text($value);
367 } else {
368 $s .= "<input type='text'";
369 if ($outtype == 0) {
370 $s .= " name='" . attr($name) . "' id='" . attr($name) . "'";
372 $s .= " size='" . attr($size) . "' $string_maxlength" .
373 " value='" . attr($value) . "'" .
374 " $under $disabled />";
376 $s .= "&nbsp;</td>";
377 return $s;
380 // $outtype = 0 for form, 1 for print, 2 for display, 3 for plain text.
381 function genLabResults($frow, $currvalue, $outtype = 0, $disabled = '')
383 $field_id = $frow['field_id'];
384 $list_id = $frow['list_id'];
385 $field_id_esc = text($field_id);
386 $under = $outtype == 1 ? "class='under'" : "";
387 $s = '';
389 $avalue = json_decode($currvalue, true);
390 if (empty($avalue)) {
391 $avalue = array();
393 // $avalue[$option_id][0] : gestation
394 // $avalue[$option_id][1] : radio button value
395 // $avalue[$option_id][2] : test value
396 // $avalue[$option_id][3] : notes
398 $maxlength = $frow['max_length'];
399 $fldlength = empty($frow['fld_length']) ? 20 : $frow['fld_length'];
401 $under = $outtype == 1 ? "class='under'" : "";
403 $s .= "<table cellpadding='0' cellspacing='0'>";
404 if ($outtype < 2) {
405 $s .= "<tr>" .
406 "<td class='bold' align='center'>" . xlt('Test/Screening') . "&nbsp;</td>" .
407 "<td class='bold' align='center'>" . xlt('Gest wks') . "&nbsp;</td>" .
408 "<td class='bold' align='center'>&nbsp;" . xlt('N/A') . "&nbsp;</td>" .
409 "<td class='bold' align='center'>" . xlt('Neg/Nrml') . "</td>" .
410 "<td class='bold' align='center'>&nbsp;" . xlt('Pos/Abn') . "&nbsp;</td>" .
411 "<td class='bold' align='center'>" . xlt('Test Value') . "&nbsp;</td>" .
412 "<td class='bold' align='center'>" . xlt('Date/Notes') . "&nbsp;</td>" .
413 "</tr>";
416 $lres = sqlStatement(
417 "SELECT * FROM list_options WHERE " .
418 "list_id = ? AND activity = 1 ORDER BY seq, title",
419 array($list_id)
422 while ($lrow = sqlFetchArray($lres)) {
423 $option_id = $lrow['option_id'];
424 $option_id_esc = text($option_id);
426 if ($outtype >= 2 && empty($avalue[$option_id][1])) {
427 continue;
430 if ($outtype == 3) {
431 if (isset($avalue[$option_id][1]) && $avalue[$option_id][1] == '2') {
432 if ($s !== '') {
433 $s .= '; ';
435 $s .= text(xl_list_label($lrow['title']));
436 $s .= ':' . text($avalue[$option_id][0]);
437 $s .= ':' . text($avalue[$option_id][2]);
438 $s .= ':' . text($avalue[$option_id][3]);
440 continue;
443 $s .= "<tr>";
444 $s .= $outtype == 2 ? "<td class='bold'>" : "<td>";
445 $s .= text(xl_list_label($lrow['title'])) . "&nbsp;</td>";
447 $s .= genLabResultsTextItem(
448 "form_{$field_id_esc}[$option_id_esc][0]",
449 (isset($avalue[$option_id][0]) ? $avalue[$option_id][0] : ''),
450 $outtype,
453 $disabled,
454 $under
457 if ($outtype == 2) {
458 $tmp = isset($avalue[$option_id][1]) ? $avalue[$option_id][1] : '0';
459 $restype = ($tmp == '1') ? xl('Normal') : (($tmp == '2') ? xl('Abnormal') : xl('N/A'));
460 $s .= "<td>" . text($restype) . "&nbsp;</td>";
461 } else {
462 for ($i = 0; $i < 3; ++$i) {
463 $s .= "<td align='center'>";
464 $s .= "<input type='radio'";
465 if ($outtype == 0) {
466 $s .= " name='radio_{$field_id_esc}[$option_id_esc]'" .
467 " id='radio_{$field_id_esc}[$option_id_esc]'";
469 $s .= " value='$i' $lbfonchange";
470 if (isset($avalue[$option_id][1]) && $avalue[$option_id][1] == "$i") {
471 $s .= " checked";
473 $s .= " $disabled />";
474 $s .= "</td>";
477 $s .= genLabResultsTextItem(
478 "form_{$field_id_esc}[$option_id_esc][2]",
479 (isset($avalue[$option_id][2]) ? $avalue[$option_id][2] : ''),
480 $outtype,
483 $disabled,
484 $under
486 $s .= genLabResultsTextItem(
487 "form_{$field_id_esc}[$option_id_esc][3]",
488 (isset($avalue[$option_id][3]) ? $avalue[$option_id][3] : ''),
489 $outtype,
490 $fldlength,
491 $maxlength,
492 $disabled,
493 $under
495 $s .= "</tr>";
497 if ($outtype != 3) {
498 $s .= "</table>";
501 return $s;
504 // $frow is a row from the layout_options table.
505 // $currvalue is the current value, if any, of the associated item.
507 function generate_form_field($frow, $currvalue)
509 global $rootdir, $date_init, $ISSUE_TYPES, $code_types, $membership_group_number;
511 $currescaped = htmlspecialchars($currvalue ?? '', ENT_QUOTES);
513 $data_type = $frow['data_type'];
514 $field_id = $frow['field_id'];
515 $list_id = $frow['list_id'] ?? null;
516 $backup_list = $frow['list_backup_id'] ?? null;
517 $edit_options = $frow['edit_options'] ?? null;
518 $form_id = $frow['form_id'] ?? null;
520 // 'smallform' can be 'true' if we want a smaller form field, otherwise
521 // can be used to assign arbitrary CSS classes to data entry fields.
522 $smallform = $frow['smallform'] ?? null;
523 if ($smallform === 'true') {
524 $smallform = ' form-control-sm';
527 // escaped variables to use in html
528 $field_id_esc = htmlspecialchars($field_id, ENT_QUOTES);
529 $list_id_esc = htmlspecialchars(($list_id ?? ''), ENT_QUOTES);
531 // Added 5-09 by BM - Translate description if applicable
532 $description = (isset($frow['description']) ? htmlspecialchars(xl_layout_label($frow['description']), ENT_QUOTES) : '');
534 // Support edit option T which assigns the (possibly very long) description as
535 // the default value.
536 if (isOption($edit_options, 'T') !== false) {
537 if (strlen($currescaped) == 0) {
538 $currescaped = $description;
541 // Description used in this way is not suitable as a title.
542 $description = '';
545 // Support using the description as a placeholder
546 $placeholder = (isOption($edit_options, 'DAP') === true) ? " placeholder='{$description}' " : '';
548 // added 5-2009 by BM to allow modification of the 'empty' text title field.
549 // Can pass $frow['empty_title'] with this variable, otherwise
550 // will default to 'Unassigned'.
551 // modified 6-2009 by BM to allow complete skipping of the 'empty' text title
552 // if make $frow['empty_title'] equal to 'SKIP'
553 $showEmpty = true;
554 if (isset($frow['empty_title'])) {
555 if ($frow['empty_title'] == "SKIP") {
556 //do not display an 'empty' choice
557 $showEmpty = false;
558 $empty_title = "Unassigned";
559 } else {
560 $empty_title = $frow['empty_title'];
562 } else {
563 $empty_title = "Unassigned";
566 $disabled = isOption($edit_options, '0') === false ? '' : 'disabled';
568 $lbfchange = (
569 !empty($form_id) &&
571 strpos($form_id, 'LBF') === 0 ||
572 strpos($form_id, 'LBT') === 0 ||
573 strpos($form_id, 'DEM') === 0 ||
574 strpos($form_id, 'HIS') === 0
576 ) ? "checkSkipConditions();" : "";
577 $lbfonchange = $lbfchange ? "onchange='$lbfchange'" : "";
579 // generic single-selection list or single-selection list with search or single-selection list with comment support.
580 // These data types support backup lists.
581 if ($data_type == 1 || $data_type == 43 || $data_type == 46) {
582 if ($data_type == 46) {
583 // support for single-selection list with comment support
584 $lbfchange = "processCommentField(" . attr_js($field_id) . ");" . $lbfchange;
587 echo generate_select_list(
588 "form_$field_id",
589 $list_id,
590 $currvalue,
591 $description,
592 ($showEmpty ? $empty_title : ''),
593 (($data_type == 43) ? "select-dropdown" : $smallform),
594 $lbfchange,
596 ($disabled ? array('disabled' => 'disabled') : null),
597 false,
598 $backup_list
601 if ($data_type == 46) {
602 // support for single-selection list with comment support
603 $selectedValues = explode("|", $currvalue);
604 if (!preg_match('/^comment_/', $currvalue) || (count($selectedValues) == 1)) {
605 $display = "display:none";
606 $comment = "";
607 } else {
608 $display = "display:inline-block";
609 $comment = $selectedValues[count($selectedValues) - 1];
611 echo "<input type='text'" .
612 " name='form_text_" . attr($field_id) . "'" .
613 " id='form_text_" . attr($field_id) . "'" .
614 " size='" . attr($frow['fld_length']) . "'" .
615 " class='form-control'" .
616 $placeholder .
617 " " . ((!empty($frow['max_length'])) ? "maxlength='" . attr($frow['max_length']) . "'" : "") . " " .
618 " style='" . $display . "'" .
619 " value='" . attr($comment) . "'/>";
621 } elseif ($data_type == 2) { // simple text field
622 $fldlength = htmlspecialchars($frow['fld_length'], ENT_QUOTES);
623 $maxlength = $frow['max_length'];
624 $string_maxlength = "";
625 // if max_length is set to zero, then do not set a maxlength
626 if ($maxlength) {
627 $string_maxlength = "maxlength='" . attr($maxlength) . "'";
630 echo "<input type='text'
631 class='form-control{$smallform}'
632 name='form_{$field_id_esc}'
633 id='form_{$field_id_esc}'
634 size='{$fldlength}'
635 {$string_maxlength}
636 {$placeholder}
637 title='{$description}'
638 value='{$currescaped}'";
639 $tmp = $lbfchange;
640 if (isOption($edit_options, 'C') !== false) {
641 $tmp .= "capitalizeMe(this);";
642 } elseif (isOption($edit_options, 'U') !== false) {
643 $tmp .= "this.value = this.value.toUpperCase();";
646 if ($tmp) {
647 echo " onchange='$tmp'";
650 $tmp = htmlspecialchars($GLOBALS['gbl_mask_patient_id'], ENT_QUOTES);
651 // If mask is for use at save time, treat as no mask.
652 if (strpos($tmp, '^') !== false) {
653 $tmp = '';
655 if ($field_id == 'pubpid' && strlen($tmp) > 0) {
656 echo " onkeyup='maskkeyup(this,\"$tmp\")'";
657 echo " onblur='maskblur(this,\"$tmp\")'";
660 if (isOption($edit_options, '1') !== false && strlen($currescaped) > 0) {
661 echo " readonly";
664 if ($disabled) {
665 echo ' disabled';
668 echo " />";
669 } elseif ($data_type == 3) { // long or multi-line text field
670 $textCols = htmlspecialchars($frow['fld_length'], ENT_QUOTES);
671 $textRows = htmlspecialchars($frow['fld_rows'], ENT_QUOTES);
672 echo "<textarea" .
673 " name='form_$field_id_esc'" .
674 " class='form-control$smallform'" .
675 " id='form_$field_id_esc'" .
676 " title='$description'" .
677 $placeholder .
678 " cols='$textCols'" .
679 " rows='$textRows' $lbfonchange $disabled" .
680 ">" . $currescaped . "</textarea>";
681 } elseif ($data_type == 4) { // date
682 $age_asof_date = ''; // optionalAge() sets this
683 $age_format = isOption($edit_options, 'A') === false ? 3 : 0;
684 $agestr = optionalAge($frow, $currvalue, $age_asof_date, $description);
685 if ($agestr) {
686 echo "<table class='table'><tr><td class='text'>";
689 $onchange_string = '';
690 if (!$disabled && $agestr) {
691 $onchange_string = "onchange=\"if (typeof(updateAgeString) == 'function') " .
692 "updateAgeString('$field_id','$age_asof_date', $age_format, '$description')\"";
694 if ($data_type == 4) {
695 $modtmp = isOption($edit_options, 'F') === false ? 0 : 1;
696 $datetimepickerclass = $frow['validation'] === 'past_date' ? '-past' : ( $frow['validation'] === 'future_date' ? '-future' : '' );
697 if (!$modtmp) {
698 $dateValue = oeFormatShortDate(substr($currescaped, 0, 10));
699 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) . "'";
700 } else {
701 $dateValue = oeFormatDateTime(substr($currescaped, 0, 20), 0);
702 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) . "'";
705 if (!$agestr) {
706 echo " title='$description'";
709 // help chrome users avoid autocomplete interfere with datepicker widget display
710 if ($frow['field_id'] == 'DOB') {
711 echo " autocomplete='off' $onchange_string $lbfonchange $disabled />";
712 } else {
713 echo " $onchange_string $lbfonchange $disabled />";
716 // Optional display of age or gestational age.
717 if ($agestr) {
718 echo "</td></tr><tr><td id='span_$field_id' class='text'>" . text($agestr) . "</td></tr></table>";
720 } elseif ($data_type == 10) { // provider list, local providers only
721 $ures = sqlStatement("SELECT id, fname, lname, specialty FROM users " .
722 "WHERE active = 1 AND ( info IS NULL OR info NOT LIKE '%Inactive%' ) " .
723 "AND authorized = 1 " .
724 "ORDER BY lname, fname");
725 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' title='$description' $lbfonchange $disabled class='form-control$smallform'>";
726 echo "<option value=''>" . xlt($empty_title) . "</option>";
727 $got_selected = false;
728 while ($urow = sqlFetchArray($ures)) {
729 $uname = text($urow['fname'] . ' ' . $urow['lname']);
730 $optionId = attr($urow['id']);
731 echo "<option value='$optionId'";
732 if ($urow['id'] == $currvalue) {
733 echo " selected";
734 $got_selected = true;
737 echo ">$uname</option>";
740 if (!$got_selected && $currvalue) {
741 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
742 echo "</select>";
743 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
744 } else {
745 echo "</select>";
747 } elseif ($data_type == 11) { // provider list, including address book entries with an NPI number
748 $ures = sqlStatement("SELECT id, fname, lname, specialty FROM users " .
749 "WHERE active = 1 AND ( info IS NULL OR info NOT LIKE '%Inactive%' ) " .
750 "AND ( authorized = 1 OR ( username = '' AND npi != '' ) ) " .
751 "ORDER BY lname, fname");
752 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' title='$description' class='form-control$smallform'";
753 echo " $lbfonchange $disabled>";
754 echo "<option value=''>" . xlt('Unassigned') . "</option>";
755 $got_selected = false;
756 while ($urow = sqlFetchArray($ures)) {
757 $uname = text($urow['fname'] . ' ' . $urow['lname']);
758 $optionId = attr($urow['id']);
759 echo "<option value='$optionId'";
760 if ($urow['id'] == $currvalue) {
761 echo " selected";
762 $got_selected = true;
765 echo ">$uname</option>";
768 if (!$got_selected && $currvalue) {
769 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
770 echo "</select>";
771 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
772 } else {
773 echo "</select>";
775 } elseif ($data_type == 12) { // pharmacy list
776 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' title='$description' class='form-control$smallform'";
777 echo " $lbfonchange $disabled>";
778 echo "<option value='0'></option>";
779 $pres = get_pharmacies();
780 $got_selected = false;
781 $zone = '';
782 while ($prow = sqlFetchArray($pres)) {
783 if ($zone != strtolower(trim($prow['city']))) {
784 if ($zone != '') {
785 echo "</optgroup>";
787 $zone = strtolower(trim($prow['city']));
788 echo "<optgroup label='" . attr($prow['city']) . "'>";
790 $key = $prow['id'];
791 $optionValue = htmlspecialchars($key, ENT_QUOTES);
792 $optionLabel = htmlspecialchars($prow['name'] . ' ' . $prow['area_code'] . '-' .
793 $prow['prefix'] . '-' . $prow['number'] . ' / ' .
794 $prow['line1'] . ' / ' . $prow['city'], ENT_NOQUOTES);
795 echo "<option value='$optionValue'";
796 if ($currvalue == $key) {
797 echo " selected";
798 $got_selected = true;
801 echo ">$optionLabel</option>";
804 if (!$got_selected && $currvalue) {
805 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
806 echo "</select>";
807 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
808 } else {
809 echo "</select>";
811 } elseif ($data_type == 13) { // squads
812 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' title='$description' class='form-control$smallform'";
813 echo " $lbfonchange $disabled>";
814 echo "<option value=''>&nbsp;</option>";
815 $squads = AclExtended::aclGetSquads();
816 if ($squads) {
817 foreach ($squads as $key => $value) {
818 $optionValue = htmlspecialchars($key, ENT_QUOTES);
819 $optionLabel = htmlspecialchars($value[3], ENT_NOQUOTES);
820 echo "<option value='$optionValue'";
821 if ($currvalue == $key) {
822 echo " selected";
825 echo ">$optionLabel</option>\n";
829 echo "</select>";
830 } elseif ($data_type == 14) {
831 // Address book, preferring organization name if it exists and is not in
832 // parentheses, and excluding local users who are not providers.
833 // Supports "referred to" practitioners and facilities.
834 // Alternatively the letter L in edit_options means that abook_type
835 // must be "ord_lab", indicating types used with the procedure
836 // lab ordering system.
837 // Alternatively the letter O in edit_options means that abook_type
838 // must begin with "ord_", indicating types used with the procedure
839 // ordering system.
840 // Alternatively the letter V in edit_options means that abook_type
841 // must be "vendor", indicating the Vendor type.
842 // Alternatively the letter R in edit_options means that abook_type
843 // must be "dist", indicating the Distributor type.
845 if (isOption($edit_options, 'L') !== false) {
846 $tmp = "abook_type = 'ord_lab'";
847 } elseif (isOption($edit_options, 'O') !== false) {
848 $tmp = "abook_type LIKE 'ord\\_%'";
849 } elseif (isOption($edit_options, 'V') !== false) {
850 $tmp = "abook_type LIKE 'vendor%'";
851 } elseif (isOption($edit_options, 'R') !== false) {
852 $tmp = "abook_type LIKE 'dist'";
853 } else {
854 $tmp = "( username = '' OR authorized = 1 )";
857 $ures = sqlStatement("SELECT id, fname, lname, organization, username, npi FROM users " .
858 "WHERE active = 1 AND ( info IS NULL OR info NOT LIKE '%Inactive%' ) " .
859 "AND $tmp " .
860 "ORDER BY organization, lname, fname, npi");
861 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' title='$description' class='form-control$smallform'";
862 echo " $lbfonchange $disabled>";
863 echo "<option value=''>" . htmlspecialchars(xl('Unassigned'), ENT_NOQUOTES) . "</option>";
864 while ($urow = sqlFetchArray($ures)) {
865 $uname = $urow['organization'];
866 if (empty($uname) || substr($uname, 0, 1) == '(') {
867 $uname = $urow['lname'];
868 if ($urow['fname']) {
869 $uname .= ", " . $urow['fname'];
871 if ($urow['npi']) {
872 $uname .= ": " . $urow['npi'];
876 $optionValue = htmlspecialchars($urow['id'], ENT_QUOTES);
877 $optionLabel = htmlspecialchars($uname, ENT_NOQUOTES);
878 echo "<option value='$optionValue'";
879 // Failure to translate Local and External is not an error here;
880 // they are only used as internal flags and must not be translated!
881 $title = $urow['username'] ? 'Local' : 'External';
882 $optionTitle = htmlspecialchars($title, ENT_QUOTES);
883 echo " title='$optionTitle'";
884 if ($urow['id'] == $currvalue) {
885 echo " selected";
888 echo ">$optionLabel</option>";
891 echo "</select>";
892 } elseif ($data_type == 15) { // A billing code. If description matches an existing code type then that type is used.
893 $codetype = '';
894 if (!empty($frow['description']) && isset($code_types[$frow['description']])) {
895 $codetype = $frow['description'];
897 $fldlength = attr($frow['fld_length']);
898 $maxlength = $frow['max_length'];
899 $string_maxlength = "";
900 // if max_length is set to zero, then do not set a maxlength
901 if ($maxlength) {
902 $string_maxlength = "maxlength='" . attr($maxlength) . "'";
904 // Edit option E means allow multiple (Extra) billing codes in a field.
905 // We invent a class name for this because JavaScript needs to know.
906 $className = '';
907 if (strpos($frow['edit_options'], 'E') !== false) {
908 $className = 'EditOptionE';
911 if (isOption($edit_options, '2') !== false) {
912 // Option "2" generates a hidden input for the codes, and a matching visible field
913 // displaying their descriptions. First step is computing the description string.
914 $currdescstring = '';
915 if (!empty($currvalue)) {
916 $relcodes = explode(';', $currvalue);
917 foreach ($relcodes as $codestring) {
918 if ($codestring === '') {
919 continue;
921 if ($currdescstring !== '') {
922 $currdescstring .= '; ';
924 $currdescstring .= getCodeDescription($codestring, $codetype);
928 $currdescstring = attr($currdescstring);
930 echo "<div>"; // wrapper for myHideOrShow()
931 echo "<input type='text'" .
932 " name='form_$field_id_esc'" .
933 " id='form_related_code'" .
934 " class='" . attr($className) . "'" .
935 " size='$fldlength'" .
936 " value='$currescaped'" .
937 " style='display:none'" .
938 " $lbfonchange readonly $disabled />";
939 // Extra readonly input field for optional display of code description(s).
940 echo "<input type='text'" .
941 " name='form_$field_id_esc" . "__desc'" .
942 " size='$fldlength'" .
943 " title='$description'" .
944 " value='$currdescstring'";
945 if (!$disabled) {
946 echo " onclick='sel_related(this," . attr_js($codetype) . ")'";
949 echo "class='form-control$smallform'";
950 echo " readonly $disabled />";
951 echo "</div>";
952 } else {
953 echo "<input type='text'" .
954 " name='form_$field_id_esc'" .
955 " id='form_related_code'" .
956 " class='" . attr($className) . "'" .
957 " size='$fldlength'" .
958 " $string_maxlength" .
959 " title='$description'" .
960 " value='$currescaped'";
961 if (!$disabled) {
962 echo " onclick='sel_related(this," . attr_js($codetype) . ")'";
965 echo "class='form-control$smallform'";
966 echo " $lbfonchange readonly $disabled />";
968 } elseif ($data_type == 16) { // insurance company list
969 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' class='form-control$smallform' title='$description'>";
970 echo "<option value='0'></option>";
971 $insprovs = getInsuranceProviders();
972 $got_selected = false;
973 foreach ($insprovs as $key => $ipname) {
974 $optionValue = htmlspecialchars($key, ENT_QUOTES);
975 $optionLabel = htmlspecialchars($ipname, ENT_NOQUOTES);
976 echo "<option value='$optionValue'";
977 if ($currvalue == $key) {
978 echo " selected";
979 $got_selected = true;
982 echo ">$optionLabel</option>";
985 if (!$got_selected && $currvalue) {
986 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
987 echo "</select>";
988 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
989 } else {
990 echo "</select>";
992 } elseif ($data_type == 17) { // issue types
993 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' class='form-control$smallform' title='$description'>";
994 echo "<option value='0'></option>";
995 $got_selected = false;
996 foreach ($ISSUE_TYPES as $key => $value) {
997 $optionValue = htmlspecialchars($key, ENT_QUOTES);
998 $optionLabel = htmlspecialchars($value[1], ENT_NOQUOTES);
999 echo "<option value='$optionValue'";
1000 if ($currvalue == $key) {
1001 echo " selected";
1002 $got_selected = true;
1005 echo ">$optionLabel</option>";
1008 if (!$got_selected && strlen($currvalue) > 0) {
1009 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
1010 echo "</select>";
1011 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
1012 } else {
1013 echo "</select>";
1015 } elseif ($data_type == 18) { // Visit categories.
1016 $cres = sqlStatement("SELECT pc_catid, pc_catname " .
1017 "FROM openemr_postcalendar_categories ORDER BY pc_catname");
1018 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' class='form-control$smallform' title='$description'" . " $lbfonchange $disabled>";
1019 echo "<option value=''>" . xlt($empty_title) . "</option>";
1020 $got_selected = false;
1021 while ($crow = sqlFetchArray($cres)) {
1022 $catid = $crow['pc_catid'];
1023 if (($catid < 9 && $catid != 5) || $catid == 11) {
1024 continue;
1027 echo "<option value='" . attr($catid) . "'";
1028 if ($catid == $currvalue) {
1029 echo " selected";
1030 $got_selected = true;
1033 echo ">" . text(xl_appt_category($crow['pc_catname'])) . "</option>";
1036 if (!$got_selected && $currvalue) {
1037 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
1038 echo "</select>";
1039 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
1040 } else {
1041 echo "</select>";
1043 } elseif ($data_type == 21) { // a set of labeled checkboxes
1044 // If no list then it's a single checkbox and its value is "Yes" or empty.
1045 if (!$list_id) {
1046 echo "<input type='checkbox' name='form_{$field_id_esc}' " .
1047 "id='form_{$field_id_esc}' value='Yes' $lbfonchange";
1048 if ($currvalue) {
1049 echo " checked";
1051 echo " $disabled />";
1052 } else {
1053 // In this special case, fld_length is the number of columns generated.
1054 $cols = max(1, $frow['fld_length']);
1055 $avalue = explode('|', $currvalue);
1056 $lres = sqlStatement("SELECT * FROM list_options " .
1057 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
1058 echo "<table class='w-100' cellpadding='0' cellspacing='0' title='" . attr($description) . "'>";
1059 $tdpct = (int) (100 / $cols);
1060 for ($count = 0; $lrow = sqlFetchArray($lres); ++$count) {
1061 $option_id = $lrow['option_id'];
1062 $option_id_esc = htmlspecialchars($option_id, ENT_QUOTES);
1063 // if ($count) echo "<br />";
1064 if ($count % $cols == 0) {
1065 if ($count) {
1066 echo "</tr>";
1068 echo "<tr>";
1070 echo "<td width='" . attr($tdpct) . "%' nowrap>";
1071 echo "<input type='checkbox' name='form_{$field_id_esc}[$option_id_esc]'" .
1072 "id='form_{$field_id_esc}[$option_id_esc]' class='form-check-inline' value='1' $lbfonchange";
1073 if (in_array($option_id, $avalue)) {
1074 echo " checked";
1076 // Added 5-09 by BM - Translate label if applicable
1077 echo " $disabled />" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES);
1078 echo "</td>";
1080 if ($count) {
1081 echo "</tr>";
1082 if ($count > $cols) {
1083 // Add some space after multiple rows of checkboxes.
1084 $cols = htmlspecialchars($cols, ENT_QUOTES);
1085 echo "<tr><td colspan='$cols' style='height:0.7rem'></td></tr>";
1088 echo "</table>";
1090 } elseif ($data_type == 22) { // a set of labeled text input fields
1091 $tmp = explode('|', $currvalue);
1092 $avalue = array();
1093 foreach ($tmp as $value) {
1094 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
1095 $avalue[$matches[1]] = $matches[2];
1099 $lres = sqlStatement("SELECT * FROM list_options " .
1100 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
1101 echo "<table class='table'>";
1102 while ($lrow = sqlFetchArray($lres)) {
1103 $option_id = $lrow['option_id'];
1104 $option_id_esc = htmlspecialchars($option_id, ENT_QUOTES);
1105 $maxlength = $frow['max_length'];
1106 $string_maxlength = "";
1107 // if max_length is set to zero, then do not set a maxlength
1108 if ($maxlength) {
1109 $string_maxlength = "maxlength='" . attr($maxlength) . "'";
1112 $fldlength = empty($frow['fld_length']) ? 20 : $frow['fld_length'];
1114 // Added 5-09 by BM - Translate label if applicable
1115 echo "<tr><td>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES) . "&nbsp;</td>";
1116 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES);
1117 $optionValue = htmlspecialchars($avalue[$option_id], ENT_QUOTES);
1118 echo "<td><input type='text'" .
1119 " name='form_{$field_id_esc}[$option_id_esc]'" .
1120 " id='form_{$field_id_esc}[$option_id_esc]'" .
1121 " size='$fldlength'" .
1122 $placeholder .
1123 " class='form-control$smallform'" .
1124 " $string_maxlength" .
1125 " value='$optionValue'";
1126 echo " $lbfonchange $disabled /></td></tr>";
1129 echo "</table>";
1130 } elseif ($data_type == 23) { // a set of exam results; 3 radio buttons and a text field:
1131 $tmp = explode('|', $currvalue);
1132 $avalue = array();
1133 foreach ($tmp as $value) {
1134 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
1135 $avalue[$matches[1]] = $matches[2];
1139 $maxlength = $frow['max_length'];
1140 $string_maxlength = "";
1141 // if max_length is set to zero, then do not set a maxlength
1142 if ($maxlength) {
1143 $string_maxlength = "maxlength='" . attr($maxlength) . "'";
1146 $fldlength = empty($frow['fld_length']) ? 20 : $frow['fld_length'];
1147 $lres = sqlStatement("SELECT * FROM list_options " .
1148 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
1149 echo "<table class='table'>";
1150 echo "<tr><td class='font-weight-bold'>" . htmlspecialchars(xl('Exam or Test'), ENT_NOQUOTES) .
1151 "</td><td class='font-weight-bold'>" . htmlspecialchars(xl('N/A'), ENT_NOQUOTES) .
1152 "&nbsp;</td><td class='font-weight-bold'>" .
1153 htmlspecialchars(xl('Nor'), ENT_NOQUOTES) . "&nbsp;</td>" .
1154 "<td class='font-weight-bold'>" .
1155 htmlspecialchars(xl('Abn'), ENT_NOQUOTES) . "&nbsp;</td><td class='font-weight-bold'>" .
1156 htmlspecialchars(xl('Date/Notes'), ENT_NOQUOTES) . "</td></tr>";
1157 while ($lrow = sqlFetchArray($lres)) {
1158 $option_id = $lrow['option_id'];
1159 $option_id_esc = htmlspecialchars($option_id, ENT_QUOTES);
1160 $restype = substr(($avalue[$option_id] ?? ''), 0, 1);
1161 $resnote = substr(($avalue[$option_id] ?? ''), 2);
1163 // Added 5-09 by BM - Translate label if applicable
1164 echo "<tr><td>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES) . "&nbsp;</td>";
1166 for ($i = 0; $i < 3; ++$i) {
1167 $inputValue = htmlspecialchars($i, ENT_QUOTES);
1168 echo "<td><input type='radio'" .
1169 " name='radio_{$field_id_esc}[$option_id_esc]'" .
1170 " id='radio_{$field_id_esc}[$option_id_esc]'" .
1171 " value='$inputValue' $lbfonchange";
1172 if ($restype === "$i") {
1173 echo " checked";
1176 echo " $disabled /></td>";
1179 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES);
1180 $resnote = htmlspecialchars($resnote, ENT_QUOTES);
1181 echo "<td><input type='text'" .
1182 " name='form_{$field_id_esc}[$option_id_esc]'" .
1183 " id='form_{$field_id_esc}[$option_id_esc]'" .
1184 " size='$fldlength'" .
1185 " class='form-control'" .
1186 " $string_maxlength" .
1187 " value='$resnote' $disabled /></td>";
1188 echo "</tr>";
1191 echo "</table>";
1192 } elseif ($data_type == 24) { // the list of active allergies for the current patient
1193 // this is read-only!
1194 $query = "SELECT title, comments FROM lists WHERE " .
1195 "pid = ? AND type = 'allergy' AND enddate IS NULL " .
1196 "ORDER BY begdate";
1197 // echo "<!-- $query -->\n"; // debugging
1198 $lres = sqlStatement($query, array($GLOBALS['pid']));
1199 $count = 0;
1200 while ($lrow = sqlFetchArray($lres)) {
1201 if ($count++) {
1202 echo "<br />";
1205 echo htmlspecialchars($lrow['title'], ENT_NOQUOTES);
1206 if ($lrow['comments']) {
1207 echo ' (' . htmlspecialchars($lrow['comments'], ENT_NOQUOTES) . ')';
1210 } elseif ($data_type == 25) { // a set of labeled checkboxes, each with a text field:
1211 $tmp = explode('|', $currvalue);
1212 $avalue = array();
1213 foreach ($tmp as $value) {
1214 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
1215 $avalue[$matches[1]] = $matches[2];
1219 $maxlength = $frow['max_length'];
1220 $string_maxlength = "";
1221 // if max_length is set to zero, then do not set a maxlength
1222 if ($maxlength) {
1223 $string_maxlength = "maxlength='" . attr($maxlength) . "'";
1226 $fldlength = empty($frow['fld_length']) ? 20 : $frow['fld_length'];
1227 $lres = sqlStatement("SELECT * FROM list_options " .
1228 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
1229 echo "<table class='table'>";
1230 while ($lrow = sqlFetchArray($lres)) {
1231 $option_id = $lrow['option_id'];
1232 $option_id_esc = htmlspecialchars($option_id, ENT_QUOTES);
1233 $restype = substr($avalue[$option_id], 0, 1);
1234 $resnote = substr($avalue[$option_id], 2);
1236 // Added 5-09 by BM - Translate label if applicable
1237 echo "<tr><td>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES) . "&nbsp;</td>";
1239 $option_id = htmlspecialchars($option_id, ENT_QUOTES);
1240 echo "<td><input type='checkbox' name='check_{$field_id_esc}[$option_id_esc]'" .
1241 " id='check_{$field_id_esc}[$option_id_esc]' class='form-check-inline' value='1' $lbfonchange";
1242 if ($restype) {
1243 echo " checked";
1246 echo " $disabled />&nbsp;</td>";
1247 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES);
1248 $resnote = htmlspecialchars($resnote, ENT_QUOTES);
1249 echo "<td><input type='text'" .
1250 " name='form_{$field_id_esc}[$option_id_esc]'" .
1251 " id='form_{$field_id_esc}[$option_id_esc]'" .
1252 " size='$fldlength'" .
1253 " class='form-control$smallform' " .
1254 " $string_maxlength" .
1255 " value='$resnote' $disabled /></td>";
1256 echo "</tr>";
1259 echo "</table>";
1260 } elseif ($data_type == 26) { // single-selection list with ability to add to it
1261 echo "<div class='input-group'>";
1262 echo generate_select_list(
1263 "form_$field_id",
1264 $list_id,
1265 $currvalue,
1266 $description,
1267 ($showEmpty ? $empty_title : ''),
1268 'addtolistclass_' . $list_id . $smallform,
1269 $lbfchange,
1271 ($disabled ? array('disabled' => 'disabled') : null),
1272 false,
1273 $backup_list
1275 // show the add button if user has access to correct list
1276 $inputValue = htmlspecialchars(xl('Add'), ENT_QUOTES);
1277 $btnSize = ($smallform) ? "btn-sm" : "";
1278 $outputAddButton = "<div class='input-group-append'><input type='button' class='btn btn-secondary $btnSize addtolist' id='addtolistid_" . $list_id_esc . "' fieldid='form_" .
1279 $field_id_esc . "' value='$inputValue' $disabled /></div>";
1280 if (AclExtended::acoExist('lists', $list_id)) {
1281 // a specific aco exist for this list, so ensure access
1282 if (AclMain::aclCheckCore('lists', $list_id)) {
1283 echo $outputAddButton;
1285 } else {
1286 // no specific aco exist for this list, so check for access to 'default' list
1287 if (AclMain::aclCheckCore('lists', 'default')) {
1288 echo $outputAddButton;
1291 echo "</div>";
1292 } elseif ($data_type == 27) { // a set of labeled radio buttons
1293 // In this special case, fld_length is the number of columns generated.
1294 $cols = max(1, $frow['fld_length']);
1295 // Support for edit option M.
1296 if (isOption($edit_options, 'M')) {
1297 ++$membership_group_number;
1300 $lres = sqlStatement("SELECT * FROM list_options " .
1301 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
1302 echo "<table class='table w-100'>";
1303 $tdpct = (int) (100 / $cols);
1304 $got_selected = false;
1305 for ($count = 0; $lrow = sqlFetchArray($lres); ++$count) {
1306 $option_id = $lrow['option_id'];
1307 $option_id_esc = htmlspecialchars($option_id, ENT_QUOTES);
1308 if ($count % $cols == 0) {
1309 if ($count) {
1310 echo "</tr>";
1312 echo "<tr>";
1314 echo "<td width='" . attr($tdpct) . "%' nowrap>";
1315 echo "<input type='radio' name='form_{$field_id_esc}' id='form_{$field_id_esc}[$option_id_esc]'" .
1316 " value='$option_id_esc' $lbfonchange";
1317 // Support for edit options M and m.
1318 if (isOption($edit_options, 'M')) {
1319 echo " class='form-check-inline'";
1320 echo " onclick='checkGroupMembers(this, $membership_group_number);'";
1321 } elseif (isOption($edit_options, 'm')) {
1322 echo " class='form-check-inline lbf_memgroup_$membership_group_number'";
1323 } else {
1324 echo " class='form-check-inline'";
1327 if (
1328 (strlen($currvalue) == 0 && $lrow['is_default']) ||
1329 (strlen($currvalue) > 0 && $option_id == $currvalue)
1331 echo " checked";
1332 $got_selected = true;
1334 echo " $disabled />" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES);
1335 echo "</td>";
1338 if ($count) {
1339 echo "</tr>";
1340 if ($count > $cols) {
1341 // Add some space after multiple rows of radio buttons.
1342 $cols = htmlspecialchars($cols, ENT_QUOTES);
1343 echo "<tr><td colspan='$cols' style='height: 0.7rem'></td></tr>";
1347 echo "</table>";
1348 if (!$got_selected && strlen($currvalue) > 0) {
1349 $fontTitle = htmlspecialchars(xl('Please choose a valid selection.'), ENT_QUOTES);
1350 $fontText = htmlspecialchars(xl('Fix this'), ENT_NOQUOTES);
1351 echo "$currescaped <span class='text-danger' title='$fontTitle'>$fontText!</span>";
1353 } elseif ($data_type == 28 || $data_type == 32) { // special case for history of lifestyle status; 3 radio buttons
1354 // and a date text field:
1355 // VicarePlus :: A selection list box for smoking status:
1356 $tmp = explode('|', $currvalue);
1357 switch (count($tmp)) {
1358 case "4":
1359 $resnote = $tmp[0];
1360 $restype = $tmp[1];
1361 $resdate = oeFormatShortDate($tmp[2]);
1362 $reslist = $tmp[3];
1363 break;
1364 case "3":
1365 $resnote = $tmp[0];
1366 $restype = $tmp[1];
1367 $resdate = oeFormatShortDate($tmp[2]);
1368 $reslist = '';
1369 break;
1370 case "2":
1371 $resnote = $tmp[0];
1372 $restype = $tmp[1];
1373 $resdate = "";
1374 $reslist = '';
1375 break;
1376 case "1":
1377 $resnote = $tmp[0];
1378 $resdate = $restype = "";
1379 $reslist = '';
1380 break;
1381 default:
1382 $restype = $resdate = $resnote = "";
1383 $reslist = '';
1384 break;
1387 $maxlength = $frow['max_length'];
1388 $string_maxlength = "";
1389 // if max_length is set to zero, then do not set a maxlength
1390 if ($maxlength) {
1391 $string_maxlength = "maxlength='" . attr($maxlength) . "'";
1394 $fldlength = empty($frow['fld_length']) ? 20 : $frow['fld_length'];
1396 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES);
1397 $resnote = htmlspecialchars($resnote, ENT_QUOTES);
1398 $resdate = htmlspecialchars($resdate, ENT_QUOTES);
1399 echo "<table class='table'>";
1400 echo "<tr>";
1401 if ($data_type == 28) {
1402 // input text
1403 echo "<td><input type='text' class='form-control'" .
1404 " name='form_$field_id_esc'" .
1405 " id='form_$field_id_esc'" .
1406 " size='$fldlength'" .
1407 " class='form-control$smallform'" .
1408 " $string_maxlength" .
1409 " value='$resnote' $disabled />&nbsp;</td>";
1410 echo "<td class='font-weight-bold'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" .
1411 "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" .
1412 htmlspecialchars(xl('Status'), ENT_NOQUOTES) . ":&nbsp;&nbsp;</td>";
1413 } elseif ($data_type == 32) {
1414 // input text
1415 echo "<tr><td><input type='text'" .
1416 " name='form_text_$field_id_esc'" .
1417 " id='form_text_$field_id_esc'" .
1418 " size='$fldlength'" .
1419 " class='form-control$smallform'" .
1420 " $string_maxlength" .
1421 " value='$resnote' $disabled />&nbsp;</td></tr>";
1422 echo "<td>";
1423 //Selection list for smoking status
1424 $onchange = 'radioChange(this.options[this.selectedIndex].value)';//VicarePlus :: The javascript function for selection list.
1425 echo generate_select_list(
1426 "form_$field_id",
1427 $list_id,
1428 $reslist,
1429 $description,
1430 ($showEmpty ? $empty_title : ''),
1431 $smallform,
1432 $onchange,
1434 ($disabled ? array('disabled' => 'disabled') : null)
1436 echo "</td>";
1437 echo "<td class='font-weight-bold'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" . xlt('Status') . ":&nbsp;&nbsp;</td>";
1440 // current
1441 echo "<td class='text'><input type='radio'" .
1442 " name='radio_{$field_id_esc}'" .
1443 " id='radio_{$field_id_esc}[current]'" .
1444 " class='form-check-inline'" .
1445 " value='current" . $field_id_esc . "' $lbfonchange";
1446 if ($restype == "current" . $field_id) {
1447 echo " checked";
1450 if ($data_type == 32) {
1451 echo " onClick='smoking_statusClicked(this)'";
1454 echo " />" . xlt('Current') . "&nbsp;</td>";
1455 // quit
1456 echo "<td class='text'><input type='radio'" .
1457 " name='radio_{$field_id_esc}'" .
1458 " id='radio_{$field_id_esc}[quit]'" .
1459 " class='form-check-inline'" .
1460 " value='quit" . $field_id_esc . "' $lbfonchange";
1461 if ($restype == "quit" . $field_id) {
1462 echo " checked";
1465 if ($data_type == 32) {
1466 echo " onClick='smoking_statusClicked(this)'";
1469 echo " $disabled />" . xlt('Quit') . "&nbsp;</td>";
1470 // quit date
1471 echo "<td class='text'><input type='text' size='6' class='form-control datepicker' name='date_$field_id_esc' id='date_$field_id_esc'" .
1472 " value='$resdate'" .
1473 " title='$description'" .
1474 " $disabled />";
1475 echo "&nbsp;</td>";
1476 // never
1477 echo "<td class='text'><input type='radio'" .
1478 " name='radio_{$field_id_esc}'" .
1479 " class='form-check-inline'" .
1480 " id='radio_{$field_id_esc}[never]'" .
1481 " value='never" . $field_id_esc . "' $lbfonchange";
1482 if ($restype == "never" . $field_id) {
1483 echo " checked";
1486 if ($data_type == 32) {
1487 echo " onClick='smoking_statusClicked(this)'";
1490 echo " />" . xlt('Never') . "&nbsp;</td>";
1491 // Not Applicable
1492 echo "<td class='text'><input type='radio'" .
1493 " class='form-check-inline' " .
1494 " name='radio_{$field_id}'" .
1495 " id='radio_{$field_id}[not_applicable]'" .
1496 " value='not_applicable" . $field_id . "' $lbfonchange";
1497 if ($restype == "not_applicable" . $field_id) {
1498 echo " checked";
1501 if ($data_type == 32) {
1502 echo " onClick='smoking_statusClicked(this)'";
1505 echo " $disabled />" . xlt('N/A') . "&nbsp;</td>";
1507 //Added on 5-jun-2k14 (regarding 'Smoking Status - display SNOMED code description')
1508 echo "<td class='text'><div id='smoke_code'></div></td>";
1509 echo "</tr>";
1510 echo "</table>";
1511 } elseif ($data_type == 31) { // static text. read-only, of course.
1512 echo parse_static_text($frow);
1513 } elseif ($data_type == 34) {
1514 // $data_type == 33
1515 // Race and Ethnicity. After added support for backup lists, this is now the same as datatype 36; so have migrated it there.
1516 // $data_type == 33
1518 $arr = explode("|*|*|*|", $currvalue);
1519 echo "<div>"; // wrapper for myHideOrShow()
1520 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'>";
1521 echo "<div id='form_{$field_id}_div' class='text-area' style='min-width: 133px'>" . $arr[0] . "</div>";
1522 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>";
1523 echo "</a>";
1524 echo "</div>";
1525 } elseif ($data_type == 35) { //facilities drop-down list
1526 if (empty($currvalue)) {
1527 $currvalue = 0;
1530 dropdown_facility(
1531 $selected = $currvalue,
1532 $name = "form_$field_id_esc",
1533 $allow_unspecified = true,
1534 $allow_allfacilities = false,
1535 $disabled,
1536 $lbfchange,
1537 false,
1538 $smallform
1540 } elseif ($data_type == 36 || $data_type == 33) { //multiple select, supports backup list
1541 echo generate_select_list(
1542 "form_$field_id",
1543 $list_id,
1544 $currvalue,
1545 $description,
1546 $showEmpty ? $empty_title : '',
1547 $smallform,
1548 $lbfchange,
1550 null,
1551 true,
1552 $backup_list
1555 // A set of lab test results; Gestation, 3 radio buttons, test value, notes field:
1556 } elseif ($data_type == 37) {
1557 echo genLabResults($frow, $currvalue, 0, $disabled);
1558 } elseif ($data_type == 40) { // Canvas and related elements for browser-side image drawing.
1559 // Note you must invoke lbf_canvas_head() (below) to use this field type in a form.
1560 // Unlike other field types, width and height are in pixels.
1561 $canWidth = intval($frow['fld_length']);
1562 $canHeight = intval($frow['fld_rows']);
1563 if (empty($currvalue)) {
1564 if (preg_match('/\\bimage=([a-zA-Z0-9._-]*)/', $frow['description'], $matches)) {
1565 // If defined this is the filename of the default starting image.
1566 $currvalue = $GLOBALS['web_root'] . '/sites/' . $_SESSION['site_id'] . '/images/' . $matches[1];
1569 $mywidth = 50 + ($canWidth > 250 ? $canWidth : 250);
1570 $myheight = 31 + ($canHeight > 261 ? $canHeight : 261);
1571 echo "<div>"; // wrapper for myHideOrShow()
1572 echo "<div id='form_$field_id_esc' style='width:${mywidth}px; height:${myheight}px;'></div>";
1573 // Hidden form field exists to send updated data to the server at submit time.
1574 echo "<input type='hidden' name='form_$field_id_esc' value='' />";
1575 // Hidden image exists to support initialization of the canvas.
1576 echo "<img src='" . attr($currvalue) . "' id='form_{$field_id_esc}_img' style='display:none'>";
1577 echo "</div>";
1578 // $date_init is a misnomer but it's the place for browser-side setup logic.
1579 $date_init .= " lbfCanvasSetup('form_$field_id_esc', $canWidth, $canHeight);\n";
1580 } elseif ($data_type == 41 || $data_type == 42) {
1581 $datatype = 'patient-signature';
1582 $cpid = $GLOBALS['pid'];
1583 $cuser = $_SESSION['authUserID'];
1584 if ($data_type == 42) {
1585 $datatype = 'admin-signature';
1587 echo "<input type='hidden' id='form_$field_id_esc' name='form_$field_id_esc' value='' />\n";
1588 echo "<img class='signature' id='form_{$field_id_esc}_img' title='$description'
1589 data-pid='$cpid' data-user='$cuser' data-type='$datatype'
1590 data-action='fetch_signature' alt='Get Signature' src='" . attr($currvalue) . "'>\n";
1591 } elseif ($data_type == 44) { //multiple select facility
1592 if (empty($currvalue)) {
1593 $currvalue = 0;
1596 dropdown_facility(
1597 $selected = $currvalue,
1598 $name = "form_$field_id_esc",
1599 $allow_unspecified = false,
1600 $allow_allfacilities = false,
1601 $disabled,
1602 $lbfchange,
1603 true,
1604 $smallform
1606 } elseif ($data_type == 45) { // Multiple provider list, local providers only
1607 $ures = sqlStatement("SELECT id, fname, lname, specialty FROM users " .
1608 "WHERE active = 1 AND ( info IS NULL OR info NOT LIKE '%Inactive%' ) " .
1609 "AND authorized = 1 ORDER BY lname, fname");
1610 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'>";
1611 $got_selected = false;
1612 while ($urow = sqlFetchArray($ures)) {
1613 $uname = text($urow['fname'] . ' ' . $urow['lname']);
1614 $optionId = attr($urow['id']);
1615 echo "<option value='$optionId'";
1616 $selectedValues = explode("|", $currvalue);
1618 if (in_array($optionId, $selectedValues)) {
1619 echo " selected";
1620 $got_selected = true;
1623 echo ">$uname</option>";
1626 if (!$got_selected && $currvalue) {
1627 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
1628 echo "</select>";
1629 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
1630 } else {
1631 echo "</select>";
1634 // Patient selector field.
1635 } elseif ($data_type == 51) {
1636 $fldlength = attr($frow['fld_length']);
1637 $currdescstring = '';
1638 if (!empty($currvalue)) {
1639 $currdescstring .= getPatientDescription($currvalue);
1641 $currdescstring = htmlspecialchars($currdescstring, ENT_QUOTES);
1642 echo "<div>"; // wrapper for myHideOrShow()
1643 echo "<input type='text'" .
1644 " name='form_$field_id_esc'" .
1645 " size='$fldlength'" .
1646 " value='$currescaped'" .
1647 " style='display:none'" .
1648 " $lbfonchange readonly $disabled />";
1649 // Extra readonly input field for patient description (name and pid).
1650 echo "<input type='text'" .
1651 " name='form_$field_id_esc" . "__desc'" .
1652 " size='$fldlength'" .
1653 " title='$description'" .
1654 " value='$currdescstring'";
1655 if (!$disabled) {
1656 echo " onclick='sel_patient(this, this.form.form_$field_id_esc)'";
1658 echo " readonly $disabled />";
1659 echo "</div>";
1660 // Previous Patient Names with add. Somewhat mirrors data types 44,45.
1661 } elseif ($data_type == 52) {
1662 global $pid;
1663 $patientService = new PatientService();
1664 $res = $patientService->getPatientNameHistory($pid);
1665 echo "<div class='input-group w-75'>";
1666 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'>";
1667 foreach ($res as $row) {
1668 $pname = $row['formatted_name']; // esc'ed in fetch.
1669 $optionId = attr($row['id']);
1670 // all names always selected
1671 echo "<option value='$optionId'" . " selected>$pname</option>";
1673 echo "</select>";
1674 echo "<button type='button' class='btn btn-primary btn-sm' id='type_52_add' onclick='return specialtyFormDialog()'>" . xlt('Add') . "</button></div>";
1675 // Patient Encounter List Field
1676 } else if ($data_type == 53) {
1677 global $pid;
1678 $encounterService = new EncounterService();
1679 $res = $encounterService->getEncountersForPatientByPid($pid);
1680 echo "<div class='input-group w-75'>";
1681 echo "<select name='form_$field_id_esc'" . " id='form_$field_id_esc' title='$description' $lbfonchange $disabled class='form-control$smallform select-encounters'>";
1682 echo "<option value=''>" . xlt("Select Encounter") . "</option>";
1683 foreach ($res as $row) {
1684 $label = text(date("Y-m-d", strtotime($row['date'])) . " " . ($row['pc_catname'] ?? ''));
1685 $optionId = attr($row['eid']);
1686 // all names always selected
1687 if ($currvalue == $row['eid']) {
1688 echo "<option value='$optionId'" . " selected>$label</option>";
1689 } else {
1690 echo "<option value='$optionId'>$label</option>";
1693 echo "</select>";
1697 function generate_print_field($frow, $currvalue, $value_allowed = true)
1699 global $rootdir, $date_init, $ISSUE_TYPES;
1701 $currescaped = htmlspecialchars($currvalue, ENT_QUOTES);
1703 $data_type = $frow['data_type'];
1704 $field_id = $frow['field_id'] ?? null;
1705 $list_id = $frow['list_id'];
1706 $fld_length = $frow['fld_length'] ?? null;
1707 $backup_list = $frow['list_backup_id'] ?? null;
1709 $description = attr(xl_layout_label($frow['description'] ?? ''));
1711 // Can pass $frow['empty_title'] with this variable, otherwise
1712 // will default to 'Unassigned'.
1713 // If it is 'SKIP' then an empty text title is completely skipped.
1714 $showEmpty = true;
1715 if (isset($frow['empty_title'])) {
1716 if ($frow['empty_title'] == "SKIP") {
1717 //do not display an 'empty' choice
1718 $showEmpty = false;
1719 $empty_title = "Unassigned";
1720 } else {
1721 $empty_title = $frow['empty_title'];
1723 } else {
1724 $empty_title = "Unassigned";
1727 // generic single-selection list
1728 // Supports backup lists.
1729 // if (false && ($data_type == 1 || $data_type == 26 || $data_type == 33 || $data_type == 43 || $data_type == 46)) {
1730 // We used to show all the list options but this was undone per CV request 2017-12-07
1731 // (see alternative code below).
1732 if ($data_type == 1 || $data_type == 26 || $data_type == 33 || $data_type == 43 || $data_type == 46) {
1733 if (empty($fld_length)) {
1734 if ($list_id == 'titles') {
1735 $fld_length = 3;
1736 } else {
1737 $fld_length = 10;
1741 $tmp = '';
1742 if ($currvalue) {
1743 if ($data_type == 46) {
1744 // support for single-selection list with comment support
1745 $selectedValues = explode("|", $currvalue);
1746 $currvalue = $selectedValues[0];
1748 $lrow = sqlQuery(
1749 "SELECT title FROM list_options " .
1750 "WHERE list_id = ? AND option_id = ? AND activity = 1",
1751 array($list_id,$currvalue)
1753 // For lists Race and Ethnicity if there is no matching value in the corresponding lists check ethrace list
1754 if (empty($lrow) && $data_type == 33) {
1755 $lrow = sqlQuery(
1756 "SELECT title FROM list_options " .
1757 "WHERE list_id = ? AND option_id = ? AND activity = 1",
1758 array('ethrace', $currvalue)
1762 $tmp = xl_list_label($lrow['title']);
1763 if ($lrow == 0 && !empty($backup_list)) {
1764 // since primary list did not map, try to map to backup list
1765 $lrow = sqlQuery("SELECT title FROM list_options " .
1766 "WHERE list_id = ? AND option_id = ?", array($backup_list,$currvalue));
1767 $tmp = xl_list_label($lrow['title']);
1770 if (empty($tmp)) {
1771 $tmp = "($currvalue)";
1774 if ($data_type == 46) {
1775 // support for single-selection list with comment support
1776 $resnote = $selectedValues[1] ?? null;
1777 if (!empty($resnote)) {
1778 $tmp .= " (" . $resnote . ")";
1783 if ($tmp === '') {
1784 $tmp = '&nbsp;';
1785 } else {
1786 $tmp = htmlspecialchars($tmp, ENT_QUOTES);
1788 echo $tmp;
1789 } elseif ($data_type == 2 || $data_type == 15) { // simple text field
1790 if ($currescaped === '') {
1791 $currescaped = '&nbsp;';
1794 echo $currescaped;
1795 } elseif ($data_type == 3) { // long or multi-line text field
1796 $fldlength = htmlspecialchars($fld_length, ENT_QUOTES);
1797 $maxlength = htmlspecialchars($frow['fld_rows'], ENT_QUOTES);
1798 echo "<textarea" .
1799 " class='form-control' " .
1800 " cols='$fldlength'" .
1801 " rows='$maxlength'>" .
1802 $currescaped . "</textarea>";
1803 } elseif ($data_type == 4) { // date
1804 $age_asof_date = '';
1805 $agestr = optionalAge($frow, $currvalue, $age_asof_date, $description);
1806 if ($currvalue === '') {
1807 echo '&nbsp;';
1808 } else {
1809 $modtmp = isOption($frow['edit_options'], 'F') === false ? 0 : 1;
1810 if (!$modtmp) {
1811 echo text(oeFormatShortDate($currvalue));
1812 } else {
1813 echo text(oeFormatDateTime($currvalue));
1815 if ($agestr) {
1816 echo "&nbsp;(" . text($agestr) . ")";
1819 } elseif ($data_type == 10 || $data_type == 11) { // provider list
1820 $tmp = '';
1821 if ($currvalue) {
1822 $urow = sqlQuery("SELECT fname, lname, specialty FROM users " .
1823 "WHERE id = ?", array($currvalue));
1824 $tmp = ucwords($urow['fname'] . " " . $urow['lname']);
1825 if (empty($tmp)) {
1826 $tmp = "($currvalue)";
1829 if ($tmp === '') {
1830 $tmp = '&nbsp;';
1831 } else {
1832 $tmp = htmlspecialchars($tmp, ENT_QUOTES);
1835 echo $tmp;
1836 } elseif ($data_type == 12) { // pharmacy list
1837 $tmp = '';
1838 if ($currvalue) {
1839 $pres = get_pharmacies();
1840 while ($prow = sqlFetchArray($pres)) {
1841 $key = $prow['id'];
1842 if ($currvalue == $key) {
1843 $tmp = $prow['name'] . ' ' . $prow['area_code'] . '-' .
1844 $prow['prefix'] . '-' . $prow['number'] . ' / ' .
1845 $prow['line1'] . ' / ' . $prow['city'];
1849 if (empty($tmp)) {
1850 $tmp = "($currvalue)";
1853 if ($tmp === '') {
1854 $tmp = '&nbsp;';
1855 } else {
1856 $tmp = htmlspecialchars($tmp, ENT_QUOTES);
1859 echo $tmp;
1860 } elseif ($data_type == 13) { // squads
1861 $tmp = '';
1862 if ($currvalue) {
1863 $squads = AclExtended::aclGetSquads();
1864 if ($squads) {
1865 foreach ($squads as $key => $value) {
1866 if ($currvalue == $key) {
1867 $tmp = $value[3];
1872 if (empty($tmp)) {
1873 $tmp = "($currvalue)";
1876 if ($tmp === '') {
1877 $tmp = '&nbsp;';
1878 } else {
1879 $tmp = htmlspecialchars($tmp, ENT_QUOTES);
1882 echo $tmp;
1883 } elseif ($data_type == 14) { // Address book.
1884 $tmp = '';
1885 if ($currvalue) {
1886 $urow = sqlQuery("SELECT fname, lname, specialty FROM users " .
1887 "WHERE id = ?", array($currvalue));
1888 $uname = $urow['lname'];
1889 if ($urow['fname']) {
1890 $uname .= ", " . $urow['fname'];
1893 $tmp = $uname;
1894 if (empty($tmp)) {
1895 $tmp = "($currvalue)";
1898 if ($tmp === '') {
1899 $tmp = '&nbsp;';
1900 } else {
1901 $tmp = htmlspecialchars($tmp, ENT_QUOTES);
1904 echo $tmp;
1905 } elseif ($data_type == 16) { // insurance company list
1906 $tmp = '';
1907 if ($currvalue) {
1908 $insprovs = getInsuranceProviders();
1909 foreach ($insprovs as $key => $ipname) {
1910 if ($currvalue == $key) {
1911 $tmp = $ipname;
1915 if (empty($tmp)) {
1916 $tmp = "($currvalue)";
1920 if ($tmp === '') {
1921 $tmp = '&nbsp;';
1922 } else {
1923 $tmp = htmlspecialchars($tmp, ENT_QUOTES);
1926 echo $tmp;
1927 } elseif ($data_type == 17) { // issue types
1928 $tmp = '';
1929 if ($currvalue) {
1930 foreach ($ISSUE_TYPES as $key => $value) {
1931 if ($currvalue == $key) {
1932 $tmp = $value[1];
1936 if (empty($tmp)) {
1937 $tmp = "($currvalue)";
1941 if ($tmp === '') {
1942 $tmp = '&nbsp;';
1943 } else {
1944 $tmp = htmlspecialchars($tmp, ENT_QUOTES);
1947 echo $tmp;
1948 } elseif ($data_type == 18) { // Visit categories.
1949 $tmp = '';
1950 if ($currvalue) {
1951 $crow = sqlQuery(
1952 "SELECT pc_catid, pc_catname " .
1953 "FROM openemr_postcalendar_categories WHERE pc_catid = ?",
1954 array($currvalue)
1956 $tmp = xl_appt_category($crow['pc_catname']);
1957 if (empty($tmp)) {
1958 $tmp = "($currvalue)";
1962 if ($tmp === '') {
1963 $tmp = '&nbsp;';
1964 } else {
1965 $tmp = htmlspecialchars($tmp, ENT_QUOTES);
1968 echo $tmp;
1969 } elseif ($data_type == 21) { // a single checkbox or set of labeled checkboxes
1970 if (!$list_id) {
1971 echo "<input type='checkbox'";
1972 if ($currvalue) {
1973 echo " checked";
1975 echo " />";
1976 } else {
1977 // In this special case, fld_length is the number of columns generated.
1978 $cols = max(1, $fld_length);
1979 $avalue = explode('|', $currvalue);
1980 $lres = sqlStatement("SELECT * FROM list_options " .
1981 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
1982 echo "<table class='w-100' cellpadding='0' cellspacing='0'>";
1983 $tdpct = (int) (100 / $cols);
1984 for ($count = 0; $lrow = sqlFetchArray($lres); ++$count) {
1985 $option_id = $lrow['option_id'];
1986 if ($count % $cols == 0) {
1987 if ($count) {
1988 echo "</tr>";
1991 echo "<tr>";
1993 echo "<td width='" . attr($tdpct) . "%' nowrap>";
1994 echo "<input type='checkbox'";
1995 if (in_array($option_id, $avalue)) {
1996 echo " checked";
1998 echo ">" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES);
1999 echo "</td>";
2001 if ($count) {
2002 echo "</tr>";
2003 if ($count > $cols) {
2004 // Add some space after multiple rows of checkboxes.
2005 $cols = htmlspecialchars($cols, ENT_QUOTES);
2006 echo "<tr><td colspan='$cols' style='height:0.7em'></td></tr>";
2009 echo "</table>";
2011 } elseif ($data_type == 22) { // a set of labeled text input fields
2012 $tmp = explode('|', $currvalue);
2013 $avalue = array();
2014 foreach ($tmp as $value) {
2015 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
2016 $avalue[$matches[1]] = $matches[2];
2020 $lres = sqlStatement("SELECT * FROM list_options " .
2021 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2022 echo "<table class='table'>";
2023 while ($lrow = sqlFetchArray($lres)) {
2024 $option_id = $lrow['option_id'];
2025 $fldlength = empty($fld_length) ? 20 : $fld_length;
2026 echo "<tr><td>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES) . "&nbsp;</td>";
2027 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES);
2028 $inputValue = htmlspecialchars($avalue[$option_id], ENT_QUOTES);
2029 echo "<td><input type='text'" .
2030 " class='form-control' " .
2031 " size='$fldlength'" .
2032 " value='$inputValue'" .
2033 " class='under'" .
2034 " /></td></tr>";
2037 echo "</table>";
2038 } elseif ($data_type == 23) { // a set of exam results; 3 radio buttons and a text field:
2039 $tmp = explode('|', $currvalue);
2040 $avalue = array();
2041 foreach ($tmp as $value) {
2042 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
2043 $avalue[$matches[1]] = $matches[2];
2047 $fldlength = empty($fld_length) ? 20 : $fld_length;
2048 $lres = sqlStatement("SELECT * FROM list_options " .
2049 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2050 echo "<table class='table'>";
2051 echo "<tr><td><td class='font-weight-bold'>" .
2052 htmlspecialchars(xl('Exam or Test'), ENT_NOQUOTES) . "</td><td class='font-weight-bold'>" .
2053 htmlspecialchars(xl('N/A'), ENT_NOQUOTES) .
2054 "&nbsp;</td><td class='font-weight-bold'>" .
2055 htmlspecialchars(xl('Nor'), ENT_NOQUOTES) . "&nbsp;</td>" .
2056 "<td class='font-weight-bold'>" .
2057 htmlspecialchars(xl('Abn'), ENT_NOQUOTES) . "&nbsp;</td><td class='font-weight-bold'>" .
2058 htmlspecialchars(xl('Date/Notes'), ENT_NOQUOTES) . "</td></tr>";
2059 while ($lrow = sqlFetchArray($lres)) {
2060 $option_id = $lrow['option_id'];
2061 $restype = substr($avalue[$option_id], 0, 1);
2062 $resnote = substr($avalue[$option_id], 2);
2063 echo "<tr><td>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES) . "&nbsp;</td>";
2064 for ($i = 0; $i < 3; ++$i) {
2065 echo "<td><input type='radio'";
2066 if ($restype === "$i") {
2067 echo " checked";
2070 echo " /></td>";
2073 $resnote = htmlspecialchars($resnote, ENT_QUOTES);
2074 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES);
2075 echo "<td><input type='text'" .
2076 " size='$fldlength'" .
2077 " value='$resnote'" .
2078 " class='under form-control' /></td>" .
2079 "</tr>";
2082 echo "</table>";
2083 } elseif ($data_type == 24) { // the list of active allergies for the current patient
2084 // this is read-only!
2085 $query = "SELECT title, comments FROM lists WHERE " .
2086 "pid = ? AND type = 'allergy' AND enddate IS NULL " .
2087 "ORDER BY begdate";
2088 $lres = sqlStatement($query, array($GLOBALS['pid']));
2089 $count = 0;
2090 while ($lrow = sqlFetchArray($lres)) {
2091 if ($count++) {
2092 echo "<br />";
2095 echo htmlspecialchars($lrow['title'], ENT_QUOTES);
2096 if ($lrow['comments']) {
2097 echo htmlspecialchars(' (' . $lrow['comments'] . ')', ENT_QUOTES);
2100 } elseif ($data_type == 25) { // a set of labeled checkboxes, each with a text field:
2101 $tmp = explode('|', $currvalue);
2102 $avalue = array();
2103 foreach ($tmp as $value) {
2104 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
2105 $avalue[$matches[1]] = $matches[2];
2109 $fldlength = empty($fld_length) ? 20 : $fld_length;
2110 $lres = sqlStatement("SELECT * FROM list_options " .
2111 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2112 echo "<table class='table'>";
2113 while ($lrow = sqlFetchArray($lres)) {
2114 $option_id = $lrow['option_id'];
2115 $restype = substr($avalue[$option_id], 0, 1);
2116 $resnote = substr($avalue[$option_id], 2);
2117 echo "<tr><td>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES) . "&nbsp;</td>";
2118 echo "<td><input type='checkbox'";
2119 if ($restype) {
2120 echo " checked";
2123 echo " />&nbsp;</td>";
2124 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES);
2125 $resnote = htmlspecialchars($resnote, ENT_QUOTES);
2126 echo "<td><input type='text'" .
2127 " size='$fldlength'" .
2128 " class='form-control' " .
2129 " value='$resnote'" .
2130 " class='under'" .
2131 " /></td>" .
2132 "</tr>";
2135 echo "</table>";
2136 } elseif ($data_type == 27) { // Removed: || $data_type == 1 || $data_type == 26 || $data_type == 33
2137 // a set of labeled radio buttons
2138 // In this special case, fld_length is the number of columns generated.
2140 $cols = max(1, ($frow['fld_length'] ?? null));
2141 $lres = sqlStatement("SELECT * FROM list_options " .
2142 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2143 echo "<table class='w-100' cellpadding='0' cellspacing='0'>";
2144 $tdpct = (int) (100 / $cols);
2145 for ($count = 0; $lrow = sqlFetchArray($lres); ++$count) {
2146 $option_id = $lrow['option_id'];
2147 if ($count % $cols == 0) {
2148 if ($count) {
2149 echo "</tr>";
2151 echo "<tr>";
2153 echo "<td width='" . attr($tdpct) . "%' nowrap>";
2154 echo "<input type='radio'";
2155 if (strlen($currvalue) > 0 && $option_id == $currvalue) {
2156 // Do not use defaults for these printable forms.
2157 echo " checked";
2159 echo ">" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES);
2160 echo "</td>";
2162 if ($count) {
2163 echo "</tr>";
2164 if ($count > $cols) {
2165 // Add some space after multiple rows of radio buttons.
2166 $cols = htmlspecialchars($cols, ENT_QUOTES);
2167 echo "<tr><td colspan='$cols' style='height:0.7em'></td></tr>";
2170 echo "</table>";
2172 // special case for history of lifestyle status; 3 radio buttons and a date text field:
2173 } elseif ($data_type == 28 || $data_type == 32) {
2174 $tmp = explode('|', $currvalue);
2175 switch (count($tmp)) {
2176 case "4":
2177 $resnote = $tmp[0];
2178 $restype = $tmp[1];
2179 $resdate = oeFormatShortDate($tmp[2]) ;
2180 $reslist = $tmp[3];
2181 break;
2182 case "3":
2183 $resnote = $tmp[0];
2184 $restype = $tmp[1];
2185 $resdate = oeFormatShortDate($tmp[2]);
2186 $reslist = '';
2187 break;
2188 case "2":
2189 $resnote = $tmp[0];
2190 $restype = $tmp[1];
2191 $resdate = "";
2192 $reslist = '';
2193 break;
2194 case "1":
2195 $resnote = $tmp[0];
2196 $resdate = $restype = "";
2197 $reslist = '';
2198 break;
2199 default:
2200 $restype = $resdate = $resnote = "";
2201 $reslist = '';
2202 break;
2205 $fldlength = empty($frow['fld_length']) ? 20 : $frow['fld_length'];
2206 echo "<table class='table'>";
2207 echo "<tr>";
2208 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES);
2209 $resnote = htmlspecialchars($resnote, ENT_QUOTES);
2210 $resdate = htmlspecialchars($resdate, ENT_QUOTES);
2211 if ($data_type == 28) {
2212 echo "<td><input type='text'" .
2213 " size='$fldlength'" .
2214 " class='under'" .
2215 " value='$resnote' /></td>";
2216 echo "<td class='font-weight-bold'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" .
2217 "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" .
2218 htmlspecialchars(xl('Status'), ENT_NOQUOTES) . ":&nbsp;</td>";
2219 } elseif ($data_type == 32) {
2220 echo "<tr><td><input type='text'" .
2221 " size='$fldlength'" .
2222 " class='under form-control'" .
2223 " value='$resnote' /></td></tr>";
2224 $fldlength = 30;
2225 $smoking_status_title = generate_display_field(array('data_type' => '1','list_id' => $list_id), $reslist);
2226 echo "<td><input type='text'" .
2227 " size='$fldlength'" .
2228 " class='under form-control'" .
2229 " value='$smoking_status_title' /></td>";
2230 echo "<td class='font-weight-bold'>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;" . htmlspecialchars(xl('Status'), ENT_NOQUOTES) . ":&nbsp;&nbsp;</td>";
2233 echo "<td><input type='radio' class='form-check-inline'";
2234 if ($restype == "current" . $field_id) {
2235 echo " checked";
2238 echo "/>" . htmlspecialchars(xl('Current'), ENT_NOQUOTES) . "&nbsp;</td>";
2240 echo "<td><input type='radio' class='form-check-inline'";
2241 if ($restype == "current" . $field_id) {
2242 echo " checked";
2245 echo "/>" . htmlspecialchars(xl('Quit'), ENT_NOQUOTES) . "&nbsp;</td>";
2247 echo "<td><input type='text' size='6'" .
2248 " value='$resdate'" .
2249 " class='under form-control'" .
2250 " /></td>";
2252 echo "<td><input type='radio' class='form-check-inline'";
2253 if ($restype == "current" . $field_id) {
2254 echo " checked";
2257 echo " />" . htmlspecialchars(xl('Never'), ENT_NOQUOTES) . "</td>";
2259 echo "<td><input type='radio' class='form-check-inline'";
2260 if ($restype == "not_applicable" . $field_id) {
2261 echo " checked";
2264 echo " />" . htmlspecialchars(xl('N/A'), ENT_NOQUOTES) . "&nbsp;</td>";
2265 echo "</tr>";
2266 echo "</table>";
2267 } elseif ($data_type == 31) { // static text. read-only, of course.
2268 echo parse_static_text($frow, $value_allowed);
2269 } elseif ($data_type == 34) {
2270 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'>";
2271 echo "<div id='form_{$field_id}_div' class='text-area'></div>";
2272 echo "<div style='display: none'><textarea name='form_{$field_id}' class='form-control' id='form_{$field_id}' style='display: none'></textarea></div>";
2273 echo "</a>";
2275 // Facilities. Changed 2017-12-15 to not show the choices.
2276 } elseif ($data_type == 35) {
2277 $urow = sqlQuery(
2278 "SELECT id, name FROM facility WHERE id = ?",
2279 array($currvalue)
2281 echo empty($urow['id']) ? '&nbsp;' : text($urow['name']);
2282 } elseif ($data_type == 36) { //Multi-select. Supports backup lists.
2283 if (empty($fld_length)) {
2284 if ($list_id == 'titles') {
2285 $fld_length = 3;
2286 } else {
2287 $fld_length = 10;
2291 $tmp = '';
2293 $values_array = explode("|", $currvalue);
2295 $i = 0;
2296 foreach ($values_array as $value) {
2297 if ($value) {
2298 $lrow = sqlQuery("SELECT title FROM list_options " .
2299 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($list_id,$value));
2300 $tmp = xl_list_label($lrow['title']);
2301 if ($lrow == 0 && !empty($backup_list)) {
2302 // since primary list did not map, try to map to backup list
2303 $lrow = sqlQuery("SELECT title FROM list_options " .
2304 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($backup_list,$currvalue));
2305 $tmp = xl_list_label($lrow['title']);
2308 if (empty($tmp)) {
2309 $tmp = "($value)";
2313 if ($tmp === '') {
2314 $tmp = '&nbsp;';
2315 } else {
2316 $tmp = htmlspecialchars($tmp, ENT_QUOTES);
2319 if ($i != 0 && $tmp != '&nbsp;') {
2320 echo ",";
2323 echo $tmp;
2324 $i++;
2327 // A set of lab test results; Gestation, 3 radio buttons, test value, notes field:
2328 } elseif ($data_type == 37) {
2329 echo genLabResults($frow, $currvalue, 1, $disabled);
2330 } elseif ($data_type == 40) { // Image from canvas drawing
2331 if (empty($currvalue)) {
2332 if (preg_match('/\\bimage=([a-zA-Z0-9._-]*)/', $frow['description'], $matches)) {
2333 $currvalue = $GLOBALS['web_root'] . '/sites/' . $_SESSION['site_id'] . '/images/' . $matches[1];
2336 if ($currvalue) {
2337 echo "<img src='" . attr($currvalue) . "'>";
2339 } elseif ($data_type == 41 || $data_type == 42) {
2340 if ($currvalue) {
2341 echo "<img class='w-auto' style='height: 70px;' src='" . attr($currvalue) . "'>";
2343 } elseif ($data_type == 44 || $data_type == 45) {
2344 $tmp = '';
2346 $values_array = explode("|", $currvalue);
2348 $i = 0;
2349 foreach ($values_array as $value) {
2350 if ($value) {
2351 if ($data_type == 44) {
2352 $lrow = sqlQuery("SELECT name as name FROM facility WHERE id = ?", array($value));
2354 if ($data_type == 45) {
2355 $lrow = sqlQuery("SELECT CONCAT(fname,' ',lname) as name FROM users WHERE id = ?", array($value));
2357 $tmp = $lrow['name'];
2360 if ($tmp === '') {
2361 $tmp = '&nbsp;';
2362 } else {
2363 $tmp = htmlspecialchars($tmp, ENT_QUOTES);
2366 if ($i != 0 && $tmp != '&nbsp;') {
2367 echo ",";
2370 echo $tmp;
2371 $i++;
2374 // Patient selector field.
2375 } else if ($data_type == 51) {
2376 if (!empty($currvalue)) {
2377 $tmp = text(getPatientDescription($currvalue));
2378 } else {
2379 echo '&nbsp;';
2385 * @param $list_id
2386 * @param bool $translate
2387 * @return array
2389 * Generate a key-value array containing each row of the specified list,
2390 * with the option ID as the index, and the title as the element
2392 * Pass in the list_id to specify this list.
2394 * Use the translate flag to run the title element through the translator
2396 function generate_list_map($list_id, $translate = false)
2398 $result = sqlStatement("SELECT option_id, title FROM list_options WHERE list_id = ?", [$list_id]);
2399 $map = [];
2400 while ($row = sqlFetchArray($result)) {
2401 if ($translate === true) {
2402 $title = xl_list_label($row['title']);
2403 } else {
2404 $title = $row['title'];
2406 $map[$row['option_id']] = $title;
2409 return $map;
2412 function generate_display_field($frow, $currvalue)
2414 global $ISSUE_TYPES, $facilityService;
2416 $data_type = $frow['data_type'];
2417 $field_id = isset($frow['field_id']) ? $frow['field_id'] : null;
2418 $list_id = $frow['list_id'];
2419 $backup_list = isset($frow['list_backup_id']) ? $frow['list_backup_id'] : null;
2421 $s = '';
2423 // generic selection list or the generic selection list with add on the fly
2424 // feature
2425 if ($data_type == 1 || $data_type == 26 || $data_type == 43 || $data_type == 46) {
2426 if ($data_type == 46) {
2427 // support for single-selection list with comment support
2428 $selectedValues = explode("|", $currvalue);
2429 $currvalue = $selectedValues[0];
2432 $lrow = sqlQuery("SELECT title FROM list_options " .
2433 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($list_id,$currvalue));
2434 $s = htmlspecialchars(xl_list_label($lrow['title'] ?? ''), ENT_NOQUOTES);
2435 //if there is no matching value in the corresponding lists check backup list
2436 // only supported in data types 1,26,43,46
2437 if ($lrow == 0 && !empty($backup_list) && ($data_type == 1 || $data_type == 26 || $$data_type == 43 || $data_type == 46)) {
2438 $lrow = sqlQuery("SELECT title FROM list_options " .
2439 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($backup_list,$currvalue));
2440 $s = htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES);
2443 // If match is not found in main and backup lists, return the key with exclamation mark
2444 if ($s == '') {
2445 $s = nl2br(text(xl_list_label($currvalue))) .
2446 '<span> <i class="fa fas fa-exclamation-circle ml-1"></i></span>';
2449 if ($data_type == 46) {
2450 // support for single-selection list with comment support
2451 $resnote = $selectedValues[1] ?? null;
2452 if (!empty($resnote)) {
2453 $s .= " (" . text($resnote) . ")";
2456 } elseif ($data_type == 2) { // simple text field
2457 $s = nl2br(htmlspecialchars($currvalue, ENT_NOQUOTES));
2458 } elseif ($data_type == 3) { // long or multi-line text field
2459 $s = nl2br(htmlspecialchars($currvalue, ENT_NOQUOTES));
2460 } elseif ($data_type == 4) { // date
2461 $asof = ''; //not used here, but set to prevent a php warning when call optionalAge
2462 $s = '';
2463 $description = (isset($frow['description']) ? htmlspecialchars(xl_layout_label($frow['description']), ENT_QUOTES) : '');
2464 $age_asof_date = '';
2465 $agestr = optionalAge($frow, $currvalue, $age_asof_date, $description);
2466 if ($currvalue === '') {
2467 $s .= '&nbsp;';
2468 } else {
2469 $modtmp = isOption($frow['edit_options'], 'F') === false ? 0 : 1;
2470 if (!$modtmp) {
2471 $s .= text(oeFormatShortDate($currvalue));
2472 } else {
2473 $s .= text(oeFormatDateTime($currvalue));
2475 if ($agestr) {
2476 $s .= "&nbsp;(" . text($agestr) . ")";
2479 } elseif ($data_type == 10 || $data_type == 11) { // provider
2480 $urow = sqlQuery("SELECT fname, lname, specialty FROM users " .
2481 "WHERE id = ?", array($currvalue));
2482 $s = text(ucwords(($urow['fname'] ?? '') . " " . ($urow['lname'] ?? '')));
2483 } elseif ($data_type == 12) { // pharmacy list
2484 $pres = get_pharmacies();
2485 while ($prow = sqlFetchArray($pres)) {
2486 $key = $prow['id'];
2487 if ($currvalue == $key) {
2488 $s .= htmlspecialchars($prow['name'] . ' ' . $prow['area_code'] . '-' .
2489 $prow['prefix'] . '-' . $prow['number'] . ' / ' .
2490 $prow['line1'] . ' / ' . $prow['city'], ENT_NOQUOTES);
2493 } elseif ($data_type == 13) { // squads
2494 $squads = AclExtended::aclGetSquads();
2495 if ($squads) {
2496 foreach ($squads as $key => $value) {
2497 if ($currvalue == $key) {
2498 $s .= htmlspecialchars($value[3], ENT_NOQUOTES);
2502 } elseif ($data_type == 14) { // address book
2503 $urow = sqlQuery("SELECT fname, lname, specialty, organization FROM users " .
2504 "WHERE id = ?", array($currvalue));
2505 //ViSolve: To display the Organization Name if it exist. Else it will display the user name.
2506 if (!empty($urow['organization'])) {
2507 $uname = $urow['organization'];
2508 } else {
2509 $uname = $urow['lname'] ?? '';
2510 if (!empty($urow['fname'])) {
2511 $uname .= ", " . $urow['fname'];
2515 $s = htmlspecialchars($uname, ENT_NOQUOTES);
2516 } elseif ($data_type == 15) { // billing code
2517 $s = '';
2518 if (!empty($currvalue)) {
2519 $relcodes = explode(';', $currvalue);
2520 foreach ($relcodes as $codestring) {
2521 if ($codestring === '') {
2522 continue;
2524 $tmp = lookup_code_descriptions($codestring);
2525 if ($s !== '') {
2526 $s .= '; ';
2528 if (!empty($tmp)) {
2529 $s .= text($tmp);
2530 } else {
2531 $s .= text($codestring) . ' (' . xlt('not found') . ')';
2535 } elseif ($data_type == 16) { // insurance company list
2536 $insprovs = getInsuranceProviders();
2537 foreach ($insprovs as $key => $ipname) {
2538 if ($currvalue == $key) {
2539 $s .= htmlspecialchars($ipname, ENT_NOQUOTES);
2542 } elseif ($data_type == 17) { // issue types
2543 foreach ($ISSUE_TYPES as $key => $value) {
2544 if ($currvalue == $key) {
2545 $s .= htmlspecialchars($value[1], ENT_NOQUOTES);
2548 } elseif ($data_type == 18) { // visit category
2549 $crow = sqlQuery(
2550 "SELECT pc_catid, pc_catname " .
2551 "FROM openemr_postcalendar_categories WHERE pc_catid = ?",
2552 array($currvalue)
2554 $s = htmlspecialchars($crow['pc_catname'], ENT_NOQUOTES);
2555 } elseif ($data_type == 21) { // a single checkbox or set of labeled checkboxes
2556 if (!$list_id) {
2557 $s .= $currvalue ? '[ x ]' : '[ &nbsp;&nbsp; ]';
2558 } else {
2559 // In this special case, fld_length is the number of columns generated.
2560 $cols = max(1, $frow['fld_length']);
2561 $avalue = explode('|', $currvalue);
2562 $lres = sqlStatement("SELECT * FROM list_options " .
2563 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2564 $s .= "<table cellspacing='0' cellpadding='0'>";
2565 for ($count = 0; $lrow = sqlFetchArray($lres); ++$count) {
2566 $option_id = $lrow['option_id'];
2567 $option_id_esc = text($option_id);
2568 if ($count % $cols == 0) {
2569 if ($count) {
2570 $s .= "</tr>";
2572 $s .= "<tr>";
2574 $s .= "<td nowrap>";
2575 $checked = in_array($option_id, $avalue);
2576 $s .= $checked ? '[ x ]' : '[ &nbsp;&nbsp; ]';
2577 $s .= '&nbsp;' . text(xl_list_label($lrow['title'])) . '&nbsp;&nbsp;';
2578 $s .= "</td>";
2580 if ($count) {
2581 $s .= "</tr>";
2583 $s .= "</table>";
2585 } elseif ($data_type == 22) { // a set of labeled text input fields
2586 $tmp = explode('|', $currvalue);
2587 $avalue = array();
2588 foreach ($tmp as $value) {
2589 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
2590 $avalue[$matches[1]] = $matches[2];
2594 $lres = sqlStatement("SELECT * FROM list_options " .
2595 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2596 $s .= "<table class='table'>";
2597 while ($lrow = sqlFetchArray($lres)) {
2598 $option_id = $lrow['option_id'];
2599 if (empty($avalue[$option_id])) {
2600 continue;
2603 // Added 5-09 by BM - Translate label if applicable
2604 $s .= "<tr><td class='font-weight-bold align-top'>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES) . ":&nbsp;</td>";
2606 $s .= "<td class='text align-top'>" . htmlspecialchars($avalue[$option_id], ENT_NOQUOTES) . "</td></tr>";
2609 $s .= "</table>";
2610 } elseif ($data_type == 23) { // a set of exam results; 3 radio buttons and a text field:
2611 $tmp = explode('|', $currvalue);
2612 $avalue = array();
2613 foreach ($tmp as $value) {
2614 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
2615 $avalue[$matches[1]] = $matches[2];
2619 $lres = sqlStatement("SELECT * FROM list_options " .
2620 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2621 $s .= "<table class='table'>";
2622 while ($lrow = sqlFetchArray($lres)) {
2623 $option_id = $lrow['option_id'];
2624 $restype = substr(($avalue[$option_id] ?? ''), 0, 1);
2625 $resnote = substr(($avalue[$option_id] ?? ''), 2);
2626 if (empty($restype) && empty($resnote)) {
2627 continue;
2630 // Added 5-09 by BM - Translate label if applicable
2631 $s .= "<tr><td class='font-weight-bold align-top'>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES) . "&nbsp;</td>";
2633 $restype = ($restype == '1') ? xl('Normal') : (($restype == '2') ? xl('Abnormal') : xl('N/A'));
2634 // $s .= "<td class='text align-top'>$restype</td></tr>";
2635 // $s .= "<td class='text align-top'>$resnote</td></tr>";
2636 $s .= "<td class='text align-top'>" . htmlspecialchars($restype, ENT_NOQUOTES) . "&nbsp;</td>";
2637 $s .= "<td class='text align-top'>" . htmlspecialchars($resnote, ENT_NOQUOTES) . "</td>";
2638 $s .= "</tr>";
2641 $s .= "</table>";
2642 } elseif ($data_type == 24) { // the list of active allergies for the current patient
2643 $query = "SELECT title, comments FROM lists WHERE " .
2644 "pid = ? AND type = 'allergy' AND enddate IS NULL " .
2645 "ORDER BY begdate";
2646 // echo "<!-- $query -->\n"; // debugging
2647 $lres = sqlStatement($query, array($GLOBALS['pid']));
2648 $count = 0;
2649 while ($lrow = sqlFetchArray($lres)) {
2650 if ($count++) {
2651 $s .= "<br />";
2654 $s .= htmlspecialchars($lrow['title'], ENT_NOQUOTES);
2655 if ($lrow['comments']) {
2656 $s .= ' (' . htmlspecialchars($lrow['comments'], ENT_NOQUOTES) . ')';
2659 } elseif ($data_type == 25) { // a set of labeled checkboxes, each with a text field:
2660 $tmp = explode('|', $currvalue);
2661 $avalue = array();
2662 foreach ($tmp as $value) {
2663 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
2664 $avalue[$matches[1]] = $matches[2];
2668 $lres = sqlStatement("SELECT * FROM list_options " .
2669 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2670 $s .= "<table class='table'>";
2671 while ($lrow = sqlFetchArray($lres)) {
2672 $option_id = $lrow['option_id'];
2673 $restype = substr($avalue[$option_id], 0, 1);
2674 $resnote = substr($avalue[$option_id], 2);
2675 if (empty($restype) && empty($resnote)) {
2676 continue;
2679 // Added 5-09 by BM - Translate label if applicable
2680 $s .= "<tr><td class='font-weight-bold align-top'>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES) . "&nbsp;</td>";
2682 $restype = $restype ? xl('Yes') : xl('No');
2683 $s .= "<td class='text align-top'>" . htmlspecialchars($restype, ENT_NOQUOTES) . "&nbsp;</td>";
2684 $s .= "<td class='text align-top'>" . htmlspecialchars($resnote, ENT_NOQUOTES) . "</td>";
2685 $s .= "</tr>";
2688 $s .= "</table>";
2689 } elseif ($data_type == 27) { // a set of labeled radio buttons
2690 // In this special case, fld_length is the number of columns generated.
2691 $cols = max(1, $frow['fld_length']);
2692 $lres = sqlStatement("SELECT * FROM list_options " .
2693 "WHERE list_id = ? ORDER BY seq, title", array($list_id));
2694 $s .= "<table cellspacing='0' cellpadding='0'>";
2695 for ($count = 0; $lrow = sqlFetchArray($lres); ++$count) {
2696 $option_id = $lrow['option_id'];
2697 $option_id_esc = text($option_id);
2698 if ($count % $cols == 0) {
2699 if ($count) {
2700 $s .= "</tr>";
2702 $s .= "<tr>";
2704 $s .= "<td nowrap>";
2705 $checked = ((strlen($currvalue) == 0 && $lrow['is_default']) ||
2706 (strlen($currvalue) > 0 && $option_id == $currvalue));
2707 $s .= $checked ? '[ x ]' : '[ &nbsp;&nbsp; ]';
2708 $s .= '&nbsp;' . text(xl_list_label($lrow['title'])) . '&nbsp;&nbsp;';
2709 $s .= "</td>";
2711 if ($count) {
2712 $s .= "</tr>";
2714 $s .= "</table>";
2715 } elseif ($data_type == 28 || $data_type == 32) { // special case for history of lifestyle status; 3 radio buttons
2716 // and a date text field:
2717 // VicarePlus :: A selection list for smoking status.
2718 $tmp = explode('|', $currvalue);
2719 switch (count($tmp)) {
2720 case "4":
2721 $resnote = $tmp[0];
2722 $restype = $tmp[1];
2723 $resdate = oeFormatShortDate($tmp[2]);
2724 $reslist = $tmp[3];
2725 break;
2726 case "3":
2727 $resnote = $tmp[0];
2728 $restype = $tmp[1];
2729 $resdate = oeFormatShortDate($tmp[2]);
2730 $reslist = '';
2731 break;
2732 case "2":
2733 $resnote = $tmp[0];
2734 $restype = $tmp[1];
2735 $resdate = "";
2736 $reslist = '';
2737 break;
2738 case "1":
2739 $resnote = $tmp[0];
2740 $resdate = $restype = "";
2741 $reslist = '';
2742 break;
2743 default:
2744 $restype = $resdate = $resnote = "";
2745 $reslist = '';
2746 break;
2749 $s .= "<table class='table'>";
2751 $s .= "<tr>";
2752 $res = "";
2753 if ($restype == "current" . $field_id) {
2754 $res = xl('Current');
2757 if ($restype == "quit" . $field_id) {
2758 $res = xl('Quit');
2761 if ($restype == "never" . $field_id) {
2762 $res = xl('Never');
2765 if ($restype == "not_applicable" . $field_id) {
2766 $res = xl('N/A');
2769 // $s .= "<td class='text align-top'>$restype</td></tr>";
2770 // $s .= "<td class='text align-top'>$resnote</td></tr>";
2771 if ($data_type == 28) {
2772 if (!empty($resnote)) {
2773 $s .= "<td class='text align-top'>" . htmlspecialchars($resnote, ENT_NOQUOTES) . "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</td>";
2775 } elseif ($data_type == 32) { //VicarePlus :: Tobacco field has a listbox, text box, date field and 3 radio buttons.
2776 // changes on 5-jun-2k14 (regarding 'Smoking Status - display SNOMED code description')
2777 $smoke_codes = getSmokeCodes();
2778 if (!empty($reslist)) {
2779 if ($smoke_codes[$reslist] != "") {
2780 $code_desc = "( " . $smoke_codes[$reslist] . " )";
2783 $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>";
2786 if (!empty($resnote)) {
2787 $s .= "<td class='text align-top'>" . htmlspecialchars($resnote, ENT_NOQUOTES) . "&nbsp;&nbsp;</td>";
2791 if (!empty($res)) {
2792 $s .= "<td class='text align-top'><strong>" . htmlspecialchars(xl('Status'), ENT_NOQUOTES) . "</strong>:&nbsp;" . htmlspecialchars($res, ENT_NOQUOTES) . "&nbsp;</td>";
2795 if ($restype == "quit" . $field_id) {
2796 $s .= "<td class='text align-top'>" . htmlspecialchars($resdate, ENT_NOQUOTES) . "&nbsp;</td>";
2799 $s .= "</tr>";
2800 $s .= "</table>";
2801 } elseif ($data_type == 31) { // static text. read-only, of course.
2802 $s .= parse_static_text($frow);
2803 } elseif ($data_type == 34) {
2804 $arr = explode("|*|*|*|", $currvalue);
2805 for ($i = 0; $i < sizeof($arr); $i++) {
2806 $s .= $arr[$i];
2808 } elseif ($data_type == 35) { // facility
2809 $urow = $facilityService->getById($currvalue);
2810 $s = htmlspecialchars($urow['name'], ENT_NOQUOTES);
2811 } elseif ($data_type == 36 || $data_type == 33) { // Multi select. Supports backup lists
2812 $values_array = explode("|", $currvalue);
2813 $i = 0;
2814 foreach ($values_array as $value) {
2815 $lrow = sqlQuery("SELECT title FROM list_options " .
2816 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($list_id,$value));
2817 if ($lrow == 0 && !empty($backup_list)) {
2818 //use back up list
2819 $lrow = sqlQuery("SELECT title FROM list_options " .
2820 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($backup_list,$value));
2823 $title = $lrow['title'] ?? '';
2824 if ($i > 0) {
2825 $s = $s . ", " . text(xl_list_label($title));
2826 } else {
2827 $s = text(xl_list_label($title));
2830 $i++;
2833 // A set of lab test results; Gestation, 3 radio buttons, test value, notes field:
2834 } elseif ($data_type == 37) {
2835 $s .= genLabResults($frow, $currvalue, 2, '');
2836 } elseif ($data_type == 40) { // Image from canvas drawing
2837 if (empty($currvalue)) {
2838 if (preg_match('/\\bimage=([a-zA-Z0-9._-]*)/', $frow['description'], $matches)) {
2839 $currvalue = $GLOBALS['web_root'] . '/sites/' . $_SESSION['site_id'] . '/images/' . $matches[1];
2842 if ($currvalue) {
2843 $s .= "<img src='" . attr($currvalue) . "'>";
2845 } elseif ($data_type == 41 || $data_type == 42) {
2846 if ($currvalue) {
2847 $s .= "<img class='w-auto' style='height: 70px;' src='" . attr($currvalue) . "'>";
2849 } elseif ($data_type == 44 || $data_type == 45) { // Multiple select facility and provider
2850 $values_array = explode("|", $currvalue);
2851 $i = 0;
2852 foreach ($values_array as $value) {
2853 if ($data_type == 44) {
2854 $lrow = sqlQuery("SELECT name as name FROM facility WHERE id = ?", array($value));
2856 if ($data_type == 45) {
2857 $lrow = sqlQuery("SELECT CONCAT(fname,' ',lname) as name FROM users WHERE id = ?", array($value));
2859 if ($i > 0) {
2860 $s = $s . ", " . htmlspecialchars($lrow['name'], ENT_NOQUOTES);
2861 } else {
2862 $s = text($lrow['name'] ?? '');
2864 $i++;
2867 // Patient selector field.
2868 } elseif ($data_type == 51) {
2869 if (!empty($currvalue)) {
2870 $s .= text(getPatientDescription($currvalue));
2872 } elseif ($data_type == 52) {
2873 global $pid;
2874 $patientService = new PatientService();
2875 $rows = $patientService->getPatientNameHistory($pid);
2876 $i = 0;
2877 foreach ($rows as $row) {
2878 // name escaped in fetch
2879 if ($i > 0) {
2880 $s .= ", " . $row['formatted_name'];
2881 } else {
2882 $s = $row['formatted_name'] ?? '';
2884 $i++;
2886 // now that we've concatenated everything, let's escape it.
2887 $s = text($s);
2888 } elseif ($data_type == 53) {
2889 $service = new EncounterService();
2890 if (!empty($currvalue)) {
2891 $encounterResult = $service->getEncounterById($currvalue);
2892 if (!empty($encounterResult) && $encounterResult->hasData()) {
2893 $encounter = reset($encounterResult->getData());
2894 $s = text($encounter['date'] ?? '');
2899 return $s;
2902 // Generate plain text versions of selected LBF field types.
2903 // Currently used by interface/patient_file/download_template.php and interface/main/finder/dynamic_finder_ajax.php.
2904 // More field types might need to be supported here in the future.
2906 function generate_plaintext_field($frow, $currvalue)
2908 global $ISSUE_TYPES;
2910 $data_type = $frow['data_type'];
2911 $field_id = isset($frow['field_id']) ? $frow['field_id'] : null;
2912 $list_id = $frow['list_id'];
2913 $backup_list = $frow['backup_list'] ?? null;
2914 $edit_options = $frow['edit_options'] ?? null;
2915 $s = '';
2917 // generic selection list or the generic selection list with add on the fly
2918 // feature, or radio buttons
2919 // Supports backup lists (for datatypes 1,26,43)
2920 if ($data_type == 1 || $data_type == 26 || $data_type == 27 || $data_type == 43 || $data_type == 46) {
2921 if ($data_type == 46) {
2922 // support for single-selection list with comment support
2923 $selectedValues = explode("|", $currvalue);
2924 $currvalue = $selectedValues[0];
2927 $lrow = sqlQuery(
2928 "SELECT title FROM list_options " .
2929 "WHERE list_id = ? AND option_id = ? AND activity = 1",
2930 array($list_id, $currvalue)
2932 $s = xl_list_label($lrow['title'] ?? '');
2933 //if there is no matching value in the corresponding lists check backup list
2934 // only supported in data types 1,26,43
2935 if ($lrow == 0 && !empty($backup_list) && ($data_type == 1 || $data_type == 26 || $data_type == 43 || $data_type == 46)) {
2936 $lrow = sqlQuery("SELECT title FROM list_options " .
2937 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($backup_list, $currvalue));
2938 $s = xl_list_label($lrow['title']);
2941 if ($data_type == 46) {
2942 // support for single-selection list with comment support
2943 $resnote = $selectedValues[1] ?? null;
2944 if (!empty($resnote)) {
2945 $s .= " (" . $resnote . ")";
2948 } elseif ($data_type == 2 || $data_type == 3 || $data_type == 15) { // simple or long text field
2949 $s = $currvalue;
2950 } elseif ($data_type == 4) { // date
2951 $modtmp = isOption($edit_options, 'F') === false ? 0 : 1;
2952 if (!$modtmp) {
2953 $s = text(oeFormatShortDate($currvalue));
2954 } else {
2955 $s = text(oeFormatDateTime($currvalue));
2957 $description = (isset($frow['description']) ? htmlspecialchars(xl_layout_label($frow['description']), ENT_QUOTES) : '');
2958 $age_asof_date = '';
2959 // Optional display of age or gestational age.
2960 $tmp = optionalAge($frow, $currvalue, $age_asof_date, $description);
2961 if ($tmp) {
2962 $s .= ' ' . $tmp;
2964 } elseif ($data_type == 10 || $data_type == 11) { // provider
2965 $urow = sqlQuery("SELECT fname, lname, specialty FROM users " .
2966 "WHERE id = ?", array($currvalue));
2967 $s = ucwords($urow['fname'] . " " . $urow['lname']);
2968 } elseif ($data_type == 12) { // pharmacy list
2969 $pres = get_pharmacies();
2970 while ($prow = sqlFetchArray($pres)) {
2971 $key = $prow['id'];
2972 if ($currvalue == $key) {
2973 $s .= $prow['name'] . ' ' . $prow['area_code'] . '-' .
2974 $prow['prefix'] . '-' . $prow['number'] . ' / ' .
2975 $prow['line1'] . ' / ' . $prow['city'];
2978 } elseif ($data_type == 14) { // address book
2979 $urow = sqlQuery("SELECT fname, lname, specialty FROM users " .
2980 "WHERE id = ?", array($currvalue));
2981 $uname = $urow['lname'];
2982 if ($urow['fname']) {
2983 $uname .= ", " . $urow['fname'];
2986 $s = $uname;
2987 } elseif ($data_type == 16) { // insurance company list
2988 $insprovs = getInsuranceProviders();
2989 foreach ($insprovs as $key => $ipname) {
2990 if ($currvalue == $key) {
2991 $s .= $ipname;
2994 } elseif ($data_type == 17) { // issue type
2995 foreach ($ISSUE_TYPES as $key => $value) {
2996 if ($currvalue == $key) {
2997 $s .= $value[1];
3000 } elseif ($data_type == 18) { // visit category
3001 $crow = sqlQuery(
3002 "SELECT pc_catid, pc_catname " .
3003 "FROM openemr_postcalendar_categories WHERE pc_catid = ?",
3004 array($currvalue)
3006 $s = $crow['pc_catname'];
3007 } elseif ($data_type == 21) { // a set of labeled checkboxes
3008 if (!$list_id) {
3009 $s .= $currvalue ? xlt('Yes') : xlt('No');
3010 } else {
3011 $avalue = explode('|', $currvalue);
3012 $lres = sqlStatement("SELECT * FROM list_options " .
3013 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
3014 $count = 0;
3015 while ($lrow = sqlFetchArray($lres)) {
3016 $option_id = $lrow['option_id'];
3017 if (in_array($option_id, $avalue)) {
3018 if ($count++) {
3019 $s .= "; ";
3021 $s .= xl_list_label($lrow['title']);
3025 } elseif ($data_type == 22) { // a set of labeled text input fields
3026 $tmp = explode('|', $currvalue);
3027 $avalue = array();
3028 foreach ($tmp as $value) {
3029 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
3030 $avalue[$matches[1]] = $matches[2];
3034 $lres = sqlStatement("SELECT * FROM list_options " .
3035 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
3036 while ($lrow = sqlFetchArray($lres)) {
3037 $option_id = $lrow['option_id'];
3038 if (empty($avalue[$option_id])) {
3039 continue;
3042 if ($s !== '') {
3043 $s .= '; ';
3046 $s .= xl_list_label($lrow['title']) . ': ';
3047 $s .= $avalue[$option_id];
3049 } elseif ($data_type == 23) { // A set of exam results; 3 radio buttons and a text field.
3050 // This shows abnormal results only.
3051 $tmp = explode('|', $currvalue);
3052 $avalue = array();
3053 foreach ($tmp as $value) {
3054 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
3055 $avalue[$matches[1]] = $matches[2];
3059 $lres = sqlStatement("SELECT * FROM list_options " .
3060 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
3061 while ($lrow = sqlFetchArray($lres)) {
3062 $option_id = $lrow['option_id'];
3063 $restype = substr($avalue[$option_id], 0, 1);
3064 $resnote = substr($avalue[$option_id], 2);
3065 if (empty($restype) && empty($resnote)) {
3066 continue;
3069 if ($restype != '2') {
3070 continue; // show abnormal results only
3073 if ($s !== '') {
3074 $s .= '; ';
3077 $s .= xl_list_label($lrow['title']);
3078 if (!empty($resnote)) {
3079 $s .= ': ' . $resnote;
3082 } elseif ($data_type == 24) { // the list of active allergies for the current patient
3083 $query = "SELECT title, comments FROM lists WHERE " .
3084 "pid = ? AND type = 'allergy' AND enddate IS NULL " .
3085 "ORDER BY begdate";
3086 $lres = sqlStatement($query, array($GLOBALS['pid']));
3087 $count = 0;
3088 while ($lrow = sqlFetchArray($lres)) {
3089 if ($count++) {
3090 $s .= "; ";
3093 $s .= $lrow['title'];
3094 if ($lrow['comments']) {
3095 $s .= ' (' . $lrow['comments'] . ')';
3098 } elseif ($data_type == 25) { // a set of labeled checkboxes, each with a text field:
3099 $tmp = explode('|', $currvalue);
3100 $avalue = array();
3101 foreach ($tmp as $value) {
3102 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
3103 $avalue[$matches[1]] = $matches[2];
3107 $lres = sqlStatement("SELECT * FROM list_options " .
3108 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
3109 while ($lrow = sqlFetchArray($lres)) {
3110 $option_id = $lrow['option_id'];
3111 $restype = substr($avalue[$option_id], 0, 1);
3112 $resnote = substr($avalue[$option_id], 2);
3113 if (empty($restype) && empty($resnote)) {
3114 continue;
3117 if ($s !== '') {
3118 $s .= '; ';
3121 $s .= xl_list_label($lrow['title']);
3122 $restype = $restype ? xl('Yes') : xl('No');
3123 $s .= $restype;
3124 if ($resnote) {
3125 $s .= ' ' . $resnote;
3128 } elseif ($data_type == 28 || $data_type == 32) { // special case for history of lifestyle status; 3 radio buttons and a date text field:
3129 // VicarePlus :: A selection list for smoking status.
3130 $tmp = explode('|', $currvalue);
3131 $resnote = count($tmp) > 0 ? $tmp[0] : '';
3132 $restype = count($tmp) > 1 ? $tmp[1] : '';
3133 $resdate = count($tmp) > 2 ? oeFormatShortDate($tmp[2]) : '';
3134 $reslist = count($tmp) > 3 ? $tmp[3] : '';
3135 $res = "";
3136 if ($restype == "current" . $field_id) {
3137 $res = xl('Current');
3140 if ($restype == "quit" . $field_id) {
3141 $res = xl('Quit');
3144 if ($restype == "never" . $field_id) {
3145 $res = xl('Never');
3148 if ($restype == "not_applicable" . $field_id) {
3149 $res = xl('N/A');
3152 if ($data_type == 28) {
3153 if (!empty($resnote)) {
3154 $s .= $resnote;
3156 } elseif ($data_type == 32) { // Tobacco field has a listbox, text box, date field and 3 radio buttons.
3157 if (!empty($reslist)) {
3158 $s .= generate_plaintext_field(array('data_type' => '1','list_id' => $list_id), $reslist);
3161 if (!empty($resnote)) {
3162 $s .= ' ' . $resnote;
3166 if (!empty($res)) {
3167 if ($s !== '') {
3168 $s .= ' ';
3171 $s .= xl('Status') . ' ' . $res;
3174 if ($restype == "quit" . $field_id) {
3175 if ($s !== '') {
3176 $s .= ' ';
3179 $s .= $resdate;
3181 } elseif ($data_type == 35) { // Facility, so facility can be listed in plain-text, as in patient finder column
3182 $facilityService = new FacilityService();
3183 $facility = $facilityService->getById($currvalue);
3184 $s = $facility['name'];
3185 } elseif ($data_type == 36 || $data_type == 33) { // Multi select. Supports backup lists
3186 $values_array = explode("|", $currvalue);
3188 $i = 0;
3189 foreach ($values_array as $value) {
3190 $lrow = sqlQuery("SELECT title FROM list_options " .
3191 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($list_id,$value));
3193 if ($lrow == 0 && !empty($backup_list)) {
3194 //use back up list
3195 $lrow = sqlQuery("SELECT title FROM list_options " .
3196 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($backup_list,$value));
3199 if ($i > 0) {
3200 $s = $s . ", " . xl_list_label($lrow['title']);
3201 } else {
3202 $s = xl_list_label($lrow['title']);
3205 $i++;
3208 // A set of lab test results; Gestation, 3 radio buttons, test value, notes field:
3209 } elseif ($data_type == 37) {
3210 $s .= genLabResults($frow, $currvalue, 3, '');
3211 } elseif ($data_type == 44 || $data_type == 45) {
3212 $values_array = explode("|", $currvalue);
3214 $i = 0;
3215 foreach ($values_array as $value) {
3216 if ($data_type == 44) {
3217 $lrow = sqlQuery("SELECT name as name FROM facility WHERE id = ?", array($value));
3219 if ($data_type == 45) {
3220 $lrow = sqlQuery("SELECT CONCAT(fname,' ',lname) as name FROM users WHERE id = ?", array($value));
3223 if ($i > 0) {
3224 $s = $s . ", " . $lrow['name'];
3225 } else {
3226 $s = $lrow['name'];
3229 $i++;
3232 // Patient selector field.
3233 } else if ($data_type == 51) {
3234 if (!empty($currvalue)) {
3235 $s .= getPatientDescription($currvalue);
3239 return $s;
3242 $CPR = 4; // cells per row of generic data
3243 $last_group = '';
3244 $cell_count = 0;
3245 $item_count = 0;
3247 function disp_end_cell()
3249 global $item_count, $cell_count;
3250 if ($item_count > 0) {
3251 echo "</td>";
3252 $item_count = 0;
3256 function disp_end_row()
3258 global $cell_count, $CPR;
3259 disp_end_cell();
3260 if ($cell_count > 0) {
3261 for (; $cell_count < $CPR; ++$cell_count) {
3262 echo "<td></td>";
3265 echo "</tr>\n";
3266 $cell_count = 0;
3270 function disp_end_group()
3272 global $last_group;
3273 if (strlen($last_group) > 0) {
3274 disp_end_row();
3278 // Bootstrapped versions of disp_end_* functions:
3280 function bs_disp_end_cell()
3282 global $item_count;
3283 if ($item_count > 0) {
3284 echo "</div>"; // end BS column
3285 $item_count = 0;
3289 function bs_disp_end_row()
3291 global $cell_count, $CPR, $BS_COL_CLASS;
3292 bs_disp_end_cell();
3293 if ($cell_count > 0 && $cell_count < $CPR) {
3294 // Create a cell occupying the remaining bootstrap columns.
3295 // BS columns will be less than 12 if $CPR is not 2, 3, 4, 6 or 12.
3296 $bs_cols_remaining = ($CPR - $cell_count) * intval(12 / $CPR);
3297 echo "<div class='$BS_COL_CLASS-$bs_cols_remaining'></div>";
3299 if ($cell_count > 0) {
3300 echo "</div><!-- End BS row -->\n";
3301 $cell_count = 0;
3305 function bs_disp_end_group()
3307 global $last_group;
3308 if (strlen($last_group) > 0) {
3309 bs_disp_end_row();
3315 function getPatientDescription($pid)
3317 $prow = sqlQuery("SELECT lname, fname FROM patient_data WHERE pid = ?", array($pid));
3318 if ($prow) {
3319 return $prow['lname'] . ", " . $prow['fname'] . " ($pid)";
3321 return xl('Unknown') . " ($pid)";
3324 // Accumulate action conditions into a JSON expression for the browser side.
3325 function accumActionConditions(&$frow, &$condition_str)
3327 $field_id = $frow['field_id'];
3328 $conditions = empty($frow['conditions']) ? array() : unserialize($frow['conditions'], ['allowed_classes' => false]);
3329 $action = 'skip';
3330 foreach ($conditions as $key => $condition) {
3331 if ($key === 'action') {
3332 // If specified this should be the first array item.
3333 if ($condition) {
3334 $action = $condition;
3336 continue;
3338 if (empty($condition['id'])) {
3339 continue;
3341 $andor = empty($condition['andor']) ? '' : $condition['andor'];
3342 if ($condition_str) {
3343 $condition_str .= ",\n";
3345 $condition_str .= "{" .
3346 "target:" . js_escape($field_id) . ", " .
3347 "action:" . js_escape($action) . ", " .
3348 "id:" . js_escape($condition['id']) . ", " .
3349 "itemid:" . js_escape($condition['itemid']) . ", " .
3350 "operator:" . js_escape($condition['operator']) . ", " .
3351 "value:" . js_escape($condition['value']) . ", ";
3352 if ($frow['data_type'] == 15 && strpos($frow['edit_options'], '2') !== false) {
3353 // For billing codes handle requirement to display its description.
3354 $tmp = explode('=', $action, 2);
3355 if (!empty($tmp[1])) {
3356 $condition_str .= "valdesc:" . js_escape(getCodeDescription($tmp[1])) . ", ";
3359 $condition_str .= "andor:" . js_escape($andor) . "}";
3363 function getCodeDescription($codestring, $defaulttype = 'ICD10')
3365 if ($codestring === '') {
3366 return '';
3368 list($ctype, $code) = explode(':', $codestring);
3369 if (empty($code)) {
3370 $code = $ctype;
3371 $ctype = $defaulttype;
3373 $desc = lookup_code_descriptions("$ctype:$code");
3374 if (!empty($desc)) {
3375 return $desc;
3376 } else {
3377 return $codestring;
3381 // This checks if the given field with the given value should have an action applied.
3382 // Originally the only action was skip, but now you can also set the field to a
3383 // specified value, or "skip and otherwise set a value".
3384 // It somewhat mirrors the checkSkipConditions function in options.js.php.
3385 // If you use this for multiple layouts in the same script, you should
3386 // clear $sk_layout_items before each layout.
3387 function isSkipped(&$frow, $currvalue)
3389 global $sk_layout_items;
3391 // Accumulate an array of the encountered fields and their values.
3392 // It is assumed that fields appear before they are tested by another field.
3393 // TBD: Bad assumption?
3394 $field_id = $frow['field_id'];
3395 if (!is_array($sk_layout_items)) {
3396 $sk_layout_items = array();
3398 $sk_layout_items[$field_id] = array('row' => $frow, 'value' => $currvalue);
3400 if (empty($frow['conditions'])) {
3401 return false;
3404 $skiprows = unserialize($frow['conditions'], ['allowed_classes' => false]);
3405 $prevandor = '';
3406 $prevcond = false;
3407 $datatype = $frow['data_type'];
3408 $action = 'skip'; // default action if none specified
3410 foreach ($skiprows as $key => $skiprow) {
3411 // id referenced field id
3412 // itemid referenced array key if applicable
3413 // operator "eq", "ne", "se" or "ns"
3414 // value if eq or ne, some string to compare with
3415 // andor "and", "or" or empty
3417 if ($key === 'action') {
3418 // Action value is a string. It can be "skip", or "value=" or "hsval=" followed by a value.
3419 $action = $skiprow;
3420 continue;
3423 if (empty($skiprow['id'])) {
3424 continue;
3427 $id = $skiprow['id'];
3428 if (!isset($sk_layout_items[$id])) {
3429 error_log("Function isSkipped() cannot find skip source field '" . errorLogEscape($id) . "'.");
3430 continue;
3432 $itemid = $skiprow['itemid'];
3433 $operator = $skiprow['operator'];
3434 $skipval = $skiprow['value'];
3435 $srcvalue = $sk_layout_items[$id]['value'];
3436 $src_datatype = $sk_layout_items[$id]['row']['data_type'];
3437 $src_list_id = $sk_layout_items[$id]['row']['list_id'];
3439 // Some data types use itemid and we have to dig for their value.
3440 if ($src_datatype == 21 && $src_list_id) { // array of checkboxes
3441 $tmp = explode('|', $srcvalue);
3442 $srcvalue = in_array($itemid, $tmp);
3443 } elseif ($src_datatype == 22 || $src_datatype == 23 || $src_datatype == 25) {
3444 $tmp = explode('|', $srcvalue);
3445 $srcvalue = '';
3446 foreach ($tmp as $tmp2) {
3447 if (strpos($tmp2, "$itemid:") === 0) {
3448 if ($datatype == 22) {
3449 $srcvalue = substr($tmp2, strlen($itemid) + 1);
3450 } else {
3451 $srcvalue = substr($tmp2, strlen($itemid) + 1, 1);
3457 // Compute the result of the test for this condition row.
3458 // PHP's looseness with variable type conversion helps us here.
3459 $condition = false;
3460 if ($operator == 'eq') {
3461 $condition = $srcvalue == $skipval;
3462 } elseif ($operator == 'ne') {
3463 $condition = $srcvalue != $skipval;
3464 } elseif ($operator == 'se') {
3465 $condition = $srcvalue == true;
3466 } elseif ($operator == 'ns') {
3467 $condition = $srcvalue != true;
3468 } else {
3469 error_log("Unknown skip operator '" . errorLogEscape($operator) . "' for field '" . errorLogEscape($field_id) . "'.");
3472 // Logic to accumulate multiple conditions for the same target.
3473 if ($prevandor == 'and') {
3474 $condition = $condition && $prevcond;
3475 } elseif ($prevandor == 'or') {
3476 $condition = $condition || $prevcond;
3478 $prevandor = $skiprow['andor'];
3479 $prevcond = $condition;
3482 if (substr($action, 0, 6) == 'hsval=') {
3483 return $prevcond ? 'skip' : ('value=' . substr($action, 6));
3485 return $prevcond ? $action : '';
3488 // Load array of names of the given layout and its groups.
3489 function getLayoutProperties($formtype, &$grparr, $sel = "grp_title")
3491 if ($sel != '*' && strpos($sel, 'grp_group_id') === false) {
3492 $sel = "grp_group_id, $sel";
3494 $gres = sqlStatement("SELECT $sel FROM layout_group_properties WHERE grp_form_id = ? " .
3495 "ORDER BY grp_group_id", array($formtype));
3496 while ($grow = sqlFetchArray($gres)) {
3497 // TBD: Remove this after grp_init_open column is implemented.
3498 if ($sel == '*' && !isset($grow['grp_init_open'])) {
3499 $tmprow = sqlQuery(
3500 "SELECT form_id FROM layout_options " .
3501 "WHERE form_id = ? AND group_id LIKE ? AND uor > 0 AND edit_options LIKE '%I%' " .
3502 "LIMIT 1",
3503 array($formtype, $grow['grp_group_id'] . '%')
3505 $grow['grp_init_open'] = !empty($tmprow['form_id']);
3507 $grparr[$grow['grp_group_id']] = $grow;
3511 function display_layout_rows($formtype, $result1, $result2 = '')
3513 global $item_count, $cell_count, $last_group, $CPR;
3515 if ('HIS' == $formtype) {
3516 $formtype .= '%'; // TBD: DEM also?
3518 $pres = sqlStatement(
3519 "SELECT grp_form_id, grp_seq, grp_title " .
3520 "FROM layout_group_properties " .
3521 "WHERE grp_form_id LIKE ? AND grp_group_id = '' " .
3522 "ORDER BY grp_seq, grp_title, grp_form_id",
3523 array("$formtype")
3525 while ($prow = sqlFetchArray($pres)) {
3526 $formtype = $prow['grp_form_id'];
3527 $last_group = '';
3528 $cell_count = 0;
3529 $item_count = 0;
3531 $grparr = array();
3532 getLayoutProperties($formtype, $grparr, '*');
3534 $TOPCPR = empty($grparr['']['grp_columns']) ? 4 : $grparr['']['grp_columns'];
3536 $fres = sqlStatement("SELECT * FROM layout_options " .
3537 "WHERE form_id = ? AND uor > 0 " .
3538 "ORDER BY group_id, seq", array($formtype));
3540 while ($frow = sqlFetchArray($fres)) {
3541 $this_group = $frow['group_id'];
3542 $titlecols = $frow['titlecols'];
3543 $datacols = $frow['datacols'];
3544 $data_type = $frow['data_type'];
3545 $field_id = $frow['field_id'];
3546 $list_id = $frow['list_id'];
3547 $currvalue = '';
3548 $jump_new_row = isOption($frow['edit_options'], 'J');
3549 $prepend_blank_row = isOption($frow['edit_options'], 'K');
3550 $portal_exclude = (!empty($_SESSION["patient_portal_onsite_two"]) && isOption($frow['edit_options'], 'EP')) ?? null;
3552 if (!empty($portal_exclude)) {
3553 continue;
3556 $CPR = empty($grparr[$this_group]['grp_columns']) ? $TOPCPR : $grparr[$this_group]['grp_columns'];
3558 if ($formtype == 'DEM') {
3559 if (strpos($field_id, 'em_') === 0) {
3560 // Skip employer related fields, if it's disabled.
3561 if ($GLOBALS['omit_employers']) {
3562 continue;
3565 $tmp = substr($field_id, 3);
3566 if (isset($result2[$tmp])) {
3567 $currvalue = $result2[$tmp];
3569 } else {
3570 if (isset($result1[$field_id])) {
3571 $currvalue = $result1[$field_id];
3574 } else {
3575 if (isset($result1[$field_id])) {
3576 $currvalue = $result1[$field_id];
3580 // Handle a data category (group) change.
3581 if (strcmp($this_group, $last_group) != 0) {
3582 $group_name = $grparr[$this_group]['grp_title'];
3583 // totally skip generating the employer category, if it's disabled.
3584 if ($group_name === 'Employer' && $GLOBALS['omit_employers']) {
3585 continue;
3588 disp_end_group();
3589 $last_group = $this_group;
3592 // filter out all the empty field data from the patient report.
3593 if (!empty($currvalue) && !($currvalue == '0000-00-00 00:00:00')) {
3594 // Handle starting of a new row.
3595 if (($titlecols > 0 && $cell_count >= $CPR) || $cell_count == 0 || $prepend_blank_row || $jump_new_row) {
3596 disp_end_row();
3597 if ($prepend_blank_row) {
3598 echo "<tr><td class='label' colspan='" . ($CPR + 1) . "'>&nbsp;</td></tr>\n";
3600 echo "<tr>";
3601 if ($group_name) {
3602 echo "<td class='groupname'>";
3603 echo text(xl_layout_label($group_name));
3604 $group_name = '';
3605 } else {
3606 echo "<td class='align-top'>&nbsp;";
3609 echo "</td>";
3612 if ($item_count == 0 && $titlecols == 0) {
3613 $titlecols = 1;
3616 // Handle starting of a new label cell.
3617 if ($titlecols > 0) {
3618 disp_end_cell();
3619 //echo "<td class='label_custom align-top' colspan='$titlecols'";
3620 $titlecols_esc = htmlspecialchars($titlecols, ENT_QUOTES);
3621 echo "<td class='label_custom' colspan='$titlecols_esc' ";
3622 //if ($cell_count == 2) echo " style='padding-left:10pt'";
3623 echo ">";
3624 $cell_count += $titlecols;
3627 ++$item_count;
3629 // Added 5-09 by BM - Translate label if applicable
3630 if ($frow['title']) {
3631 $tmp = xl_layout_label($frow['title']);
3632 echo text($tmp);
3633 // Append colon only if label does not end with punctuation.
3634 if (strpos('?!.,:-=', substr($tmp, -1, 1)) === false) {
3635 echo ':';
3637 } else {
3638 echo "&nbsp;";
3641 // Handle starting of a new data cell.
3642 if ($datacols > 0) {
3643 disp_end_cell();
3644 //echo "<td class='text data align-top' colspan='$datacols'";
3645 $datacols_esc = htmlspecialchars($datacols, ENT_QUOTES);
3646 echo "<td class='text data' colspan='$datacols_esc'";
3647 //if ($cell_count > 0) echo " style='padding-left:5pt'";
3648 echo ">";
3649 $cell_count += $datacols;
3652 ++$item_count;
3653 echo generate_display_field($frow, $currvalue);
3656 disp_end_group();
3657 } // End this layout, there may be more in the case of history.
3660 // This generates the tabs for a form.
3662 function display_layout_tabs($formtype, $result1, $result2 = '')
3664 global $item_count, $cell_count, $last_group, $CPR;
3666 if ('HIS' == $formtype) {
3667 $formtype .= '%'; // TBD: DEM also?
3669 $pres = sqlStatement(
3670 "SELECT grp_form_id, grp_seq, grp_title " .
3671 "FROM layout_group_properties " .
3672 "WHERE grp_form_id LIKE ? AND grp_group_id = '' " .
3673 "ORDER BY grp_seq, grp_title, grp_form_id",
3674 array("$formtype")
3676 $first = true;
3677 while ($prow = sqlFetchArray($pres)) {
3678 $formtype = $prow['grp_form_id'];
3679 $last_group = '';
3680 $cell_count = 0;
3681 $item_count = 0;
3683 $grparr = array();
3684 getLayoutProperties($formtype, $grparr);
3686 $fres = sqlStatement("SELECT distinct group_id FROM layout_options " .
3687 "WHERE form_id = ? AND uor > 0 " .
3688 "ORDER BY group_id", array($formtype));
3690 $prev_group = '';
3691 while ($frow = sqlFetchArray($fres)) {
3692 $this_group = $frow['group_id'];
3693 if (substr($prev_group, 0, 1) === substr($this_group, 0, 1)) {
3694 // Skip sub-groups, they will not start a new tab.
3695 continue;
3697 $prev_group = $this_group;
3698 $group_name = $grparr[$this_group]['grp_title'];
3699 if ($group_name === 'Employer' && $GLOBALS['omit_employers']) {
3700 continue;
3703 <li <?php echo $first ? 'class="current"' : '' ?>>
3704 <a href="#" id="header_tab_<?php echo attr($group_name); ?>">
3705 <?php echo text(xl_layout_label($group_name)); ?></a>
3706 </li>
3707 <?php
3708 $first = false;
3710 } // End this layout, there may be more in the case of history.
3713 // This generates the tab contents of the display version of a form.
3715 function display_layout_tabs_data($formtype, $result1, $result2 = '')
3717 global $item_count, $cell_count, $last_group, $CPR;
3719 if ('HIS' == $formtype) {
3720 $formtype .= '%'; // TBD: DEM also?
3722 $pres = sqlStatement(
3723 "SELECT grp_form_id, grp_seq, grp_title " .
3724 "FROM layout_group_properties " .
3725 "WHERE grp_form_id LIKE ? AND grp_group_id = '' " .
3726 "ORDER BY grp_seq, grp_title, grp_form_id",
3727 array("$formtype")
3729 $first = true;
3731 // This loops once per layout. Only Patient History can have multiple layouts.
3732 while ($prow = sqlFetchArray($pres)) {
3733 $formtype = $prow['grp_form_id'];
3734 $last_group = '';
3735 $cell_count = 0;
3736 $item_count = 0;
3738 $grparr = array();
3739 getLayoutProperties($formtype, $grparr, '*');
3741 $TOPCPR = empty($grparr['']['grp_columns']) ? 4 : $grparr['']['grp_columns'];
3743 // By selecting distinct group_id from layout_options we avoid empty groups.
3744 $fres = sqlStatement("SELECT distinct group_id FROM layout_options " .
3745 "WHERE form_id = ? AND uor > 0 " .
3746 "ORDER BY group_id", array($formtype));
3748 $prev_group = '';
3750 // This loops once per group within a given layout.
3751 while ($frow = sqlFetchArray($fres)) {
3752 $this_group = isset($frow['group_id']) ? $frow['group_id'] : "" ;
3754 if ($grparr[$this_group]['grp_columns'] === 'Employer' && $GLOBALS['omit_employers']) {
3755 continue;
3757 $CPR = empty($grparr[$this_group]['grp_columns']) ? $TOPCPR : $grparr[$this_group]['grp_columns'];
3758 $subtitle = empty($grparr[$this_group]['grp_subtitle']) ? '' : xl_layout_label($grparr[$this_group]['grp_subtitle']);
3760 $group_fields_query = sqlStatement(
3761 "SELECT * FROM layout_options " .
3762 "WHERE form_id = ? AND uor > 0 AND group_id = ? " .
3763 "ORDER BY seq",
3764 array($formtype, $this_group)
3767 if (substr($this_group, 0, 1) !== substr($prev_group, 0, 1)) {
3768 // Each new top level group gets its own tab div.
3769 if (!$first) {
3770 echo "</div>\n";
3772 echo "<div class='tab" . ($first ? ' current' : '') . "'>\n";
3774 echo "<table border='0' cellpadding='0'>\n";
3776 // This loops once per field within a given group.
3777 while ($group_fields = sqlFetchArray($group_fields_query)) {
3778 $titlecols = $group_fields['titlecols'];
3779 $datacols = $group_fields['datacols'];
3780 $data_type = $group_fields['data_type'];
3781 $field_id = $group_fields['field_id'];
3782 $list_id = $group_fields['list_id'];
3783 $currvalue = '';
3784 $edit_options = $group_fields['edit_options'];
3785 $jump_new_row = isOption($edit_options, 'J');
3786 $prepend_blank_row = isOption($edit_options, 'K');
3788 if ($formtype == 'DEM') {
3789 if (strpos($field_id, 'em_') === 0) {
3790 // Skip employer related fields, if it's disabled.
3791 if ($GLOBALS['omit_employers']) {
3792 continue;
3795 $tmp = substr($field_id, 3);
3796 if (isset($result2[$tmp])) {
3797 $currvalue = $result2[$tmp];
3799 } else {
3800 if (isset($result1[$field_id])) {
3801 $currvalue = $result1[$field_id];
3804 } else {
3805 if (isset($result1[$field_id])) {
3806 $currvalue = $result1[$field_id];
3810 // Skip this field if action conditions call for that.
3811 // Note this also accumulates info for subsequent skip tests.
3812 $skip_this_field = isSkipped($group_fields, $currvalue) == 'skip';
3814 // Skip this field if its do-not-print option is set.
3815 if (isOption($edit_options, 'X') !== false) {
3816 $skip_this_field = true;
3819 // Handle a data category (group) change.
3820 if (strcmp($this_group, $last_group) != 0) {
3821 $group_name = $grparr[$this_group]['grp_title'];
3822 // totally skip generating the employer category, if it's disabled.
3823 if ($group_name === 'Employer' && $GLOBALS['omit_employers']) {
3824 continue;
3826 $last_group = $this_group;
3829 // Handle starting of a new row.
3830 if (($titlecols > 0 && $cell_count >= $CPR) || $cell_count == 0 || $prepend_blank_row || $jump_new_row) {
3831 disp_end_row();
3832 if ($subtitle) {
3833 // Group subtitle exists and is not displayed yet.
3834 echo "<tr><td class='label' style='background-color: var(--gray300); padding: 4px' colspan='$CPR'>" . text($subtitle) . "</td></tr>\n";
3835 echo "<tr><td class='label' style='height: 5px' colspan='$CPR'></td></tr>\n";
3836 $subtitle = '';
3838 if ($prepend_blank_row) {
3839 echo "<tr><td class='label' style='font-size:25%' colspan='$CPR'>&nbsp;</td></tr>\n";
3841 echo "<tr>";
3844 if ($item_count == 0 && $titlecols == 0) {
3845 $titlecols = 1;
3848 // Handle starting of a new label cell.
3849 if ($titlecols > 0) {
3850 disp_end_cell();
3851 $titlecols_esc = htmlspecialchars($titlecols, ENT_QUOTES);
3852 $field_id_label = 'label_' . $group_fields['field_id'];
3853 echo "<td class='label_custom' colspan='$titlecols_esc' id='" . attr($field_id_label) . "'";
3854 echo ">";
3855 $cell_count += $titlecols;
3858 ++$item_count;
3860 if ($datacols == 0) {
3861 // Data will be in the same cell, so prevent wrapping to a new line.
3862 echo "<span class='text-nowrap mr-2'>";
3865 $field_id_label = 'label_' . $group_fields['field_id'];
3866 echo "<span id='" . attr($field_id_label) . "'>";
3867 if ($skip_this_field) {
3868 // No label because skipping
3869 } elseif ($group_fields['title']) {
3870 $tmp = xl_layout_label($group_fields['title']);
3871 echo text($tmp);
3872 // Append colon only if label does not end with punctuation.
3873 if (!str_contains('?!.,:-=', $tmp[strlen($tmp) - 1])) {
3874 echo ':';
3876 } else {
3877 echo "&nbsp;";
3879 echo "</span>";
3881 // Handle starting of a new data cell.
3882 if ($datacols > 0) {
3883 disp_end_cell();
3884 $datacols_esc = htmlspecialchars($datacols, ENT_QUOTES);
3885 $field_id = 'text_' . $group_fields['field_id'];
3886 echo "<td class='text data' colspan='$datacols_esc' id='" . attr($field_id) . "' data-value='" . attr($currvalue) . "'";
3887 if (!$skip_this_field && $data_type == 3) {
3888 // Textarea gets a light grey border.
3889 echo " style='border: 1px solid var(--gray400)'";
3891 echo ">";
3892 $cell_count += $datacols;
3893 } else {
3894 $field_id = 'text_' . $group_fields['field_id'];
3895 echo "<span id='" . attr($field_id) . "' style='display: none'>" . text($currvalue) . "</span>";
3898 ++$item_count;
3899 if (!$skip_this_field) {
3900 if ($item_count > 1) {
3901 echo "&nbsp;";
3903 echo generate_display_field($group_fields, $currvalue);
3905 if ($datacols == 0) {
3906 // End nowrap
3907 echo "</span> "; // space to allow wrap between spans
3909 } // end field
3911 disp_end_row();
3913 // End table for the group.
3914 echo "</table>\n";
3916 $prev_group = $this_group;
3917 $first = false;
3918 } // End this group.
3919 } // End this layout, there may be more in the case of history.
3921 if (!$first) {
3922 echo "</div>\n";
3926 // This generates the tab contents of the data entry version of a form.
3928 function display_layout_tabs_data_editable($formtype, $result1, $result2 = '')
3930 global $item_count, $cell_count, $last_group, $CPR, $condition_str, $BS_COL_CLASS;
3932 if ('HIS' == $formtype) {
3933 $formtype .= '%'; // TBD: DEM also?
3935 $pres = sqlStatement(
3936 "SELECT grp_form_id, grp_seq, grp_title " .
3937 "FROM layout_group_properties " .
3938 "WHERE grp_form_id LIKE ? AND grp_group_id = '' " .
3939 "ORDER BY grp_seq, grp_title, grp_form_id",
3940 array("$formtype")
3942 $first = true;
3943 $condition_str = '';
3945 // This loops once per layout. Only Patient History can have multiple layouts.
3946 while ($prow = sqlFetchArray($pres)) {
3947 $formtype = $prow['grp_form_id'];
3948 $last_group = '';
3949 $cell_count = 0;
3950 $item_count = 0;
3952 $grparr = array();
3953 getLayoutProperties($formtype, $grparr, '*');
3955 $TOPCPR = empty($grparr['']['grp_columns']) ? 4 : $grparr['']['grp_columns'];
3957 // Check the children of each top-level group to see if any of them are initially open.
3958 // If not, make the first such child initially open.
3959 foreach ($grparr as $tmprow1) {
3960 if (strlen($tmprow1['grp_group_id']) == 1) {
3961 $got_init_open = false;
3962 $keyfirst = false;
3963 foreach ($grparr as $key2 => $tmprow2) {
3964 if (substr($tmprow2['grp_group_id'], 0, 1) == $tmprow1['grp_group_id'] && strlen($tmprow2['grp_group_id']) == 2) {
3965 if (!$keyfirst) {
3966 $keyfirst = $key2;
3968 if ($tmprow2['grp_init_open']) {
3969 $got_init_open = true;
3973 if (!$got_init_open && $keyfirst) {
3974 $grparr[$keyfirst]['grp_init_open'] = 1;
3979 // Variables $gs_* are context for the group set in the current tab.
3980 $gs_display_style = 'block';
3981 // This string is the active group levels representing the current display state.
3982 // Each leading substring represents an instance of nesting.
3983 // As each new group is encountered, groups will be closed and opened as needed
3984 // until the display state matches the new group.
3985 $gs_group_levels = '';
3987 // By selecting distinct group_id from layout_options we avoid empty groups.
3988 $fres = sqlStatement("SELECT distinct group_id FROM layout_options " .
3989 "WHERE form_id = ? AND uor > 0 " .
3990 "ORDER BY group_id", array($formtype));
3992 // This loops once per group within a given layout.
3993 while ($frow = sqlFetchArray($fres)) {
3994 $this_group = $frow['group_id'];
3995 $group_name = $grparr[$this_group]['grp_title'];
3996 $group_name_esc = text($group_name);
3998 if ($grparr[$this_group]['grp_title'] === 'Employer' && $GLOBALS['omit_employers']) {
3999 continue;
4001 $CPR = empty($grparr[$this_group]['grp_columns']) ? $TOPCPR : $grparr[$this_group]['grp_columns'];
4002 $subtitle = empty($grparr[$this_group]['grp_subtitle']) ? '' : xl_layout_label($grparr[$this_group]['grp_subtitle']);
4004 $group_fields_query = sqlStatement("SELECT * FROM layout_options " .
4005 "WHERE form_id = ? AND uor > 0 AND group_id = ? " .
4006 "ORDER BY seq", array($formtype, $this_group));
4008 $gs_this_levels = $this_group;
4009 // Compute $gs_i as the number of initial matching levels.
4010 $gs_i = 0;
4011 $tmp = min(strlen($gs_this_levels), strlen($gs_group_levels));
4012 while ($gs_i < $tmp && $gs_this_levels[$gs_i] == $gs_group_levels[$gs_i]) {
4013 ++$gs_i;
4016 // Close any groups that we are done with.
4017 while (strlen($gs_group_levels) > $gs_i) {
4018 $gs_group_name = $grparr[$gs_group_levels]['grp_title'];
4019 if (strlen($gs_group_levels) > 1) {
4020 // No div for an empty sub-group name.
4021 if (strlen($gs_group_name)) {
4022 echo "</div>\n";
4024 } else {
4025 // This is the top group level so ending this tab and will start a new one.
4026 echo "</div>\n";
4028 $gs_group_levels = substr($gs_group_levels, 0, -1); // remove last character
4031 // If there are any new groups, open them.
4032 while ($gs_i < strlen($gs_this_levels)) {
4033 $gs_group_levels .= $gs_this_levels[$gs_i++];
4034 $gs_group_name = $grparr[substr($gs_group_levels, 0, $gs_i)]['grp_title'];
4035 $gs_init_open = $grparr[substr($gs_group_levels, 0, $gs_i)]['grp_init_open'];
4036 // Compute a short unique identifier for this group.
4037 $gs_group_seq = "grp-$formtype-$gs_group_levels";
4038 if ($gs_i <= 1) {
4039 // Top level group so new tab.
4040 echo "<div class='tab" . ($first ? ' current' : '') . "' id='tab_$group_name_esc'>\n";
4041 } else {
4042 // Not a new tab so start the group inline.
4043 // If group name is blank, no checkbox or div.
4044 if (strlen($gs_group_name)) {
4045 echo "<br /><span class='bold'><input type='checkbox' name='form_cb_" .
4046 attr($gs_group_seq) . "' value='1' " .
4047 "onclick='return divclick(this," . attr_js('div_' . $gs_group_seq) . ");'";
4048 $gs_display_style = $gs_init_open ? 'block' : 'none';
4049 if ($gs_display_style == 'block') {
4050 echo " checked";
4052 echo " /><b>" . text(xl_layout_label($gs_group_name)) . "</b></span>\n";
4053 echo "<div id='div_" . attr($gs_group_seq) .
4054 "' class='section' style='display:" . attr($gs_display_style) . ";'>\n";
4059 // Each group or subgroup has its own separate container.
4060 $gs_group_table_active = true;
4061 echo "<div class='container-fluid lbfdata'>\n";
4062 if ($subtitle) {
4063 // There is a group subtitle so show it.
4064 $bs_cols = $CPR * intval(12 / $CPR);
4065 echo "<div class='row mb-2'>";
4066 echo "<div class='<?php echo $BS_COL_CLASS; ?>-$bs_cols' style='color:#0000ff'>" . text($subtitle) . "</div>";
4067 echo "</div>\n";
4070 // This loops once per field within a given group.
4071 while ($group_fields = sqlFetchArray($group_fields_query)) {
4072 $titlecols = $group_fields['titlecols'];
4073 $datacols = $group_fields['datacols'];
4074 $data_type = $group_fields['data_type'];
4075 $field_id = $group_fields['field_id'];
4076 $list_id = $group_fields['list_id'];
4077 $backup_list = $group_fields['list_backup_id'];
4078 $currvalue = '';
4079 $action = 'skip';
4080 $jump_new_row = isOption($group_fields['edit_options'], 'J');
4081 $prepend_blank_row = isOption($group_fields['edit_options'], 'K');
4083 // Accumulate action conditions into a JSON expression for the browser side.
4084 accumActionConditions($group_fields, $condition_str);
4086 if ($formtype == 'DEM') {
4087 if (strpos($field_id, 'em_') === 0) {
4088 // Skip employer related fields, if it's disabled.
4089 if ($GLOBALS['omit_employers']) {
4090 continue;
4093 $tmp = substr($field_id, 3);
4094 if (isset($result2[$tmp])) {
4095 $currvalue = $result2[$tmp];
4097 } else {
4098 if (isset($result1[$field_id])) {
4099 $currvalue = $result1[$field_id];
4102 } else {
4103 if (isset($result1[$field_id])) {
4104 $currvalue = $result1[$field_id];
4108 // Handle a data category (group) change.
4109 if (strcmp($this_group, $last_group) != 0) {
4110 // totally skip generating the employer category, if it's disabled.
4111 if ($group_name === 'Employer' && $GLOBALS['omit_employers']) {
4112 continue;
4115 $last_group = $this_group;
4118 // Handle starting of a new row.
4119 if (($titlecols > 0 && $cell_count >= $CPR) || $cell_count == 0 || $prepend_blank_row || $jump_new_row) {
4120 bs_disp_end_row();
4121 $bs_cols = $CPR * intval(12 / $CPR);
4122 if ($subtitle) {
4123 // Group subtitle exists and is not displayed yet.
4124 echo "<div class='form-row mb-2'>";
4125 echo "<div class='<?php echo $BS_COL_CLASS; ?>-$bs_cols p-2 label' style='background-color: var(--gray300)'>" . text($subtitle) . "</div>";
4126 echo "</div>\n";
4127 $subtitle = '';
4129 if ($prepend_blank_row) {
4130 echo "<div class='form-row'>";
4131 echo "<div class='<?php echo $BS_COL_CLASS; ?>-$bs_cols label' style='font-size:25%'>&nbsp;</div>";
4132 echo "</div>\n";
4134 echo "<div class='form-row'>";
4137 if ($item_count == 0 && $titlecols == 0) {
4138 $titlecols = 1;
4141 // Handle starting of a new label cell.
4142 if ($titlecols > 0) {
4143 bs_disp_end_cell();
4144 $bs_cols = $titlecols * intval(12 / $CPR);
4145 echo "<div class='$BS_COL_CLASS-$bs_cols pt-1 label_custom' ";
4146 echo "id='label_id_" . attr($field_id) . "'";
4147 echo ">";
4148 $cell_count += $titlecols;
4151 // $item_count is the number of title and data items in the current cell.
4152 ++$item_count;
4154 if ($datacols == 0) {
4155 // Data will be in the same cell, so prevent wrapping to a new line.
4156 echo "<span class='text-nowrap mr-2'>";
4159 if ($group_fields['title']) {
4160 $tmp = xl_layout_label($group_fields['title']);
4161 echo text($tmp);
4162 // Append colon only if label does not end with punctuation.
4163 if (strpos('?!.,:-=', substr($tmp, -1, 1)) === false) {
4164 echo ':';
4166 } else {
4167 echo "&nbsp;";
4170 // Handle starting of a new data cell.
4171 if ($datacols > 0) {
4172 bs_disp_end_cell();
4173 $field_id = 'text_' . $group_fields['field_id'];
4174 $bs_cols = $datacols * intval(12 / $CPR);
4175 echo "<div class='$BS_COL_CLASS-$bs_cols'";
4176 echo " id='value_id_" . attr($field_id) . "'";
4177 echo ">";
4178 $cell_count += $datacols;
4181 ++$item_count;
4182 if ($item_count > 1) {
4183 echo "&nbsp;";
4185 // 'smallform' can be used to add arbitrary CSS classes. Note the leading space.
4186 $group_fields['smallform'] = ' form-control-sm mb-1 mw-100';
4187 echo generate_form_field($group_fields, $currvalue);
4188 if ($datacols == 0) {
4189 // End nowrap
4190 echo "</span> "; // space to allow wrap between spans
4192 } // End of fields for this group.
4194 bs_disp_end_row(); // TBD: Does this belong here?
4195 echo "</div>\n"; // end container-fluid
4196 $first = false;
4197 } // End this group.
4199 // Close any groups still open.
4200 while (strlen($gs_group_levels) > 0) {
4201 $gs_group_name = $grparr[$gs_group_levels]['grp_title'];
4202 if (strlen($gs_group_levels) > 1) {
4203 // No div for an empty sub-group name.
4204 if (strlen($gs_group_name)) {
4205 echo "</div>\n";
4207 } else {
4208 // This is the top group level so ending this tab and will start a new one.
4209 echo "</div>\n";
4211 $gs_group_levels = substr($gs_group_levels, 0, -1); // remove last character
4213 } // End this layout, there may be more in the case of history.
4216 // From the currently posted HTML form, this gets the value of the
4217 // field corresponding to the provided layout_options table row.
4219 function get_layout_form_value($frow, $prefix = 'form_')
4221 $maxlength = empty($frow['max_length']) ? 0 : intval($frow['max_length']);
4222 $data_type = $frow['data_type'];
4223 $field_id = $frow['field_id'];
4224 $value = '';
4225 if (isset($_POST["$prefix$field_id"])) {
4226 if ($data_type == 4) {
4227 $modtmp = isOption($frow['edit_options'], 'F') === false ? 0 : 1;
4228 if (!$modtmp) {
4229 $value = DateToYYYYMMDD($_POST["$prefix$field_id"]);
4230 } else {
4231 $value = DateTimeToYYYYMMDDHHMMSS($_POST["$prefix$field_id"]);
4233 } elseif ($data_type == 21) {
4234 if (!$frow['list_id']) {
4235 if (!empty($_POST["form_$field_id"])) {
4236 $value = xlt('Yes');
4238 } else {
4239 // $_POST["$prefix$field_id"] is an array of checkboxes and its keys
4240 // must be concatenated into a |-separated string.
4241 foreach ($_POST["$prefix$field_id"] as $key => $val) {
4242 if (strlen($value)) {
4243 $value .= '|';
4245 $value .= $key;
4248 } elseif ($data_type == 22) {
4249 // $_POST["$prefix$field_id"] is an array of text fields to be imploded
4250 // into "key:value|key:value|...".
4251 foreach ($_POST["$prefix$field_id"] as $key => $val) {
4252 $val = str_replace('|', ' ', $val);
4253 if (strlen($value)) {
4254 $value .= '|';
4257 $value .= "$key:$val";
4259 } elseif ($data_type == 23) {
4260 // $_POST["$prefix$field_id"] is an array of text fields with companion
4261 // radio buttons to be imploded into "key:n:notes|key:n:notes|...".
4262 foreach ($_POST["$prefix$field_id"] as $key => $val) {
4263 $restype = $_POST["radio_{$field_id}"][$key] ?? null;
4264 if (empty($restype)) {
4265 $restype = '0';
4268 $val = str_replace('|', ' ', $val);
4269 if (strlen($value)) {
4270 $value .= '|';
4273 $value .= "$key:$restype:$val";
4275 } elseif ($data_type == 25) {
4276 // $_POST["$prefix$field_id"] is an array of text fields with companion
4277 // checkboxes to be imploded into "key:n:notes|key:n:notes|...".
4278 foreach ($_POST["$prefix$field_id"] as $key => $val) {
4279 $restype = empty($_POST["check_{$field_id}"][$key]) ? '0' : '1';
4280 $val = str_replace('|', ' ', $val);
4281 if (strlen($value)) {
4282 $value .= '|';
4285 $value .= "$key:$restype:$val";
4287 } elseif ($data_type == 28 || $data_type == 32) {
4288 // $_POST["$prefix$field_id"] is an date text fields with companion
4289 // radio buttons to be imploded into "notes|type|date".
4290 $restype = $_POST["radio_{$field_id}"] ?? '';
4291 if (empty($restype)) {
4292 $restype = '0';
4295 $resdate = DateToYYYYMMDD(str_replace('|', ' ', $_POST["date_$field_id"]));
4296 $resnote = str_replace('|', ' ', $_POST["$prefix$field_id"]);
4297 if ($data_type == 32) {
4298 //VicarePlus :: Smoking status data is imploded into "note|type|date|list".
4299 $reslist = str_replace('|', ' ', $_POST["$prefix$field_id"]);
4300 $res_text_note = str_replace('|', ' ', $_POST["{$prefix}text_$field_id"]);
4301 $value = "$res_text_note|$restype|$resdate|$reslist";
4302 } else {
4303 $value = "$resnote|$restype|$resdate";
4305 } elseif ($data_type == 37) {
4306 // $_POST["form_$field_id"] is an array of arrays of 3 text fields with companion
4307 // radio button set to be encoded as json.
4308 $tmparr = array();
4309 foreach ($_POST["form_$field_id"] as $key => $valarr) {
4310 // Each $key here is a list item ID. $valarr has 3 text field values keyed on 0, 2 and 3.
4311 $tmparr[$key][0] = $valarr['0'];
4312 $tmparr[$key][1] = $_POST["radio_{$field_id}"][$key];
4313 $tmparr[$key][2] = $valarr['2'];
4314 $tmparr[$key][3] = $valarr['3'];
4316 $value .= json_encode($tmparr);
4317 } elseif ($data_type == 36 || $data_type == 44 || $data_type == 45 || $data_type == 33) {
4318 $value_array = $_POST["form_$field_id"];
4319 $i = 0;
4320 foreach ($value_array as $key => $valueofkey) {
4321 if ($i == 0) {
4322 $value = $valueofkey;
4323 } else {
4324 $value = $value . "|" . $valueofkey;
4327 $i++;
4329 } elseif ($data_type == 46) {
4330 $reslist = trim($_POST["$prefix$field_id"]);
4331 if (preg_match('/^comment_/', $reslist)) {
4332 $res_comment = str_replace('|', ' ', $_POST["{$prefix}text_$field_id"]);
4333 $value = $reslist . "|" . $res_comment;
4334 } else {
4335 $value = $_POST["$prefix$field_id"];
4337 } elseif ($data_type == 52) {
4338 $value_array = $_POST["form_$field_id"];
4339 $i = 0;
4340 foreach ($value_array as $key => $valueofkey) {
4341 if ($i == 0) {
4342 $value = $valueofkey;
4343 } else {
4344 $value = $value . "|" . $valueofkey;
4347 $i++;
4349 } else {
4350 $value = $_POST["$prefix$field_id"];
4354 // Better to die than to silently truncate data!
4355 if ($maxlength && $maxlength != 0 && strlen(trim($value)) > $maxlength && !$frow['list_id']) {
4356 die(htmlspecialchars(xl('ERROR: Field') . " '$field_id' " . xl('is too long'), ENT_NOQUOTES) .
4357 ":<br />&nbsp;<br />" . htmlspecialchars($value, ENT_NOQUOTES));
4360 return trim($value);
4363 // Generate JavaScript validation logic for the required fields.
4365 function generate_layout_validation($form_id)
4367 if ('HIS' == $form_id) {
4368 $form_id .= '%'; // TBD: DEM also?
4370 $pres = sqlStatement(
4371 "SELECT grp_form_id, grp_seq, grp_title " .
4372 "FROM layout_group_properties " .
4373 "WHERE grp_form_id LIKE ? AND grp_group_id = '' " .
4374 "ORDER BY grp_seq, grp_title, grp_form_id",
4375 array("$form_id")
4377 while ($prow = sqlFetchArray($pres)) {
4378 $form_id = $prow['grp_form_id'];
4380 $fres = sqlStatement("SELECT * FROM layout_options " .
4381 "WHERE form_id = ? AND uor > 0 AND field_id != '' " .
4382 "ORDER BY group_id, seq", array($form_id));
4384 while ($frow = sqlFetchArray($fres)) {
4385 $data_type = $frow['data_type'];
4386 $field_id = $frow['field_id'];
4387 $fldtitle = $frow['title'];
4388 if (!$fldtitle) {
4389 $fldtitle = $frow['description'];
4392 $fldname = attr("form_$field_id");
4394 if ($data_type == 40) {
4395 $fldid = "form_" . $field_id;
4396 // Move canvas image data to its hidden form field so the server will get it.
4397 echo
4398 " var canfld = f[" . js_escape($fldid) . "];\n" .
4399 " if (canfld) canfld.value = lbfCanvasGetData(" . js_escape($fldid) . ");\n";
4400 continue;
4402 if ($data_type == 41 || $data_type == 42) {
4403 $fldid = "form_" . $field_id;
4404 // Move canvas image data to its hidden form field so the server will get it.
4405 echo " lbfSetSignature(" . js_escape($fldid) . ");\n";
4406 continue;
4408 if ($frow['uor'] < 2) {
4409 continue;
4412 echo " if (f.$fldname && !f.$fldname.disabled) {\n";
4413 switch ($data_type) {
4414 case 1:
4415 case 11:
4416 case 12:
4417 case 13:
4418 case 14:
4419 case 26:
4420 echo
4421 " if (f.$fldname.selectedIndex <= 0) {\n" .
4422 " alert(" . xlj('Please choose a value for') . " + " .
4423 "\":\\n\" + " . js_escape(xl_layout_label($fldtitle)) . ");\n" .
4424 " if (f.$fldname.focus) f.$fldname.focus();\n" .
4425 " return false;\n" .
4426 " }\n";
4427 break;
4428 case 33:
4429 echo
4430 " if (f.$fldname.selectedIndex <= 0) {\n" .
4431 " if (f.$fldname.focus) f.$fldname.focus();\n" .
4432 " errMsgs[errMsgs.length] = " . js_escape(xl_layout_label($fldtitle)) . "; \n" .
4433 " }\n";
4434 break;
4435 case 27: // radio buttons
4436 echo
4437 " var i = 0;\n" .
4438 " for (; i < f.$fldname.length; ++i) if (f.{$fldname}[i].checked) break;\n" .
4439 " if (i >= f.$fldname.length) {\n" .
4440 " alert(" . xlj('Please choose a value for') . " + " .
4441 "\":\\n\" + " . js_escape(xl_layout_label($fldtitle)) . ");\n" .
4442 " return false;\n" .
4443 " }\n";
4444 break;
4445 case 2:
4446 case 3:
4447 case 4:
4448 case 15:
4449 echo
4450 " if (trimlen(f.$fldname.value) == 0) {\n" .
4451 " if (f.$fldname.focus) f.$fldname.focus();\n" .
4452 " $('#" . $fldname . "').parents('div.tab').each( function(){ var tabHeader = $('#header_' + $(this).attr('id') ); tabHeader.css('color','var(--danger)'); } ); " .
4453 " $('#" . $fldname . "').attr('style','background: var(--danger)'); \n" .
4454 " errMsgs[errMsgs.length] = " . js_escape(xl_layout_label($fldtitle)) . "; \n" .
4455 " } else { " .
4456 " $('#" . $fldname . "').attr('style',''); " .
4457 " $('#" . $fldname . "').parents('div.tab').each( function(){ var tabHeader = $('#header_' + $(this).attr('id') ); tabHeader.css('color',''); } ); " .
4458 " } \n";
4459 break;
4460 case 36: // multi select
4461 echo
4462 " var multi_select=f['$fldname" . "[]']; \n " .
4463 " var multi_choice_made=false; \n" .
4464 " for (var options_index=0; options_index < multi_select.length; options_index++) { " .
4465 " multi_choice_made=multi_choice_made || multi_select.options[options_index].selected; \n" .
4466 " } \n" .
4467 " if(!multi_choice_made)
4468 errMsgs[errMsgs.length] = " . js_escape(xl_layout_label($fldtitle)) . "; \n" .
4470 break;
4472 echo " }\n";
4474 } // End this layout, there may be more in the case of history.
4478 * DROPDOWN FOR FACILITIES
4480 * build a dropdown with all facilities
4482 * @param string $selected - name of the currently selected facility
4483 * use '0' for "unspecified facility"
4484 * use '' for "All facilities" (the default)
4485 * @param string $name - the name/id for select form (defaults to "form_facility")
4486 * @param boolean $allow_unspecified - include an option for "unspecified" facility
4487 * defaults to true
4488 * @return void - just echo the html encoded string
4490 * Note: This should become a data-type at some point, according to Brady
4492 function dropdown_facility(
4493 $selected = '',
4494 $name = 'form_facility',
4495 $allow_unspecified = true,
4496 $allow_allfacilities = true,
4497 $disabled = '',
4498 $onchange = '',
4499 $multiple = false,
4500 $class = ''
4502 global $facilityService;
4504 $have_selected = false;
4505 $fres = $facilityService->getAllFacility();
4506 $id = $name;
4508 if ($multiple) {
4509 $name = $name . "[]";
4511 echo " <select class='form-control$class";
4512 if ($multiple) {
4513 echo " select-dropdown";
4515 echo "' name='" . attr($name) . "' id='" . attr($id) . "'";
4516 if ($onchange) {
4517 echo " onchange='$onchange'";
4520 if ($multiple) {
4521 echo " multiple='multiple'";
4524 echo " $disabled>\n";
4526 if ($allow_allfacilities) {
4527 $option_value = '';
4528 $option_selected_attr = '';
4529 if ($selected == '') {
4530 $option_selected_attr = ' selected="selected"';
4531 $have_selected = true;
4534 $option_content = '-- ' . xl('All Facilities') . ' --';
4535 echo " <option value='" . attr($option_value) . "' $option_selected_attr>" . text($option_content) . "</option>\n";
4536 } elseif ($allow_unspecified) {
4537 $option_value = '0';
4538 $option_selected_attr = '';
4539 if ($selected == '0') {
4540 $option_selected_attr = ' selected="selected"';
4541 $have_selected = true;
4544 $option_content = '-- ' . xl('Unspecified') . ' --';
4545 echo " <option value='" . attr($option_value) . "' $option_selected_attr>" . text($option_content) . "</option>\n";
4548 foreach ($fres as $frow) {
4549 $facility_id = $frow['id'];
4550 $option_value = $facility_id;
4551 $option_selected_attr = '';
4552 if ($multiple) {
4553 $selectedValues = explode("|", $selected);
4555 if (in_array($facility_id, $selectedValues)) {
4556 $option_selected_attr = ' selected="selected"';
4557 $have_selected = true;
4559 } else {
4560 if ($selected == $facility_id) {
4561 $option_selected_attr = ' selected="selected"';
4562 $have_selected = true;
4566 $option_content = $frow['name'];
4567 echo " <option value='" . attr($option_value) . "' $option_selected_attr>" . text($option_content) . "</option>\n";
4570 if ($allow_unspecified && $allow_allfacilities) {
4571 $option_value = '0';
4572 $option_selected_attr = '';
4573 if ($selected == '0') {
4574 $option_selected_attr = ' selected="selected"';
4575 $have_selected = true;
4578 $option_content = '-- ' . xl('Unspecified') . ' --';
4579 echo " <option value='" . attr($option_value) . "' $option_selected_attr>" . text($option_content) . "</option>\n";
4582 if (!$have_selected && !$multiple) {
4583 $option_value = $selected;
4584 $option_label = '(' . xl('Do not change') . ')';
4585 $option_content = xl('Missing or Invalid');
4586 echo " <option value='" . attr($option_value) . "' label='" . attr($option_label) . "' selected='selected'>" . text($option_content) . "</option>\n";
4589 echo " </select>\n";
4593 * Expand Collapse Widget
4594 * This forms the header and functionality component of the widget. The information that is displayed
4595 * then follows this function followed by a closing div tag
4597 * @var $title is the title of the section (already translated)
4598 * @var $label is identifier used in the tag id's and sql columns
4599 * @var $buttonLabel is the button label text (already translated)
4600 * @var $buttonLink is the button link information
4601 * @var $buttonClass is any additional needed class elements for the button tag
4602 * @var $linkMethod is the button link method ('javascript' vs 'html')
4603 * @var $bodyClass is to set class(es) of the body
4604 * @var $auth is a flag to decide whether to show the button
4605 * @var $fixedWidth is to flag whether width is fixed
4606 * @var $forceExpandAlways is a flag to force the widget to always be expanded
4608 * @todo Convert to a modern layotu
4610 function expand_collapse_widget($title, $label, $buttonLabel, $buttonLink, $buttonClass, $linkMethod, $bodyClass, $auth, $fixedWidth, $forceExpandAlways = false)
4612 if ($fixedWidth) {
4613 echo "<div class='section-header'>";
4614 } else {
4615 echo "<div class='section-header-dynamic'>";
4618 echo "<table><tr>";
4619 if ($auth) {
4620 // show button, since authorized
4621 // first prepare class string
4622 if ($buttonClass) {
4623 $class_string = "btn btn-primary btn-sm " . $buttonClass;
4624 } else {
4625 $class_string = "btn btn-primary btn-sm";
4628 // next, create the link
4629 if ($linkMethod == "javascript") {
4630 echo "<td><a class='" . attr($class_string) . "' href='javascript:;' onclick='" . $buttonLink . "'";
4631 } else {
4632 echo "<td><a class='" . attr($class_string) . "' href='" . $buttonLink . "'";
4633 if (!isset($_SESSION['patient_portal_onsite_two'])) {
4634 // prevent an error from occuring when calling the function from the patient portal
4635 echo " onclick='top.restoreSession()'";
4639 echo "><span>" .
4640 text($buttonLabel) . "</span></a></td>";
4643 if ($forceExpandAlways) {
4644 // Special case to force the widget to always be expanded
4645 echo "<td><span class='text font-weight-bold'>" . text($title) . "</span>";
4646 $indicatorTag = "style='display: none'";
4649 $indicatorTag = isset($indicatorTag) ? $indicatorTag : "";
4650 echo "<td><a " . $indicatorTag . " href='javascript:;' class='small' onclick='toggleIndicator(this," .
4651 attr_js($label . "_ps_expand") . ")'><span class='text font-weight-bold'>";
4652 echo text($title) . "</span>";
4654 if (isset($_SESSION['patient_portal_onsite_two'])) {
4655 // collapse all entries in the patient portal
4656 $text = xl('expand');
4657 } elseif (getUserSetting($label . "_ps_expand")) {
4658 $text = xl('collapse');
4659 } else {
4660 $text = xl('expand');
4663 echo " (<span class='indicator'>" . text($text) .
4664 "</span>)</a></td>";
4665 echo "</tr></table>";
4666 echo "</div>";
4667 if ($forceExpandAlways) {
4668 // Special case to force the widget to always be expanded
4669 $styling = "";
4670 } elseif (isset($_SESSION['patient_portal_onsite_two'])) {
4671 // collapse all entries in the patient portal
4672 $styling = "style='display: none'";
4673 } elseif (getUserSetting($label . "_ps_expand")) {
4674 $styling = "";
4675 } else {
4676 $styling = "style='display: none'";
4679 if ($bodyClass) {
4680 $styling .= " class='" . attr($bodyClass) . "'";
4683 //next, create the first div tag to hold the information
4684 // note the code that calls this function will then place the ending div tag after the data
4685 echo "<div id='" . attr($label) . "_ps_expand' " . $styling . ">";
4688 //billing_facility fuction will give the dropdown list which contain billing faciliies.
4689 function billing_facility($name, $select)
4691 global $facilityService;
4693 $fres = $facilityService->getAllBillingLocations();
4694 echo " <select id='" . htmlspecialchars($name, ENT_QUOTES) . "' class='form-control' name='" . htmlspecialchars($name, ENT_QUOTES) . "'>";
4695 foreach ($fres as $facrow) {
4696 $selected = ( $facrow['id'] == $select ) ? 'selected="selected"' : '' ;
4697 echo "<option value=" . htmlspecialchars($facrow['id'], ENT_QUOTES) . " $selected>" . htmlspecialchars($facrow['name'], ENT_QUOTES) . "</option>";
4700 echo "</select>";
4703 // Generic function to get the translated title value for a particular list option.
4705 function getListItemTitle($list, $option)
4707 $row = sqlQuery("SELECT title FROM list_options WHERE " .
4708 "list_id = ? AND option_id = ? AND activity = 1", array($list, $option));
4709 if (empty($row['title'])) {
4710 return $option;
4713 return xl_list_label($row['title']);
4716 //function to get the translated title value in Patient Transactions
4717 function getLayoutTitle($list, $option)
4719 $row = sqlQuery("SELECT grp_title FROM layout_group_properties " .
4720 "WHERE grp_mapping = ? AND grp_form_id = ? ", array($list, $option));
4722 if (empty($row['grp_title'])) {
4723 return $option;
4725 return xl_list_label($row['grp_title']);
4727 //Added on 5-jun-2k14 (regarding get the smoking code descriptions)
4728 function getSmokeCodes()
4730 $smoking_codes_arr = array();
4731 $smoking_codes = sqlStatement("SELECT option_id,codes FROM list_options WHERE list_id='smoking_status' AND activity = 1");
4732 while ($codes_row = sqlFetchArray($smoking_codes)) {
4733 $smoking_codes_arr[$codes_row['option_id']] = $codes_row['codes'];
4736 return $smoking_codes_arr;
4739 // Get the current value for a layout based form field.
4740 // Depending on options this might come from lbf_data, patient_data,
4741 // form_encounter, shared_attributes or elsewhere.
4742 // Returns FALSE if the field ID is invalid (layout error).
4744 function lbf_current_value($frow, $formid, $encounter)
4746 global $pid;
4747 $formname = $frow['form_id'];
4748 $field_id = $frow['field_id'];
4749 $source = $frow['source'];
4750 $currvalue = '';
4751 $deffname = $formname . '_default_' . $field_id;
4752 if ($source == 'D' || $source == 'H') {
4753 // Get from patient_data, employer_data or history_data.
4754 if ($source == 'H') {
4755 $table = 'history_data';
4756 $orderby = 'ORDER BY date DESC LIMIT 1';
4757 } elseif (strpos($field_id, 'em_') === 0) {
4758 $field_id = substr($field_id, 3);
4759 $table = 'employer_data';
4760 $orderby = 'ORDER BY date DESC LIMIT 1';
4761 } else {
4762 $table = 'patient_data';
4763 $orderby = '';
4766 // It is an error if the field does not exist, but don't crash.
4767 $tmp = sqlQuery("SHOW COLUMNS FROM " . escape_table_name($table) . " WHERE Field = ?", array($field_id));
4768 if (empty($tmp)) {
4769 return '*?*';
4772 $pdrow = sqlQuery("SELECT `$field_id` AS field_value FROM " . escape_table_name($table) . " WHERE pid = ? $orderby", array($pid));
4773 if (isset($pdrow)) {
4774 $currvalue = $pdrow['field_value'];
4776 } elseif ($source == 'E') {
4777 $sarow = false;
4778 if ($encounter) {
4779 // Get value from shared_attributes of the current encounter.
4780 $sarow = sqlQuery(
4781 "SELECT field_value FROM shared_attributes WHERE " .
4782 "pid = ? AND encounter = ? AND field_id = ?",
4783 array($pid, $encounter, $field_id)
4785 if (!empty($sarow)) {
4786 $currvalue = $sarow['field_value'];
4788 } elseif ($formid) {
4789 // Get from shared_attributes of the encounter that this form is linked to.
4790 // Note the importance of having an index on forms.form_id.
4791 $sarow = sqlQuery(
4792 "SELECT sa.field_value " .
4793 "FROM forms AS f, shared_attributes AS sa WHERE " .
4794 "f.form_id = ? AND f.formdir = ? AND f.deleted = 0 AND " .
4795 "sa.pid = f.pid AND sa.encounter = f.encounter AND sa.field_id = ?",
4796 array($formid, $formname, $field_id)
4798 if (!empty($sarow)) {
4799 $currvalue = $sarow['field_value'];
4801 } else {
4802 // New form and encounter not available, this should not happen.
4804 if (empty($sarow) && !$formid) {
4805 // New form, see if there is a custom default from a plugin.
4806 if (function_exists($deffname)) {
4807 $currvalue = call_user_func($deffname);
4810 } elseif ($source == 'V') {
4811 if ($encounter) {
4812 // Get value from the current encounter's form_encounter.
4813 $ferow = sqlQuery(
4814 "SELECT * FROM form_encounter WHERE " .
4815 "pid = ? AND encounter = ?",
4816 array($pid, $encounter)
4818 if (isset($ferow[$field_id])) {
4819 $currvalue = $ferow[$field_id];
4821 } elseif ($formid) {
4822 // Get value from the form_encounter that this form is linked to.
4823 $ferow = sqlQuery(
4824 "SELECT fe.* " .
4825 "FROM forms AS f, form_encounter AS fe WHERE " .
4826 "f.form_id = ? AND f.formdir = ? AND f.deleted = 0 AND " .
4827 "fe.pid = f.pid AND fe.encounter = f.encounter",
4828 array($formid, $formname)
4830 if (isset($ferow[$field_id])) {
4831 $currvalue = $ferow[$field_id];
4833 } else {
4834 // New form and encounter not available, this should not happen.
4836 } elseif ($formid) {
4837 // This is a normal form field.
4838 $ldrow = sqlQuery("SELECT field_value FROM lbf_data WHERE " .
4839 "form_id = ? AND field_id = ?", array($formid, $field_id));
4840 if (!empty($ldrow)) {
4841 $currvalue = $ldrow['field_value'];
4843 } else {
4844 // New form, see if there is a custom default from a plugin.
4845 if (function_exists($deffname)) {
4846 $currvalue = call_user_func($deffname);
4850 return $currvalue;
4853 function signer_head()
4855 return <<<EOD
4856 <link href="{$GLOBALS['web_root']}/portal/sign/css/signer_modal.css?v={$GLOBALS['v_js_includes']}" rel="stylesheet"/>
4857 <script src="{$GLOBALS['web_root']}/portal/sign/assets/signature_pad.umd.js?v={$GLOBALS['v_js_includes']}"></script>
4858 <script src="{$GLOBALS['web_root']}/portal/sign/assets/signer_api.js?v={$GLOBALS['v_js_includes']}"></script>
4859 EOD;
4862 // This returns stuff that needs to go into the <head> section of a caller using
4863 // the drawable image field type in a form.
4864 // A TRUE argument makes the widget controls smaller.
4866 function lbf_canvas_head($small = true)
4868 $s = <<<EOD
4869 <link href="{$GLOBALS['assets_static_relative']}/literallycanvas/css/literallycanvas.css" rel="stylesheet" />
4870 <script src="{$GLOBALS['assets_static_relative']}/react/build/react-with-addons.min.js"></script>
4871 <script src="{$GLOBALS['assets_static_relative']}/react/build/react-dom.min.js"></script>
4872 <script src="{$GLOBALS['assets_static_relative']}/literallycanvas/js/literallycanvas.min.js"></script>
4873 EOD;
4874 if ($small) {
4875 $s .= <<<EOD
4876 <style>
4877 /* Custom LiterallyCanvas styling.
4878 * This makes the widget 25% less tall and adjusts some other things accordingly.
4880 .literally {
4881 min-height: 100%;
4882 min-width: 300px; /* Was 400, unspecified */
4884 .literally .lc-picker .toolbar-button {
4885 width: 20px;
4886 height: 20px;
4887 line-height: 20px; /* Was 26, 26, 26 */
4889 .literally .color-well {
4890 font-size: 8px;
4891 width: 49px; /* Was 10, 60 */
4893 .literally .color-well-color-container {
4894 width: 21px;
4895 height: 21px; /* Was 28, 28 */
4897 .literally .lc-picker {
4898 width: 50px; /* Was 61 */
4900 .literally .lc-drawing.with-gui {
4901 left: 50px; /* Was 61 */
4903 .literally .lc-options {
4904 left: 50px; /* Was 61 */
4906 .literally .color-picker-popup {
4907 left: 49px;
4908 bottom: 0px; /* Was 60, 31 */
4910 </style>
4911 EOD;
4914 return $s;
4918 * Test if modifier($test) is in array of options for data type.
4920 * @param json array $options ["G","P","T"], ["G"] or could be legacy string with form "GPT", "G", "012"
4921 * @param string $test
4922 * @return boolean
4924 function isOption($options, string $test): bool
4926 if (empty($options) || !isset($test) || $options == "null") {
4927 return false; // why bother?
4929 if (strpos($options, ',') === false) { // not json array of modifiers.
4930 // could be string of char's or single element of json ["RO"] or "TP" or "P" e.t.c.
4931 json_decode($options, true); // test if options json. json_last_error() will return JSON_ERROR_SYNTAX if not.
4932 // if of form ["RO"] (single modifier) means not legacy so continue on.
4933 if (is_string($options) && (json_last_error() !== JSON_ERROR_NONE)) { // nope, it's string.
4934 $t = str_split(trim($options)); // very good chance it's legacy modifier string.
4935 $options = json_encode($t); // make it json array to convert from legacy to new modifier json schema.
4939 $options = json_decode($options, true); // all should now be json
4941 return is_array($options) && in_array($test, $options, true); // finally the truth!