3 // Copyright (C) 2007-2021 Rod Roark <rod@sunsetsystems.com>
4 // Copyright © 2010 by Andrew Moore <amoore@cpan.org>
5 // Copyright © 2010 by "Boyd Stephen Smith Jr." <bss@iguanasuicide.net>
6 // Copyright (c) 2017 - 2021 Jerry Padgett <sjpadgett@gmail.com>
7 // Copyright (c) 2021 Robert Down <robertdown@live.com>
8 // Copyright (c) 2022 David Eschelbacher <psoas@tampabay.rr.com>
10 // This program is free software; you can redistribute it and/or
11 // modify it under the terms of the GNU General Public License
12 // as published by the Free Software Foundation; either version 2
13 // of the License, or (at your option) any later version.
15 // Functions for managing the lists and layouts
17 // Note: there are translation wrappers for the lists and layout labels
18 // at library/translation.inc.php. The functions are titled
19 // xl_list_label() and xl_layout_label() and are controlled by the
20 // $GLOBALS['translate_lists'] and $GLOBALS['translate_layout']
21 // flags in globals.php
23 // Documentation for layout_options.edit_options:
25 // A = Age as years or "xx month(s)"
26 // B = Gestational age as "xx week(s) y day(s)"
27 // C = Capitalize first letter of each word (text fields)
28 // D = Check for duplicates in New Patient form
29 // G = Graphable (for numeric fields in forms supporting historical data)
30 // H = Read-only field copied from static history (this is obsolete)
31 // J = Jump to Next Row
32 // K = Prepend Blank Row
33 // L = Lab Order ("ord_lab") types only (address book)
34 // M = Radio Group Master (currently for radio buttons only)
35 // m = Radio Group Member (currently for radio buttons only)
36 // N = Show in New Patient form
37 // O = Procedure Order ("ord_*") types only (address book)
38 // P = Default to previous value when current value is not yet set
39 // R = Distributor types only (address book)
40 // T = Use description as default Text
41 // DAP = Use description as placeholder
42 // U = Capitalize all letters (text fields)
43 // V = Vendor types only (address book)
44 // 0 = Read Only - the input element's "disabled" property is set
45 // 1 = Write Once (not editable when not empty) (text fields)
46 // 2 = Show descriptions instead of codes for billing code input
48 // note: isOption() returns true/false
50 // NOTE: All of the magic constants for the data types here are found in library/layout.inc.php
52 require_once("user.inc.php");
53 require_once("patient.inc.php");
54 require_once("lists.inc.php");
55 require_once(dirname(dirname(__FILE__
)) . "/custom/code_types.inc.php");
57 use OpenEMR\Common\Acl\AclExtended
;
58 use OpenEMR\Common\Acl\AclMain
;
59 use OpenEMR\Common\Layouts\LayoutsUtils
;
60 use OpenEMR\Services\EncounterService
;
61 use OpenEMR\Services\FacilityService
;
62 use OpenEMR\Services\PatientService
;
64 $facilityService = new FacilityService();
67 $membership_group_number = 0;
69 // Our base Bootstrap column class, referenced here and in some other modules.
70 // Using col-lg allow us to have additional breakpoint at col-md.(992px, 768px)
71 // col-md-auto will let BS decide with col-12 always for sm devices.
72 $BS_COL_CLASS = 'col-12 col-md-auto col-lg';
74 function get_pharmacies()
76 return sqlStatement("SELECT d.id, d.name, a.line1, a.city, " .
77 "p.area_code, p.prefix, p.number FROM pharmacies AS d " .
78 "LEFT OUTER JOIN addresses AS a ON a.foreign_id = d.id " .
79 "LEFT OUTER JOIN phone_numbers AS p ON p.foreign_id = d.id " .
81 "ORDER BY a.state, a.city, d.name, p.area_code, p.prefix, p.number");
84 function optionalAge($frow, $date, &$asof, $description = '')
91 $edit_options = $frow['edit_options'] ??
null;
93 $date = substr($date, 0, 10);
94 if (isOption($edit_options, 'A') !== false) {
96 } elseif (isOption($edit_options, 'B') !== false) {
102 if (isOption($frow['form_id'], 'LBF') === false) {
104 "SELECT date FROM form_encounter WHERE " .
105 "pid = ? AND encounter = ? ORDER BY id DESC LIMIT 1",
106 array($GLOBALS['pid'], $GLOBALS['encounter'])
108 if (!empty($tmp['date'])) {
109 $asof = substr($tmp['date'], 0, 10);
112 if ($description === '') {
113 $prefix = ($format ?
xl('Gest age') : xl('Age')) . ' ';
115 $prefix = $description . ' ';
117 return $prefix . oeFormatAge($date, $asof, $format);
120 // Function to generate a drop-list.
122 function generate_select_list(
131 $custom_attributes = null,
132 $multiple = false, // new #10
133 $backup_list = '', // new #11
134 $ignore_default = false,
135 $include_inactive = false,
142 $tag_name_esc = attr($tag_name);
144 $attributes['name'] = ($multiple) ?
$tag_name_esc . "[]" : $tag_name_esc;
146 if ($tabIndex !== false) {
147 $attributes['tabindex'] = attr($tabIndex);
151 $attributes['multiple'] = "multiple";
154 $attributes['id'] = attr($tag_name);
155 $attributes['class'] = (!empty($class)) ?
"form-control " . attr($class) : "form-control";
158 $attributes['onchange'] = $onchange;
161 if ($custom_attributes != null && is_array($custom_attributes)) {
162 foreach ($custom_attributes as $attr => $val) {
163 if (isset($custom_attributes [$attr])) {
164 $attributes[attr($attr)] = attr($val);
169 $attributes['title'] = attr($title);
171 $selectEmptyName = xlt($empty_name);
173 preg_match_all('/select2/m', ($class ??
''), $matches, PREG_SET_ORDER
, 0);
174 if (array_key_exists('placeholder', $attributes) && count($matches) > 0) {
175 // We have a placeholder attribute as well as a select2 class indicating there
176 // should be provide a truley empty option.
180 'label' => $selectEmptyName,
182 'isSelected' => true,
187 $got_selected = false;
189 for ($active = 1; $active == 1 ||
($active == 0 && $include_inactive); --$active) {
190 $_optgroup = ($include_inactive) ?
true : false;
192 // List order depends on language translation options.
193 // (Note we do not need to worry about the list order in the algorithm
194 // after the below code block since that is where searches for exceptions
195 // are done which include inactive items or items from a backup
196 // list; note these will always be shown at the bottom of the list no matter the
198 // This block should be migrated to the ListService but the service currently does not translate or offer a sort option.
199 $lang_id = empty($_SESSION['language_choice']) ?
'1' : $_SESSION['language_choice'];
201 $order_by_sql = ($GLOBALS['gb_how_sort_list'] == '0') ?
"seq, title" : "title, seq";
202 if (!$GLOBALS['translate_lists']) {
204 $lres = sqlStatement("SELECT * FROM list_options WHERE list_id = ? AND activity = ? ORDER BY $order_by_sql", [$list_id, $active]);
207 $order_by_sql = str_replace("seq", "lo.seq", $order_by_sql);
208 $sql = "SELECT lo.option_id, lo.is_default,
209 COALESCE((SELECT ld.definition FROM lang_constants AS lc, lang_definitions AS ld
210 WHERE lc.constant_name = lo.title AND ld.cons_id = lc.cons_id AND ld.lang_id = ? AND ld.definition IS NOT NULL
211 AND ld.definition != ''
212 LIMIT 1), lo.title) AS title
213 FROM list_options AS lo
214 WHERE lo.list_id = ? AND lo.activity = ?
215 ORDER BY {$order_by_sql}";
216 $lres = sqlStatement($sql, [$lang_id, $list_id, $active]);
219 // Populate the options array with pertinent values
221 while ($lrow = sqlFetchArray($lres)) {
222 $selectedValues = explode("|", $currvalue ??
'');
225 $optionValue = attr($lrow ['option_id']);
228 (strlen($currvalue ??
'') == 0 && $lrow['is_default'] && !$ignore_default) ||
229 (strlen($currvalue ??
'') > 0 && in_array($lrow['option_id'], $selectedValues))
231 $got_selected = true;
235 // Already has been translated above (if applicable), so do not need to use
236 // the xl_list_label() function here
237 $optionLabel = text($lrow ['title']);
240 'label' => $optionLabel,
241 'value' => $optionValue,
242 'isSelected' => $isSelected,
243 'isActive' => $include_inactive,
247 $_tmp['optGroupOptions'] = $_tmp;
248 $_tmp['optgroupLabel'] = ($active) ?
xla('Active') : xla('Inactive');
253 } // end $active loop
256 To show the inactive item in the list if the value is saved to database
258 if (!$got_selected && strlen($currvalue ??
'') > 0) {
259 $_sql = "SELECT * FROM list_options WHERE list_id = ? AND activity = 0 AND option_id = ? ORDER BY seq, title";
260 $lres_inactive = sqlStatement($_sql, [$list_id, $currvalue]);
261 $lrow_inactive = sqlFetchArray($lres_inactive);
262 if (!empty($lrow_inactive['option_id'])) {
263 $optionValue = htmlspecialchars($lrow_inactive['option_id'], ENT_QUOTES
);
265 'label' => htmlspecialchars(xl_list_label($lrow_inactive['title']), ENT_NOQUOTES
),
266 'value' => $optionValue,
267 'isSelected' => true,
270 $got_selected = true;
274 if (!$got_selected && strlen($currvalue ??
'') > 0 && !$multiple) {
275 $list_id = $backup_list;
276 $lrow = sqlQuery("SELECT title FROM list_options WHERE list_id = ? AND option_id = ?", [$list_id, $currvalue]);
279 'value' => attr($currvalue),
281 'label' => ($lrow > 0 && !empty($backup_list)) ?
text(xl_list_label($lrow['title'])) : text($currvalue),
283 if (empty($lrow) && empty($backup_list)) {
284 $metadata['error'] = [
285 'title' => xlt('Please choose a valid selection from the list.'),
286 'text' => xlt('Fix this'),
289 } elseif (!$got_selected && strlen($currvalue ??
'') > 0 && $multiple) {
290 //if not found in main list, display all selected values that exist in backup list
291 $list_id = $backup_list;
293 $got_selected_backup = false;
294 if (!empty($backup_list)) {
295 $lres_backup = sqlStatement("SELECT * FROM list_options WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
296 while ($lrow_backup = sqlFetchArray($lres_backup)) {
297 $selectedValues = explode("|", $currvalue);
298 $optionValue = attr($lrow_backup['option_id']);
300 if (in_array($lrow_backup ['option_id'], $selectedValues)) {
302 'label' => text(xl_list_label($lrow_backup['title'])),
303 'value' => $optionValue,
304 'isSelected' => true,
306 $got_selected_backup = true;
311 if (!$got_selected_backup) {
312 $selectedValues = explode("|", $currvalue);
313 foreach ($selectedValues as $selectedValue) {
315 'label' => text($selectedValue),
316 'value' => attr($selectedValue),
317 'isSelected' => true,
321 $_metadata['error'] = [
322 'title' => xlt('Please choose a valid selection from the list.'),
323 'text' => xlt('Fix this'),
328 $_parsedOptions = [];
330 foreach ($_options as $o) {
331 $_isOG = (array_key_exists('optGroupOptions', $o) && count($o['optGroupOptions']) > 0) ?
true : false;
332 $_currOG = $o['optgroupLabel'] ??
false;
334 // Render only if the current optgroup label is not triple equal to the previous label
335 if ($_og !== $_currOG) {
336 $_parsedOptions[] = "</optgroup>";
339 // Must have an opt group and it must be different than the previous
340 if ($_isOG && $_og !== $_currOG) {
341 $_parsedOptions[] = sprintf('<optgroup label="%s">', $_currOG);
344 $_parsedOptions[] = _create_option_element($o);
348 $optionString = implode("\n", $_parsedOptions);
350 $_parsedAttributes = [];
351 foreach ($attributes as $attr => $val) {
352 $_parsedAttributes[] = sprintf('%s="%s"', $attr, $val);
354 $attributeString = implode("\n", $_parsedAttributes);
356 $_selectString = sprintf("<select %s>%s</select>", $attributeString, $optionString);
357 $output[] = $_selectString;
359 if (array_key_exists('error', $_metadata)) {
360 $_errorString = sprintf("<span title=\"%s\">%s</span>", $_metadata['error']['title'], $metadata['error']['text']);
361 $output[] = $_errorString;
364 return implode("", $output);
367 function _create_option_element(array $o): string
369 $_valStr = (array_key_exists('value', $o)) ?
"value=\"{$o['value']}\"" : "";
370 $_selStr = (array_key_exists('isSelected', $o) && $o['isSelected'] == true) ?
"selected" : "";
371 $_labStr = (array_key_exists('label', $o)) ?
$o['label'] : "";
372 return "<option $_valStr $_selStr>$_labStr</option>";
375 // Parsing for data type 31, static text.
376 function parse_static_text($frow, $value_allowed = true)
378 $tmp = str_replace("\r\n", "\n", $frow['description']);
379 // Translate if it does not look like HTML.
380 if (substr($tmp, 0, 1) != '<') {
381 $tmp2 = $frow['description'];
382 $tmp3 = xl_layout_label($tmp);
383 if ($tmp3 == $tmp && $tmp2 != $tmp) {
384 // No translation, try again without the CRLF substitution.
385 $tmp3 = xl_layout_label($tmp2);
390 if ($frow['source'] == 'D' ||
$frow['source'] == 'H') {
391 // Source is demographics or history. This case supports value substitution.
392 while (preg_match('/^(.*?)\{(\w+)\}(.*)$/', $tmp, $matches)) {
394 if ($value_allowed) {
396 $tmprow['field_id'] = $matches[2];
397 $s .= lbf_current_value($tmprow, 0, 0);
406 function genLabResultsTextItem($name, $value, $outtype, $size, $maxlength, $disabled = '')
408 $string_maxlength = $maxlength ?
("maxlength='" . attr($maxlength) . "'") : '';
409 $s = "<td align='center'>";
413 $s .= "<input type='text'";
415 $s .= " name='" . attr($name) . "' id='" . attr($name) . "'";
417 $s .= " size='" . attr($size) . "' $string_maxlength" .
418 " value='" . attr($value) . "'" .
419 " $under $disabled />";
425 // $outtype = 0 for form, 1 for print, 2 for display, 3 for plain text.
426 function genLabResults($frow, $currvalue, $outtype = 0, $disabled = '')
428 $field_id = $frow['field_id'];
429 $list_id = $frow['list_id'];
430 $field_id_esc = text($field_id);
431 $under = $outtype == 1 ?
"class='under'" : "";
434 $avalue = json_decode($currvalue, true);
435 if (empty($avalue)) {
438 // $avalue[$option_id][0] : gestation
439 // $avalue[$option_id][1] : radio button value
440 // $avalue[$option_id][2] : test value
441 // $avalue[$option_id][3] : notes
443 $maxlength = $frow['max_length'];
444 $fldlength = empty($frow['fld_length']) ?
20 : $frow['fld_length'];
446 $under = $outtype == 1 ?
"class='under'" : "";
448 $s .= "<table cellpadding='0' cellspacing='0'>";
451 "<td class='bold' align='center'>" . xlt('Test/Screening') . " </td>" .
452 "<td class='bold' align='center'>" . xlt('Gest wks') . " </td>" .
453 "<td class='bold' align='center'> " . xlt('N/A') . " </td>" .
454 "<td class='bold' align='center'>" . xlt('Neg/Nrml') . "</td>" .
455 "<td class='bold' align='center'> " . xlt('Pos/Abn') . " </td>" .
456 "<td class='bold' align='center'>" . xlt('Test Value') . " </td>" .
457 "<td class='bold' align='center'>" . xlt('Date/Notes') . " </td>" .
461 $lres = sqlStatement(
462 "SELECT * FROM list_options WHERE " .
463 "list_id = ? AND activity = 1 ORDER BY seq, title",
467 while ($lrow = sqlFetchArray($lres)) {
468 $option_id = $lrow['option_id'];
469 $option_id_esc = text($option_id);
471 if ($outtype >= 2 && empty($avalue[$option_id][1])) {
476 if (isset($avalue[$option_id][1]) && $avalue[$option_id][1] == '2') {
480 $s .= text(xl_list_label($lrow['title']));
481 $s .= ':' . text($avalue[$option_id][0]);
482 $s .= ':' . text($avalue[$option_id][2]);
483 $s .= ':' . text($avalue[$option_id][3]);
489 $s .= $outtype == 2 ?
"<td class='bold'>" : "<td>";
490 $s .= text(xl_list_label($lrow['title'])) . " </td>";
492 $s .= genLabResultsTextItem(
493 "form_{$field_id_esc}[$option_id_esc][0]",
494 (isset($avalue[$option_id][0]) ?
$avalue[$option_id][0] : ''),
503 $tmp = isset($avalue[$option_id][1]) ?
$avalue[$option_id][1] : '0';
504 $restype = ($tmp == '1') ?
xl('Normal') : (($tmp == '2') ?
xl('Abnormal') : xl('N/A'));
505 $s .= "<td>" . text($restype) . " </td>";
507 for ($i = 0; $i < 3; ++
$i) {
508 $s .= "<td align='center'>";
509 $s .= "<input type='radio'";
511 $s .= " name='radio_{$field_id_esc}[$option_id_esc]'" .
512 " id='radio_{$field_id_esc}[$option_id_esc]'";
514 $s .= " value='$i' $lbfonchange";
515 if (isset($avalue[$option_id][1]) && $avalue[$option_id][1] == "$i") {
518 $s .= " $disabled />";
522 $s .= genLabResultsTextItem(
523 "form_{$field_id_esc}[$option_id_esc][2]",
524 (isset($avalue[$option_id][2]) ?
$avalue[$option_id][2] : ''),
531 $s .= genLabResultsTextItem(
532 "form_{$field_id_esc}[$option_id_esc][3]",
533 (isset($avalue[$option_id][3]) ?
$avalue[$option_id][3] : ''),
549 // $frow is a row from the layout_options table.
550 // $currvalue is the current value, if any, of the associated item.
552 function generate_form_field($frow, $currvalue)
554 global $rootdir, $date_init, $ISSUE_TYPES, $code_types, $membership_group_number;
556 $currescaped = htmlspecialchars($currvalue ??
'', ENT_QUOTES
);
558 $data_type = $frow['data_type'];
559 $field_id = $frow['field_id'];
560 $list_id = $frow['list_id'] ??
null;
561 $backup_list = $frow['list_backup_id'] ??
null;
562 $edit_options = $frow['edit_options'] ??
null;
563 $form_id = $frow['form_id'] ??
null;
565 // 'smallform' can be 'true' if we want a smaller form field, otherwise
566 // can be used to assign arbitrary CSS classes to data entry fields.
567 $smallform = $frow['smallform'] ??
null;
568 if ($smallform === 'true') {
569 $smallform = ' form-control-sm';
572 // escaped variables to use in html
573 $field_id_esc = htmlspecialchars($field_id, ENT_QUOTES
);
574 $list_id_esc = htmlspecialchars(($list_id ??
''), ENT_QUOTES
);
576 // Added 5-09 by BM - Translate description if applicable
577 $description = (isset($frow['description']) ?
htmlspecialchars(xl_layout_label($frow['description']), ENT_QUOTES
) : '');
579 // Support edit option T which assigns the (possibly very long) description as
580 // the default value.
581 if (isOption($edit_options, 'T') !== false) {
582 if (strlen($currescaped) == 0) {
583 $currescaped = $description;
586 // Description used in this way is not suitable as a title.
590 // Support using the description as a placeholder
591 $placeholder = (isOption($edit_options, 'DAP') === true) ?
" placeholder='{$description}' " : '';
593 // added 5-2009 by BM to allow modification of the 'empty' text title field.
594 // Can pass $frow['empty_title'] with this variable, otherwise
595 // will default to 'Unassigned'.
596 // modified 6-2009 by BM to allow complete skipping of the 'empty' text title
597 // if make $frow['empty_title'] equal to 'SKIP'
599 if (isset($frow['empty_title'])) {
600 if ($frow['empty_title'] == "SKIP") {
601 //do not display an 'empty' choice
603 $empty_title = "Unassigned";
605 $empty_title = $frow['empty_title'];
608 $empty_title = "Unassigned";
611 $disabled = isOption($edit_options, '0') === false ?
'' : 'disabled';
616 strpos($form_id, 'LBF') === 0 ||
617 strpos($form_id, 'LBT') === 0 ||
618 strpos($form_id, 'DEM') === 0 ||
619 strpos($form_id, 'HIS') === 0
621 ) ?
"checkSkipConditions();" : "";
622 $lbfonchange = $lbfchange ?
"onchange='$lbfchange'" : "";
624 // generic single-selection list or single-selection list with search or single-selection list with comment support.
625 // These data types support backup lists.
626 if ($data_type == 1 ||
$data_type == 43 ||
$data_type == 46) {
627 if ($data_type == 46) {
628 // support for single-selection list with comment support
629 $lbfchange = "processCommentField(" . attr_js($field_id) . ");" . $lbfchange;
632 echo generate_select_list(
637 ($showEmpty ?
$empty_title : ''),
638 (($data_type == 43) ?
"select-dropdown" : $smallform),
641 ($disabled ?
array('disabled' => 'disabled') : null),
646 if ($data_type == 46) {
647 // support for single-selection list with comment support
648 $selectedValues = explode("|", $currvalue);
649 if (!preg_match('/^comment_/', $currvalue) ||
(count($selectedValues) == 1)) {
650 $display = "display:none";
653 $display = "display:inline-block";
654 $comment = $selectedValues[count($selectedValues) - 1];
656 echo "<input type='text'" .
657 " name='form_text_" . attr($field_id) . "'" .
658 " id='form_text_" . attr($field_id) . "'" .
659 " size='" . attr($frow['fld_length']) . "'" .
660 " class='form-control'" .
662 " " . ((!empty($frow['max_length'])) ?
"maxlength='" . attr($frow['max_length']) . "'" : "") . " " .
663 " style='" . $display . "'" .
664 " value='" . attr($comment) . "'/>";
666 } elseif ($data_type == 2) { // simple text field
667 $fldlength = htmlspecialchars($frow['fld_length'] ??
'', ENT_QUOTES
);
668 $maxlength = $frow['max_length'] ??
'';
669 $string_maxlength = "";
670 // if max_length is set to zero, then do not set a maxlength
672 $string_maxlength = "maxlength='" . attr($maxlength) . "'";
675 echo "<input type='text'
676 class='form-control{$smallform}'
677 name='form_{$field_id_esc}'
678 id='form_{$field_id_esc}'
682 title='{$description}'
683 value='{$currescaped}'";
685 if (isOption($edit_options, 'C') !== false) {
686 $tmp .= "capitalizeMe(this);";
687 } elseif (isOption($edit_options, 'U') !== false) {
688 $tmp .= "this.value = this.value.toUpperCase();";
692 echo " onchange='$tmp'";
695 $tmp = htmlspecialchars($GLOBALS['gbl_mask_patient_id'], ENT_QUOTES
);
696 // If mask is for use at save time, treat as no mask.
697 if (strpos($tmp, '^') !== false) {
700 if ($field_id == 'pubpid' && strlen($tmp) > 0) {
701 echo " onkeyup='maskkeyup(this,\"$tmp\")'";
702 echo " onblur='maskblur(this,\"$tmp\")'";
705 if (isOption($edit_options, '1') !== false && strlen($currescaped) > 0) {
714 } elseif ($data_type == 3) { // long or multi-line text field
715 $textCols = htmlspecialchars($frow['fld_length'], ENT_QUOTES
);
716 $textRows = htmlspecialchars($frow['fld_rows'], ENT_QUOTES
);
718 " name='form_$field_id_esc'" .
719 " class='form-control$smallform'" .
720 " id='form_$field_id_esc'" .
721 " title='$description'" .
723 " cols='$textCols'" .
724 " rows='$textRows' $lbfonchange $disabled" .
725 ">" . $currescaped . "</textarea>";
726 } elseif ($data_type == 4) { // date
727 $age_asof_date = ''; // optionalAge() sets this
728 $age_format = isOption($edit_options, 'A') === false ?
3 : 0;
729 $agestr = optionalAge($frow, $currvalue, $age_asof_date, $description);
731 echo "<table class='table'><tr><td class='text'>";
734 $onchange_string = '';
735 if (!$disabled && $agestr) {
736 $onchange_string = "onchange=\"if (typeof(updateAgeString) == 'function') " .
737 "updateAgeString('$field_id','$age_asof_date', $age_format, '$description')\"";
739 if ($data_type == 4) {
740 $modtmp = isOption($edit_options, 'F') === false ?
0 : 1;
741 $datetimepickerclass = ($frow['validation'] ??
null) === 'past_date' ?
'-past' : ( ($frow['validation'] ??
null) === 'future_date' ?
'-future' : '' );
743 $dateValue = oeFormatShortDate(substr($currescaped, 0, 10));
744 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) . "'";
746 $dateValue = oeFormatDateTime(substr($currescaped, 0, 20), 0);
747 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) . "'";
751 echo " title='$description'";
754 // help chrome users avoid autocomplete interfere with datepicker widget display
755 if ($frow['field_id'] == 'DOB') {
756 echo " autocomplete='off' $onchange_string $lbfonchange $disabled />";
758 echo " $onchange_string $lbfonchange $disabled />";
761 // Optional display of age or gestational age.
763 echo "</td></tr><tr><td id='span_$field_id' class='text'>" . text($agestr) . "</td></tr></table>";
765 } elseif ($data_type == 10) { // provider list, local providers only
766 $ures = sqlStatement("SELECT id, fname, lname, specialty FROM users " .
767 "WHERE active = 1 AND ( info IS NULL OR info NOT LIKE '%Inactive%' ) " .
768 "AND authorized = 1 " .
769 "ORDER BY lname, fname");
770 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' title='$description' $lbfonchange $disabled class='form-control$smallform'>";
771 echo "<option value=''>" . xlt($empty_title) . "</option>";
772 $got_selected = false;
773 while ($urow = sqlFetchArray($ures)) {
774 $uname = text($urow['fname'] . ' ' . $urow['lname']);
775 $optionId = attr($urow['id']);
776 echo "<option value='$optionId'";
777 if ($urow['id'] == $currvalue) {
779 $got_selected = true;
782 echo ">$uname</option>";
785 if (!$got_selected && $currvalue) {
786 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
788 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
792 } elseif ($data_type == 11) { // provider list, including address book entries with an NPI number
793 $ures = sqlStatement("SELECT id, fname, lname, specialty FROM users " .
794 "WHERE active = 1 AND ( info IS NULL OR info NOT LIKE '%Inactive%' ) " .
795 "AND ( authorized = 1 OR ((username = '' OR username IS NULL) AND npi != '' )) " .
796 "ORDER BY lname, fname");
797 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' title='$description' class='form-control$smallform'";
798 echo " $lbfonchange $disabled>";
799 echo "<option value=''>" . xlt('Unassigned') . "</option>";
800 $got_selected = false;
801 while ($urow = sqlFetchArray($ures)) {
802 $uname = text($urow['fname'] . ' ' . $urow['lname']);
803 $optionId = attr($urow['id']);
804 echo "<option value='$optionId'";
805 if ($urow['id'] == $currvalue) {
807 $got_selected = true;
810 echo ">$uname</option>";
813 if (!$got_selected && $currvalue) {
814 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
816 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
820 } elseif ($data_type == 12) { // pharmacy list
821 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' title='$description' class='form-control$smallform'";
822 echo " $lbfonchange $disabled>";
823 echo "<option value='0'></option>";
824 $pres = get_pharmacies();
825 $got_selected = false;
827 while ($prow = sqlFetchArray($pres)) {
828 if ($zone != strtolower(trim($prow['city'] ??
''))) {
832 $zone = strtolower(trim($prow['city']));
833 echo "<optgroup label='" . attr($prow['city']) . "'>";
836 $optionValue = htmlspecialchars($key, ENT_QUOTES
);
837 $optionLabel = htmlspecialchars($prow['name'] . ' ' . $prow['area_code'] . '-' .
838 $prow['prefix'] . '-' . $prow['number'] . ' / ' .
839 $prow['line1'] . ' / ' . $prow['city'], ENT_NOQUOTES
);
840 echo "<option value='$optionValue'";
841 if ($currvalue == $key) {
843 $got_selected = true;
846 echo ">$optionLabel</option>";
849 if (!$got_selected && $currvalue) {
850 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
852 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
856 } elseif ($data_type == 13) { // squads
857 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' title='$description' class='form-control$smallform'";
858 echo " $lbfonchange $disabled>";
859 echo "<option value=''> </option>";
860 $squads = AclExtended
::aclGetSquads();
862 foreach ($squads as $key => $value) {
863 $optionValue = htmlspecialchars($key, ENT_QUOTES
);
864 $optionLabel = htmlspecialchars($value[3], ENT_NOQUOTES
);
865 echo "<option value='$optionValue'";
866 if ($currvalue == $key) {
870 echo ">$optionLabel</option>\n";
875 } elseif ($data_type == 14) {
876 // Address book, preferring organization name if it exists and is not in
877 // parentheses, and excluding local users who are not providers.
878 // Supports "referred to" practitioners and facilities.
879 // Alternatively the letter L in edit_options means that abook_type
880 // must be "ord_lab", indicating types used with the procedure
881 // lab ordering system.
882 // Alternatively the letter O in edit_options means that abook_type
883 // must begin with "ord_", indicating types used with the procedure
885 // Alternatively the letter V in edit_options means that abook_type
886 // must be "vendor", indicating the Vendor type.
887 // Alternatively the letter R in edit_options means that abook_type
888 // must be "dist", indicating the Distributor type.
890 if (isOption($edit_options, 'L') !== false) {
891 $tmp = "abook_type = 'ord_lab'";
892 } elseif (isOption($edit_options, 'O') !== false) {
893 $tmp = "abook_type LIKE 'ord\\_%'";
894 } elseif (isOption($edit_options, 'V') !== false) {
895 $tmp = "abook_type LIKE 'vendor%'";
896 } elseif (isOption($edit_options, 'R') !== false) {
897 $tmp = "abook_type LIKE 'dist'";
899 $tmp = "( username = '' OR authorized = 1 )";
902 $ures = sqlStatement("SELECT id, fname, lname, organization, username, npi FROM users " .
903 "WHERE active = 1 AND ( info IS NULL OR info NOT LIKE '%Inactive%' ) " .
905 "ORDER BY organization, lname, fname, npi");
906 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' title='$description' class='form-control$smallform'";
907 echo " $lbfonchange $disabled>";
908 echo "<option value=''>" . htmlspecialchars(xl('Unassigned'), ENT_NOQUOTES
) . "</option>";
909 while ($urow = sqlFetchArray($ures)) {
910 $uname = $urow['organization'];
911 if (empty($uname) ||
substr($uname, 0, 1) == '(') {
912 $uname = $urow['lname'];
913 if ($urow['fname']) {
914 $uname .= ", " . $urow['fname'];
917 $uname .= ": " . $urow['npi'];
921 $optionValue = htmlspecialchars($urow['id'], ENT_QUOTES
);
922 $optionLabel = htmlspecialchars($uname, ENT_NOQUOTES
);
923 echo "<option value='$optionValue'";
924 // Failure to translate Local and External is not an error here;
925 // they are only used as internal flags and must not be translated!
926 $title = $urow['username'] ?
'Local' : 'External';
927 $optionTitle = htmlspecialchars($title, ENT_QUOTES
);
928 echo " title='$optionTitle'";
929 if ($urow['id'] == $currvalue) {
933 echo ">$optionLabel</option>";
937 } elseif ($data_type == 15) { // A billing code. If description matches an existing code type then that type is used.
939 if (!empty($frow['description']) && isset($code_types[$frow['description']])) {
940 $codetype = $frow['description'];
942 $fldlength = attr($frow['fld_length']);
943 $maxlength = $frow['max_length'];
944 $string_maxlength = "";
945 // if max_length is set to zero, then do not set a maxlength
947 $string_maxlength = "maxlength='" . attr($maxlength) . "'";
949 // Edit option E means allow multiple (Extra) billing codes in a field.
950 // We invent a class name for this because JavaScript needs to know.
952 if (strpos($frow['edit_options'], 'E') !== false) {
953 $className = 'EditOptionE';
956 if (isOption($edit_options, '2') !== false) {
957 // Option "2" generates a hidden input for the codes, and a matching visible field
958 // displaying their descriptions. First step is computing the description string.
959 $currdescstring = '';
960 if (!empty($currvalue)) {
961 $relcodes = explode(';', $currvalue);
962 foreach ($relcodes as $codestring) {
963 if ($codestring === '') {
966 if ($currdescstring !== '') {
967 $currdescstring .= '; ';
969 $currdescstring .= getCodeDescription($codestring, $codetype);
973 $currdescstring = attr($currdescstring);
975 echo "<div>"; // wrapper for myHideOrShow()
976 echo "<input type='text'" .
977 " name='form_$field_id_esc'" .
978 " id='form_related_code'" .
979 " class='" . attr($className) . "'" .
980 " size='$fldlength'" .
981 " value='$currescaped'" .
982 " style='display:none'" .
983 " $lbfonchange readonly $disabled />";
984 // Extra readonly input field for optional display of code description(s).
985 echo "<input type='text'" .
986 " name='form_$field_id_esc" . "__desc'" .
987 " size='$fldlength'" .
988 " title='$description'" .
989 " value='$currdescstring'";
991 echo " onclick='sel_related(this," . attr_js($codetype) . ")'";
994 echo "class='form-control$smallform'";
995 echo " readonly $disabled />";
998 echo "<input type='text'" .
999 " name='form_$field_id_esc'" .
1000 " id='form_related_code'" .
1001 " class='" . attr($className) . "'" .
1002 " size='$fldlength'" .
1003 " $string_maxlength" .
1004 " title='$description'" .
1005 " value='$currescaped'";
1007 echo " onclick='sel_related(this," . attr_js($codetype) . ")'";
1010 echo "class='form-control$smallform'";
1011 echo " $lbfonchange readonly $disabled />";
1013 } elseif ($data_type == 16) { // insurance company list
1014 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' class='form-control$smallform' title='$description'>";
1015 echo "<option value='0'></option>";
1016 $insprovs = getInsuranceProviders();
1017 $got_selected = false;
1018 foreach ($insprovs as $key => $ipname) {
1019 $optionValue = htmlspecialchars($key, ENT_QUOTES
);
1020 $optionLabel = htmlspecialchars($ipname, ENT_NOQUOTES
);
1021 echo "<option value='$optionValue'";
1022 if ($currvalue == $key) {
1024 $got_selected = true;
1027 echo ">$optionLabel</option>";
1030 if (!$got_selected && $currvalue) {
1031 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
1033 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
1037 } elseif ($data_type == 17) { // issue types
1038 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' class='form-control$smallform' title='$description'>";
1039 echo "<option value='0'></option>";
1040 $got_selected = false;
1041 foreach ($ISSUE_TYPES as $key => $value) {
1042 $optionValue = htmlspecialchars($key, ENT_QUOTES
);
1043 $optionLabel = htmlspecialchars($value[1], ENT_NOQUOTES
);
1044 echo "<option value='$optionValue'";
1045 if ($currvalue == $key) {
1047 $got_selected = true;
1050 echo ">$optionLabel</option>";
1053 if (!$got_selected && strlen($currvalue) > 0) {
1054 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
1056 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
1060 } elseif ($data_type == 18) { // Visit categories.
1061 $cres = sqlStatement("SELECT pc_catid, pc_catname " .
1062 "FROM openemr_postcalendar_categories ORDER BY pc_catname");
1063 echo "<select name='form_$field_id_esc' id='form_$field_id_esc' class='form-control$smallform' title='$description'" . " $lbfonchange $disabled>";
1064 echo "<option value=''>" . xlt($empty_title) . "</option>";
1065 $got_selected = false;
1066 while ($crow = sqlFetchArray($cres)) {
1067 $catid = $crow['pc_catid'];
1068 if (($catid < 9 && $catid != 5) ||
$catid == 11) {
1072 echo "<option value='" . attr($catid) . "'";
1073 if ($catid == $currvalue) {
1075 $got_selected = true;
1078 echo ">" . text(xl_appt_category($crow['pc_catname'])) . "</option>";
1081 if (!$got_selected && $currvalue) {
1082 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
1084 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
1088 } elseif ($data_type == 21) { // a set of labeled checkboxes
1089 // If no list then it's a single checkbox and its value is "Yes" or empty.
1091 echo "<input type='checkbox' name='form_{$field_id_esc}' " .
1092 "id='form_{$field_id_esc}' value='Yes' $lbfonchange";
1096 echo " $disabled />";
1098 // In this special case, fld_length is the number of columns generated.
1099 $cols = max(1, $frow['fld_length']);
1100 $avalue = explode('|', $currvalue);
1101 $lres = sqlStatement("SELECT * FROM list_options " .
1102 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
1103 echo "<table class='w-100' cellpadding='0' cellspacing='0' title='" . attr($description) . "'>";
1104 $tdpct = (int) (100 / $cols);
1105 for ($count = 0; $lrow = sqlFetchArray($lres); ++
$count) {
1106 $option_id = $lrow['option_id'];
1107 $option_id_esc = htmlspecialchars($option_id, ENT_QUOTES
);
1108 // if ($count) echo "<br />";
1109 if ($count %
$cols == 0) {
1115 echo "<td width='" . attr($tdpct) . "%' nowrap>";
1116 echo "<input type='checkbox' name='form_{$field_id_esc}[$option_id_esc]'" .
1117 "id='form_{$field_id_esc}[$option_id_esc]' class='form-check-inline' value='1' $lbfonchange";
1118 if (in_array($option_id, $avalue)) {
1121 // Added 5-09 by BM - Translate label if applicable
1122 echo " $disabled />" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES
);
1127 if ($count > $cols) {
1128 // Add some space after multiple rows of checkboxes.
1129 $cols = htmlspecialchars($cols, ENT_QUOTES
);
1130 echo "<tr><td colspan='$cols' style='height:0.7rem'></td></tr>";
1135 } elseif ($data_type == 22) { // a set of labeled text input fields
1136 $tmp = explode('|', $currvalue);
1138 foreach ($tmp as $value) {
1139 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
1140 $avalue[$matches[1]] = $matches[2];
1144 $lres = sqlStatement("SELECT * FROM list_options " .
1145 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
1146 echo "<table class='table'>";
1147 while ($lrow = sqlFetchArray($lres)) {
1148 $option_id = $lrow['option_id'];
1149 $option_id_esc = htmlspecialchars($option_id, ENT_QUOTES
);
1150 $maxlength = $frow['max_length'];
1151 $string_maxlength = "";
1152 // if max_length is set to zero, then do not set a maxlength
1154 $string_maxlength = "maxlength='" . attr($maxlength) . "'";
1157 $fldlength = empty($frow['fld_length']) ?
20 : $frow['fld_length'];
1159 // Added 5-09 by BM - Translate label if applicable
1160 echo "<tr><td>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES
) . " </td>";
1161 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES
);
1162 $optionValue = htmlspecialchars($avalue[$option_id], ENT_QUOTES
);
1163 echo "<td><input type='text'" .
1164 " name='form_{$field_id_esc}[$option_id_esc]'" .
1165 " id='form_{$field_id_esc}[$option_id_esc]'" .
1166 " size='$fldlength'" .
1168 " class='form-control$smallform'" .
1169 " $string_maxlength" .
1170 " value='$optionValue'";
1171 echo " $lbfonchange $disabled /></td></tr>";
1175 } elseif ($data_type == 23) { // a set of exam results; 3 radio buttons and a text field:
1176 $tmp = explode('|', $currvalue);
1178 foreach ($tmp as $value) {
1179 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
1180 $avalue[$matches[1]] = $matches[2];
1184 $maxlength = $frow['max_length'];
1185 $string_maxlength = "";
1186 // if max_length is set to zero, then do not set a maxlength
1188 $string_maxlength = "maxlength='" . attr($maxlength) . "'";
1191 $fldlength = empty($frow['fld_length']) ?
20 : $frow['fld_length'];
1192 $lres = sqlStatement("SELECT * FROM list_options " .
1193 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
1194 echo "<table class='table'>";
1195 echo "<tr><td class='font-weight-bold'>" . htmlspecialchars(xl('Exam or Test'), ENT_NOQUOTES
) .
1196 "</td><td class='font-weight-bold'>" . htmlspecialchars(xl('N/A'), ENT_NOQUOTES
) .
1197 " </td><td class='font-weight-bold'>" .
1198 htmlspecialchars(xl('Nor'), ENT_NOQUOTES
) . " </td>" .
1199 "<td class='font-weight-bold'>" .
1200 htmlspecialchars(xl('Abn'), ENT_NOQUOTES
) . " </td><td class='font-weight-bold'>" .
1201 htmlspecialchars(xl('Date/Notes'), ENT_NOQUOTES
) . "</td></tr>";
1202 while ($lrow = sqlFetchArray($lres)) {
1203 $option_id = $lrow['option_id'];
1204 $option_id_esc = htmlspecialchars($option_id, ENT_QUOTES
);
1205 $restype = substr(($avalue[$option_id] ??
''), 0, 1);
1206 $resnote = substr(($avalue[$option_id] ??
''), 2);
1208 // Added 5-09 by BM - Translate label if applicable
1209 echo "<tr><td>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES
) . " </td>";
1211 for ($i = 0; $i < 3; ++
$i) {
1212 $inputValue = htmlspecialchars($i, ENT_QUOTES
);
1213 echo "<td><input type='radio'" .
1214 " name='radio_{$field_id_esc}[$option_id_esc]'" .
1215 " id='radio_{$field_id_esc}[$option_id_esc]'" .
1216 " value='$inputValue' $lbfonchange";
1217 if ($restype === "$i") {
1221 echo " $disabled /></td>";
1224 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES
);
1225 $resnote = htmlspecialchars($resnote, ENT_QUOTES
);
1226 echo "<td><input type='text'" .
1227 " name='form_{$field_id_esc}[$option_id_esc]'" .
1228 " id='form_{$field_id_esc}[$option_id_esc]'" .
1229 " size='$fldlength'" .
1230 " class='form-control'" .
1231 " $string_maxlength" .
1232 " value='$resnote' $disabled /></td>";
1237 } elseif ($data_type == 24) { // the list of active allergies for the current patient
1238 // this is read-only!
1239 $query = "SELECT title, comments FROM lists WHERE " .
1240 "pid = ? AND type = 'allergy' AND enddate IS NULL " .
1242 // echo "<!-- $query -->\n"; // debugging
1243 $lres = sqlStatement($query, array($GLOBALS['pid']));
1245 while ($lrow = sqlFetchArray($lres)) {
1250 echo htmlspecialchars($lrow['title'], ENT_NOQUOTES
);
1251 if ($lrow['comments']) {
1252 echo ' (' . htmlspecialchars($lrow['comments'], ENT_NOQUOTES
) . ')';
1255 } elseif ($data_type == 25) { // a set of labeled checkboxes, each with a text field:
1256 $tmp = explode('|', $currvalue);
1258 foreach ($tmp as $value) {
1259 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
1260 $avalue[$matches[1]] = $matches[2];
1264 $maxlength = $frow['max_length'];
1265 $string_maxlength = "";
1266 // if max_length is set to zero, then do not set a maxlength
1268 $string_maxlength = "maxlength='" . attr($maxlength) . "'";
1271 $fldlength = empty($frow['fld_length']) ?
20 : $frow['fld_length'];
1272 $lres = sqlStatement("SELECT * FROM list_options " .
1273 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
1274 echo "<table class='table'>";
1275 while ($lrow = sqlFetchArray($lres)) {
1276 $option_id = $lrow['option_id'];
1277 $option_id_esc = htmlspecialchars($option_id, ENT_QUOTES
);
1278 $restype = substr($avalue[$option_id], 0, 1);
1279 $resnote = substr($avalue[$option_id], 2);
1281 // Added 5-09 by BM - Translate label if applicable
1282 echo "<tr><td>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES
) . " </td>";
1284 $option_id = htmlspecialchars($option_id, ENT_QUOTES
);
1285 echo "<td><input type='checkbox' name='check_{$field_id_esc}[$option_id_esc]'" .
1286 " id='check_{$field_id_esc}[$option_id_esc]' class='form-check-inline' value='1' $lbfonchange";
1291 echo " $disabled /> </td>";
1292 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES
);
1293 $resnote = htmlspecialchars($resnote, ENT_QUOTES
);
1294 echo "<td><input type='text'" .
1295 " name='form_{$field_id_esc}[$option_id_esc]'" .
1296 " id='form_{$field_id_esc}[$option_id_esc]'" .
1297 " size='$fldlength'" .
1298 " class='form-control$smallform' " .
1299 " $string_maxlength" .
1300 " value='$resnote' $disabled /></td>";
1305 } elseif ($data_type == 26) { // single-selection list with ability to add to it
1306 echo "<div class='input-group'>";
1307 echo generate_select_list(
1312 ($showEmpty ?
$empty_title : ''),
1313 'addtolistclass_' . $list_id . $smallform,
1316 ($disabled ?
array('disabled' => 'disabled') : null),
1320 // show the add button if user has access to correct list
1321 $inputValue = htmlspecialchars(xl('Add'), ENT_QUOTES
);
1322 $btnSize = ($smallform) ?
"btn-sm" : "";
1323 $outputAddButton = "<div class='input-group-append'><input type='button' class='btn btn-secondary $btnSize mb-1 addtolist' id='addtolistid_" . $list_id_esc . "' fieldid='form_" .
1324 $field_id_esc . "' value='$inputValue' $disabled /></div>";
1325 if (AclExtended
::acoExist('lists', $list_id)) {
1326 // a specific aco exist for this list, so ensure access
1327 if (AclMain
::aclCheckCore('lists', $list_id)) {
1328 echo $outputAddButton;
1331 // no specific aco exist for this list, so check for access to 'default' list
1332 if (AclMain
::aclCheckCore('lists', 'default')) {
1333 echo $outputAddButton;
1337 } elseif ($data_type == 27) { // a set of labeled radio buttons
1338 // In this special case, fld_length is the number of columns generated.
1339 $cols = max(1, $frow['fld_length']);
1340 // Support for edit option M.
1341 if (isOption($edit_options, 'M')) {
1342 ++
$membership_group_number;
1345 $lres = sqlStatement("SELECT * FROM list_options " .
1346 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
1347 echo "<table class='table w-100'>";
1348 $tdpct = (int) (100 / $cols);
1349 $got_selected = false;
1350 for ($count = 0; $lrow = sqlFetchArray($lres); ++
$count) {
1351 $option_id = $lrow['option_id'];
1352 $option_id_esc = htmlspecialchars($option_id, ENT_QUOTES
);
1353 if ($count %
$cols == 0) {
1359 echo "<td width='" . attr($tdpct) . "%' nowrap>";
1360 echo "<input type='radio' name='form_{$field_id_esc}' id='form_{$field_id_esc}[$option_id_esc]'" .
1361 " value='$option_id_esc' $lbfonchange";
1362 // Support for edit options M and m.
1363 if (isOption($edit_options, 'M')) {
1364 echo " class='form-check-inline'";
1365 echo " onclick='checkGroupMembers(this, $membership_group_number);'";
1366 } elseif (isOption($edit_options, 'm')) {
1367 echo " class='form-check-inline lbf_memgroup_$membership_group_number'";
1369 echo " class='form-check-inline'";
1373 (strlen($currvalue) == 0 && $lrow['is_default']) ||
1374 (strlen($currvalue) > 0 && $option_id == $currvalue)
1377 $got_selected = true;
1379 echo " $disabled />" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES
);
1385 if ($count > $cols) {
1386 // Add some space after multiple rows of radio buttons.
1387 $cols = htmlspecialchars($cols, ENT_QUOTES
);
1388 echo "<tr><td colspan='$cols' style='height: 0.7rem'></td></tr>";
1393 if (!$got_selected && strlen($currvalue) > 0) {
1394 $fontTitle = htmlspecialchars(xl('Please choose a valid selection.'), ENT_QUOTES
);
1395 $fontText = htmlspecialchars(xl('Fix this'), ENT_NOQUOTES
);
1396 echo "$currescaped <span class='text-danger' title='$fontTitle'>$fontText!</span>";
1398 } elseif ($data_type == 28 ||
$data_type == 32) { // special case for history of lifestyle status; 3 radio buttons
1399 // and a date text field:
1400 // VicarePlus :: A selection list box for smoking status:
1401 $tmp = explode('|', $currvalue);
1402 switch (count($tmp)) {
1406 $resdate = oeFormatShortDate($tmp[2]);
1412 $resdate = oeFormatShortDate($tmp[2]);
1423 $resdate = $restype = "";
1427 $restype = $resdate = $resnote = "";
1432 $maxlength = $frow['max_length'];
1433 $string_maxlength = "";
1434 // if max_length is set to zero, then do not set a maxlength
1436 $string_maxlength = "maxlength='" . attr($maxlength) . "'";
1439 $fldlength = empty($frow['fld_length']) ?
20 : $frow['fld_length'];
1441 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES
);
1442 $resnote = htmlspecialchars($resnote, ENT_QUOTES
);
1443 $resdate = htmlspecialchars($resdate, ENT_QUOTES
);
1444 echo "<table class='table'>";
1446 if ($data_type == 28) {
1448 echo "<td><input type='text' class='form-control'" .
1449 " name='form_$field_id_esc'" .
1450 " id='form_$field_id_esc'" .
1451 " size='$fldlength'" .
1452 " class='form-control$smallform'" .
1453 " $string_maxlength" .
1454 " value='$resnote' $disabled /> </td>";
1455 echo "<td class='font-weight-bold'> " .
1456 " " .
1457 htmlspecialchars(xl('Status'), ENT_NOQUOTES
) . ": </td>";
1458 } elseif ($data_type == 32) {
1460 echo "<tr><td><input type='text'" .
1461 " name='form_text_$field_id_esc'" .
1462 " id='form_text_$field_id_esc'" .
1463 " size='$fldlength'" .
1464 " class='form-control$smallform'" .
1465 " $string_maxlength" .
1466 " value='$resnote' $disabled /> </td></tr>";
1468 //Selection list for smoking status
1469 $onchange = 'radioChange(this.options[this.selectedIndex].value)';//VicarePlus :: The javascript function for selection list.
1470 echo generate_select_list(
1475 ($showEmpty ?
$empty_title : ''),
1479 ($disabled ?
array('disabled' => 'disabled') : null)
1482 echo "<td class='font-weight-bold'> " . xlt('Status') . ": </td>";
1486 echo "<td class='text'><input type='radio'" .
1487 " name='radio_{$field_id_esc}'" .
1488 " id='radio_{$field_id_esc}[current]'" .
1489 " class='form-check-inline'" .
1490 " value='current" . $field_id_esc . "' $lbfonchange";
1491 if ($restype == "current" . $field_id) {
1495 if ($data_type == 32) {
1496 echo " onClick='smoking_statusClicked(this)'";
1499 echo " />" . xlt('Current') . " </td>";
1501 echo "<td class='text'><input type='radio'" .
1502 " name='radio_{$field_id_esc}'" .
1503 " id='radio_{$field_id_esc}[quit]'" .
1504 " class='form-check-inline'" .
1505 " value='quit" . $field_id_esc . "' $lbfonchange";
1506 if ($restype == "quit" . $field_id) {
1510 if ($data_type == 32) {
1511 echo " onClick='smoking_statusClicked(this)'";
1514 echo " $disabled />" . xlt('Quit') . " </td>";
1516 echo "<td class='text'><input type='text' size='6' class='form-control datepicker' name='date_$field_id_esc' id='date_$field_id_esc'" .
1517 " value='$resdate'" .
1518 " title='$description'" .
1522 echo "<td class='text'><input type='radio'" .
1523 " name='radio_{$field_id_esc}'" .
1524 " class='form-check-inline'" .
1525 " id='radio_{$field_id_esc}[never]'" .
1526 " value='never" . $field_id_esc . "' $lbfonchange";
1527 if ($restype == "never" . $field_id) {
1531 if ($data_type == 32) {
1532 echo " onClick='smoking_statusClicked(this)'";
1535 echo " />" . xlt('Never') . " </td>";
1537 echo "<td class='text'><input type='radio'" .
1538 " class='form-check-inline' " .
1539 " name='radio_{$field_id}'" .
1540 " id='radio_{$field_id}[not_applicable]'" .
1541 " value='not_applicable" . $field_id . "' $lbfonchange";
1542 if ($restype == "not_applicable" . $field_id) {
1546 if ($data_type == 32) {
1547 echo " onClick='smoking_statusClicked(this)'";
1550 echo " $disabled />" . xlt('N/A') . " </td>";
1552 //Added on 5-jun-2k14 (regarding 'Smoking Status - display SNOMED code description')
1553 echo "<td class='text'><div id='smoke_code'></div></td>";
1556 } elseif ($data_type == 31) { // static text. read-only, of course.
1557 echo parse_static_text($frow);
1558 } elseif ($data_type == 34) {
1560 // Race and Ethnicity. After added support for backup lists, this is now the same as datatype 36; so have migrated it there.
1563 $arr = explode("|*|*|*|", $currvalue);
1564 echo "<div>"; // wrapper for myHideOrShow()
1565 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'>";
1566 echo "<div id='form_{$field_id}_div' class='text-area' style='min-width: 133px'>" . $arr[0] . "</div>";
1567 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>";
1570 } elseif ($data_type == 35) { //facilities drop-down list
1571 if (empty($currvalue)) {
1576 $selected = $currvalue,
1577 $name = "form_$field_id_esc",
1578 $allow_unspecified = true,
1579 $allow_allfacilities = false,
1585 } elseif ($data_type == 36 ||
$data_type == 33) { //multiple select, supports backup list
1586 echo generate_select_list(
1591 $showEmpty ?
$empty_title : '',
1600 // A set of lab test results; Gestation, 3 radio buttons, test value, notes field:
1601 } elseif ($data_type == 37) {
1602 echo genLabResults($frow, $currvalue, 0, $disabled);
1603 } elseif ($data_type == 40) { // Canvas and related elements for browser-side image drawing.
1604 // Note you must invoke lbf_canvas_head() (below) to use this field type in a form.
1605 // Unlike other field types, width and height are in pixels.
1606 $canWidth = intval($frow['fld_length']);
1607 $canHeight = intval($frow['fld_rows']);
1608 if (empty($currvalue)) {
1609 if (preg_match('/\\bimage=([a-zA-Z0-9._-]*)/', $frow['description'], $matches)) {
1610 // If defined this is the filename of the default starting image.
1611 $currvalue = $GLOBALS['web_root'] . '/sites/' . $_SESSION['site_id'] . '/images/' . $matches[1];
1614 $mywidth = 50 +
($canWidth > 250 ?
$canWidth : 250);
1615 $myheight = 31 +
($canHeight > 261 ?
$canHeight : 261);
1616 echo "<div>"; // wrapper for myHideOrShow()
1617 echo "<div id='form_$field_id_esc' style='width:{$mywidth}px; height:{$myheight}px;'></div>";
1618 // Hidden form field exists to send updated data to the server at submit time.
1619 echo "<input type='hidden' name='form_$field_id_esc' value='' />";
1620 // Hidden image exists to support initialization of the canvas.
1621 echo "<img src='" . attr($currvalue) . "' id='form_{$field_id_esc}_img' style='display:none'>";
1623 // $date_init is a misnomer but it's the place for browser-side setup logic.
1624 $date_init .= " lbfCanvasSetup('form_$field_id_esc', $canWidth, $canHeight);\n";
1625 } elseif ($data_type == 41 ||
$data_type == 42) {
1626 $datatype = 'patient-signature';
1627 $cpid = $GLOBALS['pid'];
1628 $cuser = $_SESSION['authUserID'];
1629 if ($data_type == 42) {
1630 $datatype = 'admin-signature';
1632 echo "<input type='hidden' id='form_$field_id_esc' name='form_$field_id_esc' value='' />\n";
1633 echo "<img class='signature' id='form_{$field_id_esc}_img' title='$description'
1634 data-pid='$cpid' data-user='$cuser' data-type='$datatype'
1635 data-action='fetch_signature' alt='Get Signature' src='" . attr($currvalue) . "'>\n";
1636 } elseif ($data_type == 44) { //multiple select facility
1637 if (empty($currvalue)) {
1642 $selected = $currvalue,
1643 $name = "form_$field_id_esc",
1644 $allow_unspecified = false,
1645 $allow_allfacilities = false,
1651 } elseif ($data_type == 45) { // Multiple provider list, local providers only
1652 $ures = sqlStatement("SELECT id, fname, lname, specialty FROM users " .
1653 "WHERE active = 1 AND ( info IS NULL OR info NOT LIKE '%Inactive%' ) " .
1654 "AND authorized = 1 ORDER BY lname, fname");
1655 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'>";
1656 $got_selected = false;
1657 while ($urow = sqlFetchArray($ures)) {
1658 $uname = text($urow['fname'] . ' ' . $urow['lname']);
1659 $optionId = attr($urow['id']);
1660 echo "<option value='$optionId'";
1661 $selectedValues = explode("|", $currvalue);
1663 if (in_array($optionId, $selectedValues)) {
1665 $got_selected = true;
1668 echo ">$uname</option>";
1671 if (!$got_selected && $currvalue) {
1672 echo "<option value='" . attr($currvalue) . "' selected>* " . text($currvalue) . " *</option>";
1674 echo " <span class='text-danger' title='" . xla('Please choose a valid selection from the list.') . "'>" . xlt('Fix this') . "!</span>";
1679 // Patient selector field.
1680 } elseif ($data_type == 51) {
1681 $fldlength = attr($frow['fld_length']);
1682 $currdescstring = '';
1683 if (!empty($currvalue)) {
1684 $currdescstring .= getPatientDescription($currvalue);
1686 $currdescstring = htmlspecialchars($currdescstring, ENT_QUOTES
);
1687 echo "<div>"; // wrapper for myHideOrShow()
1688 echo "<input type='text'" .
1689 " name='form_$field_id_esc'" .
1690 " size='$fldlength'" .
1691 " value='$currescaped'" .
1692 " style='display:none'" .
1693 " $lbfonchange readonly $disabled />";
1694 // Extra readonly input field for patient description (name and pid).
1695 echo "<input type='text'" .
1696 " name='form_$field_id_esc" . "__desc'" .
1697 " size='$fldlength'" .
1698 " title='$description'" .
1699 " value='$currdescstring'";
1701 echo " onclick='sel_patient(this, this.form.form_$field_id_esc)'";
1703 echo " readonly $disabled />";
1705 // Previous Patient Names with add. Somewhat mirrors data types 44,45.
1706 } elseif ($data_type == 52) {
1708 $pid = ($frow['blank_form'] ??
null) ?
null : $pid;
1709 $patientService = new PatientService();
1710 $res = $patientService->getPatientNameHistory($pid);
1711 echo "<div class='input-group w-75'>";
1712 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'>";
1713 foreach ($res as $row) {
1714 $pname = $row['formatted_name']; // esc'ed in fetch.
1715 $optionId = attr($row['id']);
1716 // all names always selected
1717 echo "<option value='$optionId'" . " selected>$pname</option>";
1720 echo "<button type='button' class='btn btn-primary btn-sm' id='type_52_add' onclick='return specialtyFormDialog()'>" . xlt('Add') . "</button></div>";
1721 // Patient Encounter List Field
1722 } elseif ($data_type == 53) {
1724 $pid = ($frow['blank_form'] ??
null) ?
0 : $pid;
1725 $encounterService = new EncounterService();
1726 $res = $encounterService->getEncountersForPatientByPid($pid);
1727 echo "<div class='input-group w-75'>";
1728 echo "<select name='form_$field_id_esc'" . " id='form_$field_id_esc' title='$description' $lbfonchange $disabled class='form-control$smallform select-encounters'>";
1729 echo "<option value=''>" . xlt("Select Encounter") . "</option>";
1730 foreach ($res as $row) {
1731 $label = text(date("Y-m-d", strtotime($row['date'])) . " " . ($row['pc_catname'] ??
''));
1732 $optionId = attr($row['eid']);
1733 // all names always selected
1734 if ($currvalue == $row['eid']) {
1735 echo "<option value='$optionId'" . " selected>$label</option>";
1737 echo "<option value='$optionId'>$label</option>";
1741 } elseif ($data_type == 54) {
1742 include "templates/address_list_form.php";
1746 function generate_print_field($frow, $currvalue, $value_allowed = true)
1748 global $rootdir, $date_init, $ISSUE_TYPES;
1750 $currescaped = htmlspecialchars($currvalue, ENT_QUOTES
);
1752 $data_type = $frow['data_type'];
1753 $field_id = $frow['field_id'] ??
null;
1754 $list_id = $frow['list_id'];
1755 $fld_length = $frow['fld_length'] ??
null;
1756 $backup_list = $frow['list_backup_id'] ??
null;
1758 $description = attr(xl_layout_label($frow['description'] ??
''));
1760 // Can pass $frow['empty_title'] with this variable, otherwise
1761 // will default to 'Unassigned'.
1762 // If it is 'SKIP' then an empty text title is completely skipped.
1764 if (isset($frow['empty_title'])) {
1765 if ($frow['empty_title'] == "SKIP") {
1766 //do not display an 'empty' choice
1768 $empty_title = "Unassigned";
1770 $empty_title = $frow['empty_title'];
1773 $empty_title = "Unassigned";
1776 // generic single-selection list
1777 // Supports backup lists.
1778 // if (false && ($data_type == 1 || $data_type == 26 || $data_type == 33 || $data_type == 43 || $data_type == 46)) {
1779 // We used to show all the list options but this was undone per CV request 2017-12-07
1780 // (see alternative code below).
1781 if ($data_type == 1 ||
$data_type == 26 ||
$data_type == 33 ||
$data_type == 43 ||
$data_type == 46) {
1782 if (empty($fld_length)) {
1783 if ($list_id == 'titles') {
1792 if ($data_type == 46) {
1793 // support for single-selection list with comment support
1794 $selectedValues = explode("|", $currvalue);
1795 $currvalue = $selectedValues[0];
1798 "SELECT title FROM list_options " .
1799 "WHERE list_id = ? AND option_id = ? AND activity = 1",
1800 array($list_id,$currvalue)
1802 // For lists Race and Ethnicity if there is no matching value in the corresponding lists check ethrace list
1803 if (empty($lrow) && $data_type == 33) {
1805 "SELECT title FROM list_options " .
1806 "WHERE list_id = ? AND option_id = ? AND activity = 1",
1807 array('ethrace', $currvalue)
1811 $tmp = xl_list_label($lrow['title']);
1812 if ($lrow == 0 && !empty($backup_list)) {
1813 // since primary list did not map, try to map to backup list
1814 $lrow = sqlQuery("SELECT title FROM list_options " .
1815 "WHERE list_id = ? AND option_id = ?", array($backup_list,$currvalue));
1816 $tmp = xl_list_label($lrow['title']);
1820 $tmp = "($currvalue)";
1823 if ($data_type == 46) {
1824 // support for single-selection list with comment support
1825 $resnote = $selectedValues[1] ??
null;
1826 if (!empty($resnote)) {
1827 $tmp .= " (" . $resnote . ")";
1835 $tmp = htmlspecialchars($tmp, ENT_QUOTES
);
1838 } elseif ($data_type == 2 ||
$data_type == 15) { // simple text field
1839 if ($currescaped === '') {
1840 $currescaped = ' ';
1844 } elseif ($data_type == 3) { // long or multi-line text field
1845 $fldlength = htmlspecialchars($fld_length, ENT_QUOTES
);
1846 $maxlength = htmlspecialchars($frow['fld_rows'], ENT_QUOTES
);
1848 " class='form-control' " .
1849 " cols='$fldlength'" .
1850 " rows='$maxlength'>" .
1851 $currescaped . "</textarea>";
1852 } elseif ($data_type == 4) { // date
1853 $age_asof_date = '';
1854 $agestr = optionalAge($frow, $currvalue, $age_asof_date, $description);
1855 if ($currvalue === '') {
1858 $modtmp = isOption($frow['edit_options'], 'F') === false ?
0 : 1;
1860 echo text(oeFormatShortDate($currvalue));
1862 echo text(oeFormatDateTime($currvalue));
1865 echo " (" . text($agestr) . ")";
1868 } elseif ($data_type == 10 ||
$data_type == 11) { // provider list
1871 $urow = sqlQuery("SELECT fname, lname, specialty FROM users " .
1872 "WHERE id = ?", array($currvalue));
1873 $tmp = ucwords($urow['fname'] . " " . $urow['lname']);
1875 $tmp = "($currvalue)";
1881 $tmp = htmlspecialchars($tmp, ENT_QUOTES
);
1885 } elseif ($data_type == 12) { // pharmacy list
1888 $pres = get_pharmacies();
1889 while ($prow = sqlFetchArray($pres)) {
1891 if ($currvalue == $key) {
1892 $tmp = $prow['name'] . ' ' . $prow['area_code'] . '-' .
1893 $prow['prefix'] . '-' . $prow['number'] . ' / ' .
1894 $prow['line1'] . ' / ' . $prow['city'];
1899 $tmp = "($currvalue)";
1905 $tmp = htmlspecialchars($tmp, ENT_QUOTES
);
1909 } elseif ($data_type == 13) { // squads
1912 $squads = AclExtended
::aclGetSquads();
1914 foreach ($squads as $key => $value) {
1915 if ($currvalue == $key) {
1922 $tmp = "($currvalue)";
1928 $tmp = htmlspecialchars($tmp, ENT_QUOTES
);
1932 } elseif ($data_type == 14) { // Address book.
1935 $urow = sqlQuery("SELECT fname, lname, specialty FROM users " .
1936 "WHERE id = ?", array($currvalue));
1937 $uname = $urow['lname'];
1938 if ($urow['fname']) {
1939 $uname .= ", " . $urow['fname'];
1944 $tmp = "($currvalue)";
1950 $tmp = htmlspecialchars($tmp, ENT_QUOTES
);
1954 } elseif ($data_type == 16) { // insurance company list
1957 $insprovs = getInsuranceProviders();
1958 foreach ($insprovs as $key => $ipname) {
1959 if ($currvalue == $key) {
1965 $tmp = "($currvalue)";
1972 $tmp = htmlspecialchars($tmp, ENT_QUOTES
);
1976 } elseif ($data_type == 17) { // issue types
1979 foreach ($ISSUE_TYPES as $key => $value) {
1980 if ($currvalue == $key) {
1986 $tmp = "($currvalue)";
1993 $tmp = htmlspecialchars($tmp, ENT_QUOTES
);
1997 } elseif ($data_type == 18) { // Visit categories.
2001 "SELECT pc_catid, pc_catname " .
2002 "FROM openemr_postcalendar_categories WHERE pc_catid = ?",
2005 $tmp = xl_appt_category($crow['pc_catname']);
2007 $tmp = "($currvalue)";
2014 $tmp = htmlspecialchars($tmp, ENT_QUOTES
);
2018 } elseif ($data_type == 21) { // a single checkbox or set of labeled checkboxes
2020 echo "<input type='checkbox'";
2026 // In this special case, fld_length is the number of columns generated.
2027 $cols = max(1, $fld_length);
2028 $avalue = explode('|', $currvalue);
2029 $lres = sqlStatement("SELECT * FROM list_options " .
2030 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2031 echo "<table class='w-100' cellpadding='0' cellspacing='0'>";
2032 $tdpct = (int) (100 / $cols);
2033 for ($count = 0; $lrow = sqlFetchArray($lres); ++
$count) {
2034 $option_id = $lrow['option_id'];
2035 if ($count %
$cols == 0) {
2042 echo "<td width='" . attr($tdpct) . "%' nowrap>";
2043 echo "<input type='checkbox'";
2044 if (in_array($option_id, $avalue)) {
2047 echo ">" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES
);
2052 if ($count > $cols) {
2053 // Add some space after multiple rows of checkboxes.
2054 $cols = htmlspecialchars($cols, ENT_QUOTES
);
2055 echo "<tr><td colspan='$cols' style='height:0.7em'></td></tr>";
2060 } elseif ($data_type == 22) { // a set of labeled text input fields
2061 $tmp = explode('|', $currvalue);
2063 foreach ($tmp as $value) {
2064 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
2065 $avalue[$matches[1]] = $matches[2];
2069 $lres = sqlStatement("SELECT * FROM list_options " .
2070 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2071 echo "<table class='table'>";
2072 while ($lrow = sqlFetchArray($lres)) {
2073 $option_id = $lrow['option_id'];
2074 $fldlength = empty($fld_length) ?
20 : $fld_length;
2075 echo "<tr><td>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES
) . " </td>";
2076 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES
);
2077 $inputValue = htmlspecialchars($avalue[$option_id], ENT_QUOTES
);
2078 echo "<td><input type='text'" .
2079 " class='form-control' " .
2080 " size='$fldlength'" .
2081 " value='$inputValue'" .
2087 } elseif ($data_type == 23) { // a set of exam results; 3 radio buttons and a text field:
2088 $tmp = explode('|', $currvalue);
2090 foreach ($tmp as $value) {
2091 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
2092 $avalue[$matches[1]] = $matches[2];
2096 $fldlength = empty($fld_length) ?
20 : $fld_length;
2097 $lres = sqlStatement("SELECT * FROM list_options " .
2098 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2099 echo "<table class='table'>";
2100 echo "<tr><td><td class='font-weight-bold'>" .
2101 htmlspecialchars(xl('Exam or Test'), ENT_NOQUOTES
) . "</td><td class='font-weight-bold'>" .
2102 htmlspecialchars(xl('N/A'), ENT_NOQUOTES
) .
2103 " </td><td class='font-weight-bold'>" .
2104 htmlspecialchars(xl('Nor'), ENT_NOQUOTES
) . " </td>" .
2105 "<td class='font-weight-bold'>" .
2106 htmlspecialchars(xl('Abn'), ENT_NOQUOTES
) . " </td><td class='font-weight-bold'>" .
2107 htmlspecialchars(xl('Date/Notes'), ENT_NOQUOTES
) . "</td></tr>";
2108 while ($lrow = sqlFetchArray($lres)) {
2109 $option_id = $lrow['option_id'];
2110 $restype = substr($avalue[$option_id], 0, 1);
2111 $resnote = substr($avalue[$option_id], 2);
2112 echo "<tr><td>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES
) . " </td>";
2113 for ($i = 0; $i < 3; ++
$i) {
2114 echo "<td><input type='radio'";
2115 if ($restype === "$i") {
2122 $resnote = htmlspecialchars($resnote, ENT_QUOTES
);
2123 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES
);
2124 echo "<td><input type='text'" .
2125 " size='$fldlength'" .
2126 " value='$resnote'" .
2127 " class='under form-control' /></td>" .
2132 } elseif ($data_type == 24) { // the list of active allergies for the current patient
2133 // this is read-only!
2134 $query = "SELECT title, comments FROM lists WHERE " .
2135 "pid = ? AND type = 'allergy' AND enddate IS NULL " .
2137 $lres = sqlStatement($query, array($GLOBALS['pid']));
2139 while ($lrow = sqlFetchArray($lres)) {
2144 echo htmlspecialchars($lrow['title'], ENT_QUOTES
);
2145 if ($lrow['comments']) {
2146 echo htmlspecialchars(' (' . $lrow['comments'] . ')', ENT_QUOTES
);
2149 } elseif ($data_type == 25) { // a set of labeled checkboxes, each with a text field:
2150 $tmp = explode('|', $currvalue);
2152 foreach ($tmp as $value) {
2153 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
2154 $avalue[$matches[1]] = $matches[2];
2158 $fldlength = empty($fld_length) ?
20 : $fld_length;
2159 $lres = sqlStatement("SELECT * FROM list_options " .
2160 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2161 echo "<table class='table'>";
2162 while ($lrow = sqlFetchArray($lres)) {
2163 $option_id = $lrow['option_id'];
2164 $restype = substr($avalue[$option_id], 0, 1);
2165 $resnote = substr($avalue[$option_id], 2);
2166 echo "<tr><td>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES
) . " </td>";
2167 echo "<td><input type='checkbox'";
2172 echo " /> </td>";
2173 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES
);
2174 $resnote = htmlspecialchars($resnote, ENT_QUOTES
);
2175 echo "<td><input type='text'" .
2176 " size='$fldlength'" .
2177 " class='form-control' " .
2178 " value='$resnote'" .
2185 } elseif ($data_type == 27) { // Removed: || $data_type == 1 || $data_type == 26 || $data_type == 33
2186 // a set of labeled radio buttons
2187 // In this special case, fld_length is the number of columns generated.
2189 $cols = max(1, ($frow['fld_length'] ??
null));
2190 $lres = sqlStatement("SELECT * FROM list_options " .
2191 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2192 echo "<table class='w-100' cellpadding='0' cellspacing='0'>";
2193 $tdpct = (int) (100 / $cols);
2194 for ($count = 0; $lrow = sqlFetchArray($lres); ++
$count) {
2195 $option_id = $lrow['option_id'];
2196 if ($count %
$cols == 0) {
2202 echo "<td width='" . attr($tdpct) . "%' nowrap>";
2203 echo "<input type='radio'";
2204 if (strlen($currvalue) > 0 && $option_id == $currvalue) {
2205 // Do not use defaults for these printable forms.
2208 echo ">" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES
);
2213 if ($count > $cols) {
2214 // Add some space after multiple rows of radio buttons.
2215 $cols = htmlspecialchars($cols, ENT_QUOTES
);
2216 echo "<tr><td colspan='$cols' style='height:0.7em'></td></tr>";
2221 // special case for history of lifestyle status; 3 radio buttons and a date text field:
2222 } elseif ($data_type == 28 ||
$data_type == 32) {
2223 $tmp = explode('|', $currvalue);
2224 switch (count($tmp)) {
2228 $resdate = oeFormatShortDate($tmp[2]) ;
2234 $resdate = oeFormatShortDate($tmp[2]);
2245 $resdate = $restype = "";
2249 $restype = $resdate = $resnote = "";
2254 $fldlength = empty($frow['fld_length']) ?
20 : $frow['fld_length'];
2255 echo "<table class='table'>";
2257 $fldlength = htmlspecialchars($fldlength, ENT_QUOTES
);
2258 $resnote = htmlspecialchars($resnote, ENT_QUOTES
);
2259 $resdate = htmlspecialchars($resdate, ENT_QUOTES
);
2260 if ($data_type == 28) {
2261 echo "<td><input type='text'" .
2262 " size='$fldlength'" .
2264 " value='$resnote' /></td>";
2265 echo "<td class='font-weight-bold'> " .
2266 " " .
2267 htmlspecialchars(xl('Status'), ENT_NOQUOTES
) . ": </td>";
2268 } elseif ($data_type == 32) {
2269 echo "<tr><td><input type='text'" .
2270 " size='$fldlength'" .
2271 " class='under form-control'" .
2272 " value='$resnote' /></td></tr>";
2274 $smoking_status_title = generate_display_field(array('data_type' => '1','list_id' => $list_id), $reslist);
2275 echo "<td><input type='text'" .
2276 " size='$fldlength'" .
2277 " class='under form-control'" .
2278 " value='$smoking_status_title' /></td>";
2279 echo "<td class='font-weight-bold'> " . htmlspecialchars(xl('Status'), ENT_NOQUOTES
) . ": </td>";
2282 echo "<td><input type='radio' class='form-check-inline'";
2283 if ($restype == "current" . $field_id) {
2287 echo "/>" . htmlspecialchars(xl('Current'), ENT_NOQUOTES
) . " </td>";
2289 echo "<td><input type='radio' class='form-check-inline'";
2290 if ($restype == "current" . $field_id) {
2294 echo "/>" . htmlspecialchars(xl('Quit'), ENT_NOQUOTES
) . " </td>";
2296 echo "<td><input type='text' size='6'" .
2297 " value='$resdate'" .
2298 " class='under form-control'" .
2301 echo "<td><input type='radio' class='form-check-inline'";
2302 if ($restype == "current" . $field_id) {
2306 echo " />" . htmlspecialchars(xl('Never'), ENT_NOQUOTES
) . "</td>";
2308 echo "<td><input type='radio' class='form-check-inline'";
2309 if ($restype == "not_applicable" . $field_id) {
2313 echo " />" . htmlspecialchars(xl('N/A'), ENT_NOQUOTES
) . " </td>";
2316 } elseif ($data_type == 31) { // static text. read-only, of course.
2317 echo parse_static_text($frow, $value_allowed);
2318 } elseif ($data_type == 34) {
2319 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'>";
2320 echo "<div id='form_{$field_id}_div' class='text-area'></div>";
2321 echo "<div style='display: none'><textarea name='form_{$field_id}' class='form-control' id='form_{$field_id}' style='display: none'></textarea></div>";
2324 // Facilities. Changed 2017-12-15 to not show the choices.
2325 } elseif ($data_type == 35) {
2327 "SELECT id, name FROM facility WHERE id = ?",
2330 echo empty($urow['id']) ?
' ' : text($urow['name']);
2331 } elseif ($data_type == 36) { //Multi-select. Supports backup lists.
2332 if (empty($fld_length)) {
2333 if ($list_id == 'titles') {
2342 $values_array = explode("|", $currvalue);
2345 foreach ($values_array as $value) {
2347 $lrow = sqlQuery("SELECT title FROM list_options " .
2348 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($list_id,$value));
2349 $tmp = xl_list_label($lrow['title']);
2350 if ($lrow == 0 && !empty($backup_list)) {
2351 // since primary list did not map, try to map to backup list
2352 $lrow = sqlQuery("SELECT title FROM list_options " .
2353 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($backup_list,$currvalue));
2354 $tmp = xl_list_label($lrow['title']);
2365 $tmp = htmlspecialchars($tmp, ENT_QUOTES
);
2368 if ($i != 0 && $tmp != ' ') {
2376 // A set of lab test results; Gestation, 3 radio buttons, test value, notes field:
2377 } elseif ($data_type == 37) {
2378 echo genLabResults($frow, $currvalue, 1, $disabled);
2379 } elseif ($data_type == 40) { // Image from canvas drawing
2380 if (empty($currvalue)) {
2381 if (preg_match('/\\bimage=([a-zA-Z0-9._-]*)/', $frow['description'], $matches)) {
2382 $currvalue = $GLOBALS['web_root'] . '/sites/' . $_SESSION['site_id'] . '/images/' . $matches[1];
2386 echo "<img src='" . attr($currvalue) . "'>";
2388 } elseif ($data_type == 41 ||
$data_type == 42) {
2390 echo "<img class='w-auto' style='height: 70px;' src='" . attr($currvalue) . "'>";
2392 } elseif ($data_type == 44 ||
$data_type == 45) {
2395 $values_array = explode("|", $currvalue);
2398 foreach ($values_array as $value) {
2400 if ($data_type == 44) {
2401 $lrow = sqlQuery("SELECT name as name FROM facility WHERE id = ?", array($value));
2403 if ($data_type == 45) {
2404 $lrow = sqlQuery("SELECT CONCAT(fname,' ',lname) as name FROM users WHERE id = ?", array($value));
2406 $tmp = $lrow['name'];
2412 $tmp = htmlspecialchars($tmp, ENT_QUOTES
);
2415 if ($i != 0 && $tmp != ' ') {
2423 // Patient selector field.
2424 } elseif ($data_type == 51) {
2425 if (!empty($currvalue)) {
2426 $tmp = text(getPatientDescription($currvalue));
2435 * @param bool $translate
2438 * Generate a key-value array containing each row of the specified list,
2439 * with the option ID as the index, and the title as the element
2441 * Pass in the list_id to specify this list.
2443 * Use the translate flag to run the title element through the translator
2445 function generate_list_map($list_id, $translate = false)
2447 $result = sqlStatement("SELECT option_id, title FROM list_options WHERE list_id = ?", [$list_id]);
2449 while ($row = sqlFetchArray($result)) {
2450 if ($translate === true) {
2451 $title = xl_list_label($row['title']);
2453 $title = $row['title'];
2455 $map[$row['option_id']] = $title;
2461 function generate_display_field($frow, $currvalue)
2463 global $ISSUE_TYPES, $facilityService;
2465 $data_type = $frow['data_type'];
2466 $field_id = isset($frow['field_id']) ?
$frow['field_id'] : null;
2467 $list_id = $frow['list_id'];
2468 $backup_list = isset($frow['list_backup_id']) ?
$frow['list_backup_id'] : null;
2469 $show_unchecked_arr = array();
2470 getLayoutProperties($frow['form_id'] ??
null, $show_unchecked_arr, 'grp_unchecked', "1");
2471 $show_unchecked = strval($show_unchecked_arr['']['grp_unchecked'] ??
null) == "0" ?
false : true;
2475 // generic selection list or the generic selection list with add on the fly
2477 if ($data_type == 1 ||
$data_type == 26 ||
$data_type == 43 ||
$data_type == 46) {
2478 if ($data_type == 46) {
2479 // support for single-selection list with comment support
2480 $selectedValues = explode("|", $currvalue);
2481 $currvalue = $selectedValues[0];
2484 $lrow = sqlQuery("SELECT title FROM list_options " .
2485 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($list_id,$currvalue));
2486 $s = htmlspecialchars(xl_list_label($lrow['title'] ??
''), ENT_NOQUOTES
);
2487 //if there is no matching value in the corresponding lists check backup list
2488 // only supported in data types 1,26,43,46
2489 if ($lrow == 0 && !empty($backup_list) && ($data_type == 1 ||
$data_type == 26 ||
$data_type == 43 ||
$data_type == 46)) {
2490 $lrow = sqlQuery("SELECT title FROM list_options " .
2491 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($backup_list,$currvalue));
2492 $s = htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES
);
2495 // If match is not found in main and backup lists, return the key with exclamation mark
2497 $s = nl2br(text(xl_list_label($currvalue))) .
2498 '<span> <i class="fa fas fa-exclamation-circle ml-1"></i></span>';
2501 if ($data_type == 46) {
2502 // support for single-selection list with comment support
2503 $resnote = $selectedValues[1] ??
null;
2504 if (!empty($resnote)) {
2505 $s .= " (" . text($resnote) . ")";
2508 } elseif ($data_type == 2) { // simple text field
2509 $s = nl2br(htmlspecialchars($currvalue, ENT_NOQUOTES
));
2510 } elseif ($data_type == 3) { // long or multi-line text field
2511 $s = nl2br(htmlspecialchars($currvalue, ENT_NOQUOTES
));
2512 } elseif ($data_type == 4) { // date
2513 $asof = ''; //not used here, but set to prevent a php warning when call optionalAge
2515 $description = (isset($frow['description']) ?
htmlspecialchars(xl_layout_label($frow['description']), ENT_QUOTES
) : '');
2516 $age_asof_date = '';
2517 $agestr = optionalAge($frow, $currvalue, $age_asof_date, $description);
2518 if ($currvalue === '') {
2521 $modtmp = isOption($frow['edit_options'], 'F') === false ?
0 : 1;
2523 $s .= text(oeFormatShortDate($currvalue));
2525 $s .= text(oeFormatDateTime($currvalue));
2528 $s .= " (" . text($agestr) . ")";
2531 } elseif ($data_type == 10 ||
$data_type == 11) { // provider
2532 $urow = sqlQuery("SELECT fname, lname, specialty FROM users " .
2533 "WHERE id = ?", array($currvalue));
2534 $s = text(ucwords(($urow['fname'] ??
'') . " " . ($urow['lname'] ??
'')));
2535 } elseif ($data_type == 12) { // pharmacy list
2536 $pres = get_pharmacies();
2537 while ($prow = sqlFetchArray($pres)) {
2539 if ($currvalue == $key) {
2540 $s .= htmlspecialchars($prow['name'] . ' ' . $prow['area_code'] . '-' .
2541 $prow['prefix'] . '-' . $prow['number'] . ' / ' .
2542 $prow['line1'] . ' / ' . $prow['city'], ENT_NOQUOTES
);
2545 } elseif ($data_type == 13) { // squads
2546 $squads = AclExtended
::aclGetSquads();
2548 foreach ($squads as $key => $value) {
2549 if ($currvalue == $key) {
2550 $s .= htmlspecialchars($value[3], ENT_NOQUOTES
);
2554 } elseif ($data_type == 14) { // address book
2555 $urow = sqlQuery("SELECT fname, lname, specialty, organization FROM users " .
2556 "WHERE id = ?", array($currvalue));
2557 //ViSolve: To display the Organization Name if it exist. Else it will display the user name.
2558 if (!empty($urow['organization'])) {
2559 $uname = $urow['organization'];
2561 $uname = $urow['lname'] ??
'';
2562 if (!empty($urow['fname'])) {
2563 $uname .= ", " . $urow['fname'];
2567 $s = htmlspecialchars($uname, ENT_NOQUOTES
);
2568 } elseif ($data_type == 15) { // billing code
2570 if (!empty($currvalue)) {
2571 $relcodes = explode(';', $currvalue);
2572 foreach ($relcodes as $codestring) {
2573 if ($codestring === '') {
2576 $tmp = lookup_code_descriptions($codestring);
2583 $s .= text($codestring) . ' (' . xlt('not found') . ')';
2587 } elseif ($data_type == 16) { // insurance company list
2588 $insprovs = getInsuranceProviders();
2589 foreach ($insprovs as $key => $ipname) {
2590 if ($currvalue == $key) {
2591 $s .= htmlspecialchars($ipname, ENT_NOQUOTES
);
2594 } elseif ($data_type == 17) { // issue types
2595 foreach ($ISSUE_TYPES as $key => $value) {
2596 if ($currvalue == $key) {
2597 $s .= htmlspecialchars($value[1], ENT_NOQUOTES
);
2600 } elseif ($data_type == 18) { // visit category
2602 "SELECT pc_catid, pc_catname " .
2603 "FROM openemr_postcalendar_categories WHERE pc_catid = ?",
2606 $s = htmlspecialchars($crow['pc_catname'], ENT_NOQUOTES
);
2607 } elseif ($data_type == 21) { // a single checkbox or set of labeled checkboxes
2609 $s .= $currvalue ?
'☑' : '☐';
2611 // In this special case, fld_length is the number of columns generated.
2612 $cols = max(1, $frow['fld_length']);
2613 $avalue = explode('|', $currvalue);
2614 $lres = sqlStatement("SELECT * FROM list_options " .
2615 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2616 $s .= "<table cellspacing='0' cellpadding='0'>";
2617 for ($count = 0; $lrow = sqlFetchArray($lres); ++
$count) {
2618 $option_id = $lrow['option_id'];
2619 $option_id_esc = text($option_id);
2620 if ($count %
$cols == 0) {
2626 $checked = in_array($option_id, $avalue);
2627 if (!$show_unchecked && $checked) {
2628 $s .= "<td nowrap>";
2629 $s .= text(xl_list_label($lrow['title'])) . ' ';
2631 } elseif ($show_unchecked) {
2632 $s .= "<td nowrap>";
2633 $s .= $checked ?
'☑' : '☐';
2634 $s .= ' ' . text(xl_list_label($lrow['title'])) . ' ';
2643 } elseif ($data_type == 22) { // a set of labeled text input fields
2644 $tmp = explode('|', $currvalue);
2646 foreach ($tmp as $value) {
2647 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
2648 $avalue[$matches[1]] = $matches[2];
2652 $lres = sqlStatement("SELECT * FROM list_options " .
2653 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2654 $s .= "<table class='table'>";
2655 while ($lrow = sqlFetchArray($lres)) {
2656 $option_id = $lrow['option_id'];
2657 if (empty($avalue[$option_id])) {
2661 // Added 5-09 by BM - Translate label if applicable
2662 $s .= "<tr><td class='font-weight-bold align-top'>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES
) . ": </td>";
2664 $s .= "<td class='text align-top'>" . htmlspecialchars($avalue[$option_id], ENT_NOQUOTES
) . "</td></tr>";
2668 } elseif ($data_type == 23) { // a set of exam results; 3 radio buttons and a text field:
2669 $tmp = explode('|', $currvalue);
2671 foreach ($tmp as $value) {
2672 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
2673 $avalue[$matches[1]] = $matches[2];
2677 $lres = sqlStatement("SELECT * FROM list_options " .
2678 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2679 $s .= "<table class='table'>";
2680 while ($lrow = sqlFetchArray($lres)) {
2681 $option_id = $lrow['option_id'];
2682 $restype = substr(($avalue[$option_id] ??
''), 0, 1);
2683 $resnote = substr(($avalue[$option_id] ??
''), 2);
2684 if (empty($restype) && empty($resnote)) {
2688 // Added 5-09 by BM - Translate label if applicable
2689 $s .= "<tr><td class='font-weight-bold align-top'>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES
) . " </td>";
2691 $restype = ($restype == '1') ?
xl('Normal') : (($restype == '2') ?
xl('Abnormal') : xl('N/A'));
2692 // $s .= "<td class='text align-top'>$restype</td></tr>";
2693 // $s .= "<td class='text align-top'>$resnote</td></tr>";
2694 $s .= "<td class='text align-top'>" . htmlspecialchars($restype, ENT_NOQUOTES
) . " </td>";
2695 $s .= "<td class='text align-top'>" . htmlspecialchars($resnote, ENT_NOQUOTES
) . "</td>";
2700 } elseif ($data_type == 24) { // the list of active allergies for the current patient
2701 $query = "SELECT title, comments FROM lists WHERE " .
2702 "pid = ? AND type = 'allergy' AND enddate IS NULL " .
2704 // echo "<!-- $query -->\n"; // debugging
2705 $lres = sqlStatement($query, array($GLOBALS['pid']));
2707 while ($lrow = sqlFetchArray($lres)) {
2712 $s .= htmlspecialchars($lrow['title'], ENT_NOQUOTES
);
2713 if ($lrow['comments']) {
2714 $s .= ' (' . htmlspecialchars($lrow['comments'], ENT_NOQUOTES
) . ')';
2717 } elseif ($data_type == 25) { // a set of labeled checkboxes, each with a text field:
2718 $tmp = explode('|', $currvalue);
2720 foreach ($tmp as $value) {
2721 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
2722 $avalue[$matches[1]] = $matches[2];
2726 $lres = sqlStatement("SELECT * FROM list_options " .
2727 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
2728 $s .= "<table class='table'>";
2729 while ($lrow = sqlFetchArray($lres)) {
2730 $option_id = $lrow['option_id'];
2731 $restype = substr($avalue[$option_id], 0, 1);
2732 $resnote = substr($avalue[$option_id], 2);
2733 if (empty($restype) && empty($resnote)) {
2737 // Added 5-09 by BM - Translate label if applicable
2738 $s .= "<tr><td class='font-weight-bold align-top'>" . htmlspecialchars(xl_list_label($lrow['title']), ENT_NOQUOTES
) . " </td>";
2740 $restype = $restype ?
xl('Yes') : xl('No');
2741 $s .= "<td class='text align-top'>" . htmlspecialchars($restype, ENT_NOQUOTES
) . " </td>";
2742 $s .= "<td class='text align-top'>" . htmlspecialchars($resnote, ENT_NOQUOTES
) . "</td>";
2747 } elseif ($data_type == 27) { // a set of labeled radio buttons
2748 // In this special case, fld_length is the number of columns generated.
2749 $cols = max(1, $frow['fld_length']);
2750 $lres = sqlStatement("SELECT * FROM list_options " .
2751 "WHERE list_id = ? ORDER BY seq, title", array($list_id));
2752 $s .= "<table cellspacing='0' cellpadding='0'>";
2753 for ($count = 0; $lrow = sqlFetchArray($lres); ++
$count) {
2754 $option_id = $lrow['option_id'];
2755 $option_id_esc = text($option_id);
2756 if ($count %
$cols == 0) {
2762 $checked = ((strlen($currvalue) == 0 && $lrow['is_default']) ||
2763 (strlen($currvalue) > 0 && $option_id == $currvalue));
2764 if (!$show_unchecked && $checked) {
2765 $s .= "<td nowrap>";
2766 $s .= text(xl_list_label($lrow['title'])) . ' ';
2768 } elseif ($show_unchecked) {
2769 $s .= "<td nowrap>";
2770 $s .= $checked ?
'☑' : '☐';
2771 $s .= ' ' . text(xl_list_label($lrow['title'])) . ' ';
2779 } elseif ($data_type == 28 ||
$data_type == 32) { // special case for history of lifestyle status; 3 radio buttons
2780 // and a date text field:
2781 // VicarePlus :: A selection list for smoking status.
2782 $tmp = explode('|', $currvalue);
2783 switch (count($tmp)) {
2787 $resdate = oeFormatShortDate($tmp[2]);
2793 $resdate = oeFormatShortDate($tmp[2]);
2804 $resdate = $restype = "";
2808 $restype = $resdate = $resnote = "";
2813 $s .= "<table class='table'>";
2817 if ($restype == "current" . $field_id) {
2818 $res = xl('Current');
2821 if ($restype == "quit" . $field_id) {
2825 if ($restype == "never" . $field_id) {
2829 if ($restype == "not_applicable" . $field_id) {
2833 // $s .= "<td class='text align-top'>$restype</td></tr>";
2834 // $s .= "<td class='text align-top'>$resnote</td></tr>";
2835 if ($data_type == 28) {
2836 if (!empty($resnote)) {
2837 $s .= "<td class='text align-top'>" . htmlspecialchars($resnote, ENT_NOQUOTES
) . " </td>";
2839 } elseif ($data_type == 32) { //VicarePlus :: Tobacco field has a listbox, text box, date field and 3 radio buttons.
2840 // changes on 5-jun-2k14 (regarding 'Smoking Status - display SNOMED code description')
2841 $smoke_codes = getSmokeCodes();
2842 if (!empty($reslist)) {
2843 if ($smoke_codes[$reslist] != "") {
2844 $code_desc = "( " . $smoke_codes[$reslist] . " )";
2847 $s .= "<td class='text align-top'>" . generate_display_field(array('data_type' => '1','list_id' => $list_id), $reslist) . " " . text($code_desc) . " </td>";
2850 if (!empty($resnote)) {
2851 $s .= "<td class='text align-top'>" . htmlspecialchars($resnote, ENT_NOQUOTES
) . " </td>";
2856 $s .= "<td class='text align-top'><strong>" . htmlspecialchars(xl('Status'), ENT_NOQUOTES
) . "</strong>: " . htmlspecialchars($res, ENT_NOQUOTES
) . " </td>";
2859 if ($restype == "quit" . $field_id) {
2860 $s .= "<td class='text align-top'>" . htmlspecialchars($resdate, ENT_NOQUOTES
) . " </td>";
2865 } elseif ($data_type == 31) { // static text. read-only, of course.
2866 $s .= parse_static_text($frow);
2867 } elseif ($data_type == 34) {
2868 $arr = explode("|*|*|*|", $currvalue);
2869 for ($i = 0; $i < sizeof($arr); $i++
) {
2872 } elseif ($data_type == 35) { // facility
2873 $urow = $facilityService->getById($currvalue);
2874 $s = htmlspecialchars($urow['name'] ??
'', ENT_NOQUOTES
);
2875 } elseif ($data_type == 36 ||
$data_type == 33) { // Multi select. Supports backup lists
2876 $values_array = explode("|", $currvalue);
2878 foreach ($values_array as $value) {
2879 $lrow = sqlQuery("SELECT title FROM list_options " .
2880 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($list_id,$value));
2881 if ($lrow == 0 && !empty($backup_list)) {
2883 $lrow = sqlQuery("SELECT title FROM list_options " .
2884 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($backup_list,$value));
2887 $title = $lrow['title'] ??
'';
2889 $s = $s . ", " . text(xl_list_label($title));
2891 $s = text(xl_list_label($title));
2897 // A set of lab test results; Gestation, 3 radio buttons, test value, notes field:
2898 } elseif ($data_type == 37) {
2899 $s .= genLabResults($frow, $currvalue, 2, '');
2900 } elseif ($data_type == 40) { // Image from canvas drawing
2901 if (empty($currvalue)) {
2902 if (preg_match('/\\bimage=([a-zA-Z0-9._-]*)/', $frow['description'], $matches)) {
2903 $currvalue = $GLOBALS['web_root'] . '/sites/' . $_SESSION['site_id'] . '/images/' . $matches[1];
2907 $s .= "<img src='" . attr($currvalue) . "'>";
2909 } elseif ($data_type == 41 ||
$data_type == 42) {
2911 $s .= "<img class='w-auto' style='height: 70px;' src='" . attr($currvalue) . "'>";
2913 } elseif ($data_type == 44 ||
$data_type == 45) { // Multiple select facility and provider
2914 $values_array = explode("|", $currvalue);
2916 foreach ($values_array as $value) {
2917 if ($data_type == 44) {
2918 $lrow = sqlQuery("SELECT name as name FROM facility WHERE id = ?", array($value));
2920 if ($data_type == 45) {
2921 $lrow = sqlQuery("SELECT CONCAT(fname,' ',lname) as name FROM users WHERE id = ?", array($value));
2924 $s = $s . ", " . htmlspecialchars($lrow['name'], ENT_NOQUOTES
);
2926 $s = text($lrow['name'] ??
'');
2931 // Patient selector field.
2932 } elseif ($data_type == 51) {
2933 if (!empty($currvalue)) {
2934 $s .= text(getPatientDescription($currvalue));
2936 } elseif ($data_type == 52) {
2938 $patientService = new PatientService();
2939 $rows = $patientService->getPatientNameHistory($pid);
2941 foreach ($rows as $row) {
2942 // name escaped in fetch
2944 $s .= ", " . $row['formatted_name'];
2946 $s = $row['formatted_name'] ??
'';
2950 // now that we've concatenated everything, let's escape it.
2952 } elseif ($data_type == 53) {
2953 $service = new EncounterService();
2954 if (!empty($currvalue)) {
2955 $encounterResult = $service->getEncounterById($currvalue);
2956 if (!empty($encounterResult) && $encounterResult->hasData()) {
2957 $encounter = reset($encounterResult->getData());
2958 $s = text($encounter['date'] ??
'');
2961 } elseif ($data_type == 54) {
2962 include "templates/address_list_display.php";
2968 // Generate plain text versions of selected LBF field types.
2969 // Currently used by interface/patient_file/download_template.php and interface/main/finder/dynamic_finder_ajax.php.
2970 // More field types might need to be supported here in the future.
2972 function generate_plaintext_field($frow, $currvalue)
2974 global $ISSUE_TYPES;
2976 $data_type = $frow['data_type'];
2977 $field_id = isset($frow['field_id']) ?
$frow['field_id'] : null;
2978 $list_id = $frow['list_id'];
2979 $backup_list = $frow['backup_list'] ??
null;
2980 $edit_options = $frow['edit_options'] ??
null;
2983 // generic selection list or the generic selection list with add on the fly
2984 // feature, or radio buttons
2985 // Supports backup lists (for datatypes 1,26,43)
2986 if ($data_type == 1 ||
$data_type == 26 ||
$data_type == 27 ||
$data_type == 43 ||
$data_type == 46) {
2987 if ($data_type == 46) {
2988 // support for single-selection list with comment support
2989 $selectedValues = explode("|", $currvalue);
2990 $currvalue = $selectedValues[0];
2994 "SELECT title FROM list_options " .
2995 "WHERE list_id = ? AND option_id = ? AND activity = 1",
2996 array($list_id, $currvalue)
2998 $s = xl_list_label($lrow['title'] ??
'');
2999 //if there is no matching value in the corresponding lists check backup list
3000 // only supported in data types 1,26,43
3001 if ($lrow == 0 && !empty($backup_list) && ($data_type == 1 ||
$data_type == 26 ||
$data_type == 43 ||
$data_type == 46)) {
3002 $lrow = sqlQuery("SELECT title FROM list_options " .
3003 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($backup_list, $currvalue));
3004 $s = xl_list_label($lrow['title']);
3007 if ($data_type == 46) {
3008 // support for single-selection list with comment support
3009 $resnote = $selectedValues[1] ??
null;
3010 if (!empty($resnote)) {
3011 $s .= " (" . $resnote . ")";
3014 } elseif ($data_type == 2 ||
$data_type == 3 ||
$data_type == 15) { // simple or long text field
3016 } elseif ($data_type == 4) { // date
3017 $modtmp = isOption($edit_options, 'F') === false ?
0 : 1;
3019 $s = text(oeFormatShortDate($currvalue));
3021 $s = text(oeFormatDateTime($currvalue));
3023 $description = (isset($frow['description']) ?
htmlspecialchars(xl_layout_label($frow['description']), ENT_QUOTES
) : '');
3024 $age_asof_date = '';
3025 // Optional display of age or gestational age.
3026 $tmp = optionalAge($frow, $currvalue, $age_asof_date, $description);
3030 } elseif ($data_type == 10 ||
$data_type == 11) { // provider
3031 $urow = sqlQuery("SELECT fname, lname, specialty FROM users " .
3032 "WHERE id = ?", array($currvalue));
3033 $s = ucwords($urow['fname'] . " " . $urow['lname']);
3034 } elseif ($data_type == 12) { // pharmacy list
3035 $pres = get_pharmacies();
3036 while ($prow = sqlFetchArray($pres)) {
3038 if ($currvalue == $key) {
3039 $s .= $prow['name'] . ' ' . $prow['area_code'] . '-' .
3040 $prow['prefix'] . '-' . $prow['number'] . ' / ' .
3041 $prow['line1'] . ' / ' . $prow['city'];
3044 } elseif ($data_type == 14) { // address book
3045 $urow = sqlQuery("SELECT fname, lname, specialty FROM users " .
3046 "WHERE id = ?", array($currvalue));
3047 $uname = $urow['lname'];
3048 if ($urow['fname']) {
3049 $uname .= ", " . $urow['fname'];
3053 } elseif ($data_type == 16) { // insurance company list
3054 $insprovs = getInsuranceProviders();
3055 foreach ($insprovs as $key => $ipname) {
3056 if ($currvalue == $key) {
3060 } elseif ($data_type == 17) { // issue type
3061 foreach ($ISSUE_TYPES as $key => $value) {
3062 if ($currvalue == $key) {
3066 } elseif ($data_type == 18) { // visit category
3068 "SELECT pc_catid, pc_catname " .
3069 "FROM openemr_postcalendar_categories WHERE pc_catid = ?",
3072 $s = $crow['pc_catname'];
3073 } elseif ($data_type == 21) { // a set of labeled checkboxes
3075 $s .= $currvalue ?
xlt('Yes') : xlt('No');
3077 $avalue = explode('|', $currvalue);
3078 $lres = sqlStatement("SELECT * FROM list_options " .
3079 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
3081 while ($lrow = sqlFetchArray($lres)) {
3082 $option_id = $lrow['option_id'];
3083 if (in_array($option_id, $avalue)) {
3087 $s .= xl_list_label($lrow['title']);
3091 } elseif ($data_type == 22) { // a set of labeled text input fields
3092 $tmp = explode('|', $currvalue);
3094 foreach ($tmp as $value) {
3095 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
3096 $avalue[$matches[1]] = $matches[2];
3100 $lres = sqlStatement("SELECT * FROM list_options " .
3101 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
3102 while ($lrow = sqlFetchArray($lres)) {
3103 $option_id = $lrow['option_id'];
3104 if (empty($avalue[$option_id])) {
3112 $s .= xl_list_label($lrow['title']) . ': ';
3113 $s .= $avalue[$option_id];
3115 } elseif ($data_type == 23) { // A set of exam results; 3 radio buttons and a text field.
3116 // This shows abnormal results only.
3117 $tmp = explode('|', $currvalue);
3119 foreach ($tmp as $value) {
3120 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
3121 $avalue[$matches[1]] = $matches[2];
3125 $lres = sqlStatement("SELECT * FROM list_options " .
3126 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
3127 while ($lrow = sqlFetchArray($lres)) {
3128 $option_id = $lrow['option_id'];
3129 $restype = substr($avalue[$option_id], 0, 1);
3130 $resnote = substr($avalue[$option_id], 2);
3131 if (empty($restype) && empty($resnote)) {
3135 if ($restype != '2') {
3136 continue; // show abnormal results only
3143 $s .= xl_list_label($lrow['title']);
3144 if (!empty($resnote)) {
3145 $s .= ': ' . $resnote;
3148 } elseif ($data_type == 24) { // the list of active allergies for the current patient
3149 $query = "SELECT title, comments FROM lists WHERE " .
3150 "pid = ? AND type = 'allergy' AND enddate IS NULL " .
3152 $lres = sqlStatement($query, array($GLOBALS['pid']));
3154 while ($lrow = sqlFetchArray($lres)) {
3159 $s .= $lrow['title'];
3160 if ($lrow['comments']) {
3161 $s .= ' (' . $lrow['comments'] . ')';
3164 } elseif ($data_type == 25) { // a set of labeled checkboxes, each with a text field:
3165 $tmp = explode('|', $currvalue);
3167 foreach ($tmp as $value) {
3168 if (preg_match('/^([^:]+):(.*)$/', $value, $matches)) {
3169 $avalue[$matches[1]] = $matches[2];
3173 $lres = sqlStatement("SELECT * FROM list_options " .
3174 "WHERE list_id = ? AND activity = 1 ORDER BY seq, title", array($list_id));
3175 while ($lrow = sqlFetchArray($lres)) {
3176 $option_id = $lrow['option_id'];
3177 $restype = substr($avalue[$option_id], 0, 1);
3178 $resnote = substr($avalue[$option_id], 2);
3179 if (empty($restype) && empty($resnote)) {
3187 $s .= xl_list_label($lrow['title']);
3188 $restype = $restype ?
xl('Yes') : xl('No');
3191 $s .= ' ' . $resnote;
3194 } elseif ($data_type == 28 ||
$data_type == 32) { // special case for history of lifestyle status; 3 radio buttons and a date text field:
3195 // VicarePlus :: A selection list for smoking status.
3196 $tmp = explode('|', $currvalue);
3197 $resnote = count($tmp) > 0 ?
$tmp[0] : '';
3198 $restype = count($tmp) > 1 ?
$tmp[1] : '';
3199 $resdate = count($tmp) > 2 ?
oeFormatShortDate($tmp[2]) : '';
3200 $reslist = count($tmp) > 3 ?
$tmp[3] : '';
3202 if ($restype == "current" . $field_id) {
3203 $res = xl('Current');
3206 if ($restype == "quit" . $field_id) {
3210 if ($restype == "never" . $field_id) {
3214 if ($restype == "not_applicable" . $field_id) {
3218 if ($data_type == 28) {
3219 if (!empty($resnote)) {
3222 } elseif ($data_type == 32) { // Tobacco field has a listbox, text box, date field and 3 radio buttons.
3223 if (!empty($reslist)) {
3224 $s .= generate_plaintext_field(array('data_type' => '1','list_id' => $list_id), $reslist);
3227 if (!empty($resnote)) {
3228 $s .= ' ' . $resnote;
3237 $s .= xl('Status') . ' ' . $res;
3240 if ($restype == "quit" . $field_id) {
3247 } elseif ($data_type == 35) { // Facility, so facility can be listed in plain-text, as in patient finder column
3248 $facilityService = new FacilityService();
3249 $facility = $facilityService->getById($currvalue);
3250 $s = $facility['name'];
3251 } elseif ($data_type == 36 ||
$data_type == 33) { // Multi select. Supports backup lists
3252 $values_array = explode("|", $currvalue);
3255 foreach ($values_array as $value) {
3256 $lrow = sqlQuery("SELECT title FROM list_options " .
3257 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($list_id,$value));
3259 if ($lrow == 0 && !empty($backup_list)) {
3261 $lrow = sqlQuery("SELECT title FROM list_options " .
3262 "WHERE list_id = ? AND option_id = ? AND activity = 1", array($backup_list,$value));
3266 $s = $s . ", " . xl_list_label($lrow['title']);
3268 $s = xl_list_label($lrow['title']);
3274 // A set of lab test results; Gestation, 3 radio buttons, test value, notes field:
3275 } elseif ($data_type == 37) {
3276 $s .= genLabResults($frow, $currvalue, 3, '');
3277 } elseif ($data_type == 44 ||
$data_type == 45) {
3278 $values_array = explode("|", $currvalue);
3281 foreach ($values_array as $value) {
3282 if ($data_type == 44) {
3283 $lrow = sqlQuery("SELECT name as name FROM facility WHERE id = ?", array($value));
3285 if ($data_type == 45) {
3286 $lrow = sqlQuery("SELECT CONCAT(fname,' ',lname) as name FROM users WHERE id = ?", array($value));
3290 $s = $s . ", " . $lrow['name'];
3298 // Patient selector field.
3299 } elseif ($data_type == 51) {
3300 if (!empty($currvalue)) {
3301 $s .= getPatientDescription($currvalue);
3308 $CPR = 4; // cells per row of generic data
3313 function disp_end_cell()
3315 global $item_count, $cell_count;
3316 if ($item_count > 0) {
3322 function disp_end_row()
3324 global $cell_count, $CPR;
3326 if ($cell_count > 0) {
3327 for (; $cell_count < $CPR; ++
$cell_count) {
3336 function disp_end_group()
3339 if (strlen($last_group) > 0) {
3344 // Bootstrapped versions of disp_end_* functions:
3346 function bs_disp_end_cell()
3349 if ($item_count > 0) {
3350 echo "</div>"; // end BS column
3355 function bs_disp_end_row()
3357 global $cell_count, $CPR, $BS_COL_CLASS;
3359 if ($cell_count > 0 && $cell_count < $CPR) {
3360 // Create a cell occupying the remaining bootstrap columns.
3361 // BS columns will be less than 12 if $CPR is not 2, 3, 4, 6 or 12.
3362 $bs_cols_remaining = ($CPR - $cell_count) * intval(12 / $CPR);
3363 echo "<div class='$BS_COL_CLASS-$bs_cols_remaining'></div>";
3365 if ($cell_count > 0) {
3366 echo "</div><!-- End BS row -->\n";
3371 function bs_disp_end_group()
3374 if (strlen($last_group) > 0) {
3381 function getPatientDescription($pid)
3383 $prow = sqlQuery("SELECT lname, fname FROM patient_data WHERE pid = ?", array($pid));
3385 return $prow['lname'] . ", " . $prow['fname'] . " ($pid)";
3387 return xl('Unknown') . " ($pid)";
3390 // Accumulate action conditions into a JSON expression for the browser side.
3391 function accumActionConditions(&$frow, &$condition_str)
3393 $field_id = $frow['field_id'];
3394 $conditions = empty($frow['conditions']) ?
array() : unserialize($frow['conditions'], ['allowed_classes' => false]);
3396 foreach ($conditions as $key => $condition) {
3397 if ($key === 'action') {
3398 // If specified this should be the first array item.
3400 $action = $condition;
3404 if (empty($condition['id'])) {
3407 $andor = empty($condition['andor']) ?
'' : $condition['andor'];
3408 if ($condition_str) {
3409 $condition_str .= ",\n";
3411 $condition_str .= "{" .
3412 "target:" . js_escape($field_id) . ", " .
3413 "action:" . js_escape($action) . ", " .
3414 "id:" . js_escape($condition['id']) . ", " .
3415 "itemid:" . js_escape($condition['itemid']) . ", " .
3416 "operator:" . js_escape($condition['operator']) . ", " .
3417 "value:" . js_escape($condition['value']) . ", ";
3418 if ($frow['data_type'] == 15 && strpos($frow['edit_options'], '2') !== false) {
3419 // For billing codes handle requirement to display its description.
3420 $tmp = explode('=', $action, 2);
3421 if (!empty($tmp[1])) {
3422 $condition_str .= "valdesc:" . js_escape(getCodeDescription($tmp[1])) . ", ";
3425 $condition_str .= "andor:" . js_escape($andor) . "}";
3429 function getCodeDescription($codestring, $defaulttype = 'ICD10')
3431 if ($codestring === '') {
3434 list($ctype, $code) = explode(':', $codestring);
3437 $ctype = $defaulttype;
3439 $desc = lookup_code_descriptions("$ctype:$code");
3440 if (!empty($desc)) {
3447 // This checks if the given field with the given value should have an action applied.
3448 // Originally the only action was skip, but now you can also set the field to a
3449 // specified value, or "skip and otherwise set a value".
3450 // It somewhat mirrors the checkSkipConditions function in options.js.php.
3451 // If you use this for multiple layouts in the same script, you should
3452 // clear $sk_layout_items before each layout.
3453 function isSkipped(&$frow, $currvalue)
3455 global $sk_layout_items;
3457 // Accumulate an array of the encountered fields and their values.
3458 // It is assumed that fields appear before they are tested by another field.
3459 // TBD: Bad assumption?
3460 $field_id = $frow['field_id'];
3461 if (!is_array($sk_layout_items)) {
3462 $sk_layout_items = array();
3464 $sk_layout_items[$field_id] = array('row' => $frow, 'value' => $currvalue);
3466 if (empty($frow['conditions'])) {
3470 $skiprows = unserialize($frow['conditions'], ['allowed_classes' => false]);
3473 $datatype = $frow['data_type'];
3474 $action = 'skip'; // default action if none specified
3476 foreach ($skiprows as $key => $skiprow) {
3477 // id referenced field id
3478 // itemid referenced array key if applicable
3479 // operator "eq", "ne", "se" or "ns"
3480 // value if eq or ne, some string to compare with
3481 // andor "and", "or" or empty
3483 if ($key === 'action') {
3484 // Action value is a string. It can be "skip", or "value=" or "hsval=" followed by a value.
3489 if (empty($skiprow['id'])) {
3493 $id = $skiprow['id'];
3494 if (!isset($sk_layout_items[$id])) {
3495 error_log("Function isSkipped() cannot find skip source field '" . errorLogEscape($id) . "'.");
3498 $itemid = $skiprow['itemid'];
3499 $operator = $skiprow['operator'];
3500 $skipval = $skiprow['value'];
3501 $srcvalue = $sk_layout_items[$id]['value'];
3502 $src_datatype = $sk_layout_items[$id]['row']['data_type'];
3503 $src_list_id = $sk_layout_items[$id]['row']['list_id'];
3505 // Some data types use itemid and we have to dig for their value.
3506 if ($src_datatype == 21 && $src_list_id) { // array of checkboxes
3507 $tmp = explode('|', $srcvalue);
3508 $srcvalue = in_array($itemid, $tmp);
3509 } elseif ($src_datatype == 22 ||
$src_datatype == 23 ||
$src_datatype == 25) {
3510 $tmp = explode('|', $srcvalue);
3512 foreach ($tmp as $tmp2) {
3513 if (strpos($tmp2, "$itemid:") === 0) {
3514 if ($datatype == 22) {
3515 $srcvalue = substr($tmp2, strlen($itemid) +
1);
3517 $srcvalue = substr($tmp2, strlen($itemid) +
1, 1);
3523 // Compute the result of the test for this condition row.
3524 // PHP's looseness with variable type conversion helps us here.
3526 if ($operator == 'eq') {
3527 $condition = $srcvalue == $skipval;
3528 } elseif ($operator == 'ne') {
3529 $condition = $srcvalue != $skipval;
3530 } elseif ($operator == 'se') {
3531 $condition = $srcvalue == true;
3532 } elseif ($operator == 'ns') {
3533 $condition = $srcvalue != true;
3535 error_log("Unknown skip operator '" . errorLogEscape($operator) . "' for field '" . errorLogEscape($field_id) . "'.");
3538 // Logic to accumulate multiple conditions for the same target.
3539 if ($prevandor == 'and') {
3540 $condition = $condition && $prevcond;
3541 } elseif ($prevandor == 'or') {
3542 $condition = $condition ||
$prevcond;
3544 $prevandor = $skiprow['andor'];
3545 $prevcond = $condition;
3548 if (substr($action, 0, 6) == 'hsval=') {
3549 return $prevcond ?
'skip' : ('value=' . substr($action, 6));
3551 return $prevcond ?
$action : '';
3554 // Load array of names of the given layout and its groups.
3555 function getLayoutProperties($formtype, &$grparr, $sel = "grp_title", $limit = null)
3557 if ($sel != '*' && strpos($sel, 'grp_group_id') === false) {
3558 $sel = "grp_group_id, $sel";
3560 $gres = sqlStatement("SELECT $sel FROM layout_group_properties WHERE grp_form_id = ? " .
3561 " ORDER BY grp_group_id " .
3562 ($limit ?
"LIMIT " . escape_limit($limit) : ""), array($formtype));
3563 while ($grow = sqlFetchArray($gres)) {
3564 // TBD: Remove this after grp_init_open column is implemented.
3565 if ($sel == '*' && !isset($grow['grp_init_open'])) {
3567 "SELECT form_id FROM layout_options " .
3568 "WHERE form_id = ? AND group_id LIKE ? AND uor > 0 AND edit_options LIKE '%I%' " .
3570 array($formtype, $grow['grp_group_id'] . '%')
3572 $grow['grp_init_open'] = !empty($tmprow['form_id']);
3574 $grparr[$grow['grp_group_id']] = $grow;
3578 function display_layout_rows($formtype, $result1, $result2 = '')
3580 global $item_count, $cell_count, $last_group, $CPR;
3582 if ('HIS' == $formtype) {
3583 $formtype .= '%'; // TBD: DEM also?
3585 $pres = sqlStatement(
3586 "SELECT grp_form_id, grp_seq, grp_title " .
3587 "FROM layout_group_properties " .
3588 "WHERE grp_form_id LIKE ? AND grp_group_id = '' " .
3589 "ORDER BY grp_seq, grp_title, grp_form_id",
3592 while ($prow = sqlFetchArray($pres)) {
3593 $formtype = $prow['grp_form_id'];
3599 getLayoutProperties($formtype, $grparr, '*');
3601 $TOPCPR = empty($grparr['']['grp_columns']) ?
4 : $grparr['']['grp_columns'];
3603 $fres = sqlStatement("SELECT * FROM layout_options " .
3604 "WHERE form_id = ? AND uor > 0 " .
3605 "ORDER BY group_id, seq", array($formtype));
3607 while ($frow = sqlFetchArray($fres)) {
3608 $this_group = $frow['group_id'];
3609 $titlecols = $frow['titlecols'];
3610 $datacols = $frow['datacols'];
3611 $data_type = $frow['data_type'];
3612 $field_id = $frow['field_id'];
3613 $list_id = $frow['list_id'];
3615 $jump_new_row = isOption($frow['edit_options'], 'J');
3616 $prepend_blank_row = isOption($frow['edit_options'], 'K');
3617 $portal_exclude = (!empty($_SESSION["patient_portal_onsite_two"]) && isOption($frow['edit_options'], 'EP')) ??
null;
3618 $span_col_row = isOption($frow['edit_options'], 'SP');
3620 if (!empty($portal_exclude)) {
3624 $CPR = empty($grparr[$this_group]['grp_columns']) ?
$TOPCPR : $grparr[$this_group]['grp_columns'];
3626 if ($formtype == 'DEM') {
3627 if (strpos($field_id, 'em_') === 0) {
3628 // Skip employer related fields, if it's disabled.
3629 if ($GLOBALS['omit_employers']) {
3633 $tmp = substr($field_id, 3);
3634 if (isset($result2[$tmp])) {
3635 $currvalue = $result2[$tmp];
3638 if (isset($result1[$field_id])) {
3639 $currvalue = $result1[$field_id];
3643 if (isset($result1[$field_id])) {
3644 $currvalue = $result1[$field_id];
3648 // Handle a data category (group) change.
3649 if (strcmp($this_group, $last_group) != 0) {
3650 $group_name = $grparr[$this_group]['grp_title'];
3651 // totally skip generating the employer category, if it's disabled.
3652 if ($group_name === 'Employer' && $GLOBALS['omit_employers']) {
3657 $last_group = $this_group;
3660 // filter out all the empty field data from the patient report.
3661 if (!empty($currvalue) && !($currvalue == '0000-00-00 00:00:00')) {
3662 // Handle starting of a new row.
3663 if (($titlecols > 0 && $cell_count >= $CPR) ||
$cell_count == 0 ||
$prepend_blank_row ||
$jump_new_row) {
3665 if ($prepend_blank_row) {
3666 echo "<tr><td class='label' colspan='" . ($CPR +
1) . "'> </td></tr>\n";
3670 echo "<td class='groupname'>";
3671 echo text(xl_layout_label($group_name));
3674 echo "<td class='align-top'> ";
3680 if ($item_count == 0 && $titlecols == 0) {
3684 // Handle starting of a new label cell.
3685 if ($titlecols > 0 ||
$span_col_row) {
3687 $titlecols = $span_col_row ?
0 : $titlecols;
3688 $titlecols_esc = htmlspecialchars($titlecols, ENT_QUOTES
);
3689 if (!$span_col_row) {
3690 echo "<td class='label_custom' colspan='$titlecols_esc' ";
3693 $cell_count +
= $titlecols;
3698 // Prevent title write if span entire row.
3699 if (!$span_col_row) {
3700 // Added 5-09 by BM - Translate label if applicable
3701 if ($frow['title']) {
3702 $tmp = xl_layout_label($frow['title']);
3704 // Append colon only if label does not end with punctuation.
3705 if (strpos('?!.,:-=', substr($tmp, -1, 1)) === false) {
3712 // Handle starting of a new data cell.
3713 if ($datacols > 0) {
3715 $datacols = $span_col_row ?
$CPR : $datacols;
3716 $datacols_esc = htmlspecialchars($datacols, ENT_QUOTES
);
3717 echo "<td class='text data' colspan='$datacols_esc'";
3719 $cell_count +
= $datacols;
3723 echo generate_display_field($frow, $currvalue);
3727 } // End this layout, there may be more in the case of history.
3730 // This generates the tabs for a form.
3732 function display_layout_tabs($formtype, $result1, $result2 = '')
3734 global $item_count, $cell_count, $last_group, $CPR;
3736 if ('HIS' == $formtype) {
3737 $formtype .= '%'; // TBD: DEM also?
3739 $pres = sqlStatement(
3740 "SELECT grp_form_id, grp_seq, grp_title " .
3741 "FROM layout_group_properties " .
3742 "WHERE grp_form_id LIKE ? AND grp_group_id = '' " .
3743 "ORDER BY grp_seq, grp_title, grp_form_id",
3747 while ($prow = sqlFetchArray($pres)) {
3748 $formtype = $prow['grp_form_id'];
3754 getLayoutProperties($formtype, $grparr);
3756 $fres = sqlStatement("SELECT distinct group_id FROM layout_options " .
3757 "WHERE form_id = ? AND uor > 0 " .
3758 "ORDER BY group_id", array($formtype));
3761 while ($frow = sqlFetchArray($fres)) {
3762 $this_group = $frow['group_id'];
3763 if (substr($prev_group, 0, 1) === substr($this_group, 0, 1)) {
3764 // Skip sub-groups, they will not start a new tab.
3767 $prev_group = $this_group;
3768 $group_name = $grparr[$this_group]['grp_title'];
3769 if ($group_name === 'Employer' && $GLOBALS['omit_employers']) {
3773 <li
<?php
echo $first ?
'class="current"' : '' ?
>>
3774 <a href
="#" id
="header_tab_<?php echo attr($group_name); ?>">
3775 <?php
echo text(xl_layout_label($group_name)); ?
></a
>
3780 } // End this layout, there may be more in the case of history.
3783 // This generates the tab contents of the display version of a form.
3785 function display_layout_tabs_data($formtype, $result1, $result2 = '')
3787 global $item_count, $cell_count, $last_group, $CPR;
3789 if ('HIS' == $formtype) {
3790 $formtype .= '%'; // TBD: DEM also?
3792 $pres = sqlStatement(
3793 "SELECT grp_form_id, grp_seq, grp_title " .
3794 "FROM layout_group_properties " .
3795 "WHERE grp_form_id LIKE ? AND grp_group_id = '' " .
3796 "ORDER BY grp_seq, grp_title, grp_form_id",
3801 // This loops once per layout. Only Patient History can have multiple layouts.
3802 while ($prow = sqlFetchArray($pres)) {
3803 $formtype = $prow['grp_form_id'];
3809 getLayoutProperties($formtype, $grparr, '*');
3811 $TOPCPR = empty($grparr['']['grp_columns']) ?
4 : $grparr['']['grp_columns'];
3813 // By selecting distinct group_id from layout_options we avoid empty groups.
3814 $fres = sqlStatement("SELECT distinct group_id FROM layout_options " .
3815 "WHERE form_id = ? AND uor > 0 " .
3816 "ORDER BY group_id", array($formtype));
3820 // This loops once per group within a given layout.
3821 while ($frow = sqlFetchArray($fres)) {
3822 $this_group = isset($frow['group_id']) ?
$frow['group_id'] : "" ;
3824 if ($grparr[$this_group]['grp_title'] === 'Employer' && $GLOBALS['omit_employers']) {
3827 $CPR = empty($grparr[$this_group]['grp_columns']) ?
$TOPCPR : $grparr[$this_group]['grp_columns'];
3828 $subtitle = empty($grparr[$this_group]['grp_subtitle']) ?
'' : xl_layout_label($grparr[$this_group]['grp_subtitle']);
3830 $group_fields_query = sqlStatement(
3831 "SELECT * FROM layout_options " .
3832 "WHERE form_id = ? AND uor > 0 AND group_id = ? " .
3834 array($formtype, $this_group)
3837 if (substr($this_group, 0, 1) !== substr($prev_group, 0, 1)) {
3838 // Each new top level group gets its own tab div.
3842 echo "<div class='tab" . ($first ?
' current' : '') . "'>\n";
3844 echo "<table border='0' cellpadding='0'>\n";
3846 // This loops once per field within a given group.
3847 while ($group_fields = sqlFetchArray($group_fields_query)) {
3848 $titlecols = $group_fields['titlecols'];
3849 $datacols = $group_fields['datacols'];
3850 $data_type = $group_fields['data_type'];
3851 $field_id = $group_fields['field_id'];
3852 $list_id = $group_fields['list_id'];
3854 $edit_options = $group_fields['edit_options'];
3855 $jump_new_row = isOption($edit_options, 'J');
3856 $prepend_blank_row = isOption($edit_options, 'K');
3857 $span_col_row = isOption($edit_options, 'SP');
3859 if ($formtype == 'DEM') {
3860 if (strpos($field_id, 'em_') === 0) {
3861 // Skip employer related fields, if it's disabled.
3862 if ($GLOBALS['omit_employers']) {
3866 $tmp = substr($field_id, 3);
3867 if (isset($result2[$tmp])) {
3868 $currvalue = $result2[$tmp];
3871 if (isset($result1[$field_id])) {
3872 $currvalue = $result1[$field_id];
3876 if (isset($result1[$field_id])) {
3877 $currvalue = $result1[$field_id];
3881 // Skip this field if action conditions call for that.
3882 // Note this also accumulates info for subsequent skip tests.
3883 $skip_this_field = isSkipped($group_fields, $currvalue) == 'skip';
3885 // Skip this field if its do-not-print option is set.
3886 if (isOption($edit_options, 'X') !== false) {
3887 $skip_this_field = true;
3890 // Handle a data category (group) change.
3891 if (strcmp($this_group, $last_group) != 0) {
3892 $group_name = $grparr[$this_group]['grp_title'];
3893 // totally skip generating the employer category, if it's disabled.
3894 if ($group_name === 'Employer' && $GLOBALS['omit_employers']) {
3897 $last_group = $this_group;
3900 // Handle starting of a new row.
3901 if (($titlecols > 0 && $cell_count >= $CPR) ||
$cell_count == 0 ||
$prepend_blank_row ||
$jump_new_row) {
3904 // Group subtitle exists and is not displayed yet.
3905 echo "<tr><td class='label' style='background-color: var(--gray300); padding: 4px' colspan='$CPR'>" . text($subtitle) . "</td></tr>\n";
3906 echo "<tr><td class='label' style='height: 5px' colspan='$CPR'></td></tr>\n";
3909 if ($prepend_blank_row) {
3910 echo "<tr><td class='label' style='font-size:25%' colspan='$CPR'> </td></tr>\n";
3915 if ($item_count == 0 && $titlecols == 0) {
3919 // Handle starting of a new label cell.
3920 if ($titlecols > 0 ||
$span_col_row) {
3922 $titlecols = $span_col_row ?
0 : $titlecols;
3923 $titlecols_esc = htmlspecialchars($titlecols, ENT_QUOTES
);
3924 $field_id_label = 'label_' . $group_fields['field_id'];
3925 if (!$span_col_row) {
3926 echo "<td class='label_custom' colspan='$titlecols_esc' id='" . attr($field_id_label) . "'";
3929 $cell_count +
= $titlecols;
3934 if ($datacols == 0) {
3935 // Data will be in the same cell, so prevent wrapping to a new line.
3936 echo "<span class='text-nowrap mr-2'>";
3939 $field_id_label = 'label_' . $group_fields['field_id'];
3940 if (!$span_col_row) {
3941 echo "<span id='" . attr($field_id_label) . "'>";
3942 if ($skip_this_field) {
3943 // No label because skipping
3944 } elseif ($group_fields['title']) {
3945 $tmp = xl_layout_label($group_fields['title']);
3947 // Append colon only if label does not end with punctuation.
3948 if (!str_contains('?!.,:-=', $tmp[strlen($tmp) - 1])) {
3957 // Handle starting of a new data cell.
3958 if ($datacols > 0) {
3960 $datacols = $span_col_row ?
$CPR : $datacols;
3961 $datacols_esc = htmlspecialchars($datacols, ENT_QUOTES
);
3962 $field_id = 'text_' . $group_fields['field_id'];
3963 echo "<td class='text data' colspan='$datacols_esc' id='" . attr($field_id) . "' data-value='" . attr($currvalue) . "'";
3964 if (!$skip_this_field && $data_type == 3) {
3965 // Textarea gets a light grey border.
3966 echo " style='border: 1px solid var(--gray400)'";
3969 $cell_count +
= $datacols;
3971 $field_id = 'text_' . $group_fields['field_id'];
3972 echo "<span id='" . attr($field_id) . "' style='display: none'>" . text($currvalue) . "</span>";
3976 if (!$skip_this_field) {
3977 if ($item_count > 1) {
3980 echo generate_display_field($group_fields, $currvalue);
3982 if ($datacols == 0) {
3984 echo "</span> "; // space to allow wrap between spans
3990 // End table for the group.
3993 $prev_group = $this_group;
3995 } // End this group.
3996 } // End this layout, there may be more in the case of history.
4003 // This generates the tab contents of the data entry version of a form.
4005 function display_layout_tabs_data_editable($formtype, $result1, $result2 = '')
4007 global $item_count, $cell_count, $last_group, $CPR, $condition_str, $BS_COL_CLASS;
4009 if ('HIS' == $formtype) {
4010 $formtype .= '%'; // TBD: DEM also?
4012 $pres = sqlStatement(
4013 "SELECT grp_form_id, grp_seq, grp_title " .
4014 "FROM layout_group_properties " .
4015 "WHERE grp_form_id LIKE ? AND grp_group_id = '' " .
4016 "ORDER BY grp_seq, grp_title, grp_form_id",
4020 $condition_str = '';
4022 // This loops once per layout. Only Patient History can have multiple layouts.
4023 while ($prow = sqlFetchArray($pres)) {
4024 $formtype = $prow['grp_form_id'];
4030 getLayoutProperties($formtype, $grparr, '*');
4032 $TOPCPR = empty($grparr['']['grp_columns']) ?
4 : $grparr['']['grp_columns'];
4034 // Check the children of each top-level group to see if any of them are initially open.
4035 // If not, make the first such child initially open.
4036 foreach ($grparr as $tmprow1) {
4037 if (strlen($tmprow1['grp_group_id']) == 1) {
4038 $got_init_open = false;
4040 foreach ($grparr as $key2 => $tmprow2) {
4041 if (substr($tmprow2['grp_group_id'], 0, 1) == $tmprow1['grp_group_id'] && strlen($tmprow2['grp_group_id']) == 2) {
4045 if ($tmprow2['grp_init_open']) {
4046 $got_init_open = true;
4050 if (!$got_init_open && $keyfirst) {
4051 $grparr[$keyfirst]['grp_init_open'] = 1;
4056 // Variables $gs_* are context for the group set in the current tab.
4057 $gs_display_style = 'block';
4058 // This string is the active group levels representing the current display state.
4059 // Each leading substring represents an instance of nesting.
4060 // As each new group is encountered, groups will be closed and opened as needed
4061 // until the display state matches the new group.
4062 $gs_group_levels = '';
4064 // By selecting distinct group_id from layout_options we avoid empty groups.
4065 $fres = sqlStatement("SELECT distinct group_id FROM layout_options " .
4066 "WHERE form_id = ? AND uor > 0 " .
4067 "ORDER BY group_id", array($formtype));
4069 // This loops once per group within a given layout.
4070 while ($frow = sqlFetchArray($fres)) {
4071 $this_group = $frow['group_id'];
4072 $group_name = $grparr[$this_group]['grp_title'];
4073 $group_name_esc = text($group_name);
4075 if ($grparr[$this_group]['grp_title'] === 'Employer' && $GLOBALS['omit_employers']) {
4078 $CPR = empty($grparr[$this_group]['grp_columns']) ?
$TOPCPR : $grparr[$this_group]['grp_columns'];
4079 $subtitle = empty($grparr[$this_group]['grp_subtitle']) ?
'' : xl_layout_label($grparr[$this_group]['grp_subtitle']);
4081 $group_fields_query = sqlStatement("SELECT * FROM layout_options " .
4082 "WHERE form_id = ? AND uor > 0 AND group_id = ? " .
4083 "ORDER BY seq", array($formtype, $this_group));
4085 $gs_this_levels = $this_group;
4086 // Compute $gs_i as the number of initial matching levels.
4088 $tmp = min(strlen($gs_this_levels), strlen($gs_group_levels));
4089 while ($gs_i < $tmp && $gs_this_levels[$gs_i] == $gs_group_levels[$gs_i]) {
4093 // Close any groups that we are done with.
4094 while (strlen($gs_group_levels) > $gs_i) {
4095 $gs_group_name = $grparr[$gs_group_levels]['grp_title'];
4096 if (strlen($gs_group_levels) > 1) {
4097 // No div for an empty sub-group name.
4098 if (strlen($gs_group_name)) {
4102 // This is the top group level so ending this tab and will start a new one.
4105 $gs_group_levels = substr($gs_group_levels, 0, -1); // remove last character
4108 // If there are any new groups, open them.
4109 while ($gs_i < strlen($gs_this_levels)) {
4110 $gs_group_levels .= $gs_this_levels[$gs_i++
];
4111 $gs_group_name = $grparr[substr($gs_group_levels, 0, $gs_i)]['grp_title'];
4112 $gs_init_open = $grparr[substr($gs_group_levels, 0, $gs_i)]['grp_init_open'];
4113 // Compute a short unique identifier for this group.
4114 $gs_group_seq = "grp-$formtype-$gs_group_levels";
4116 // Top level group so new tab.
4117 echo "<div class='tab" . ($first ?
' current' : '') . "' id='tab_$group_name_esc'>\n";
4119 // Not a new tab so start the group inline.
4120 // If group name is blank, no checkbox or div.
4121 if (strlen($gs_group_name)) {
4122 echo "<br /><span class='bold'><input type='checkbox' name='form_cb_" .
4123 attr($gs_group_seq) . "' value='1' " .
4124 "onclick='return divclick(this," . attr_js('div_' . $gs_group_seq) . ");'";
4125 $gs_display_style = $gs_init_open ?
'block' : 'none';
4126 if ($gs_display_style == 'block') {
4129 echo " /><b>" . text(xl_layout_label($gs_group_name)) . "</b></span>\n";
4130 echo "<div id='div_" . attr($gs_group_seq) .
4131 "' class='section' style='display:" . attr($gs_display_style) . ";'>\n";
4136 // Each group or subgroup has its own separate container.
4137 $gs_group_table_active = true;
4138 echo "<div class='container-fluid lbfdata'>\n";
4140 // There is a group subtitle so show it.
4141 $bs_cols = $CPR * intval(12 / $CPR);
4142 echo "<div class='row mb-2'>";
4143 echo "<div class='$BS_COL_CLASS-$bs_cols' style='color:#0000ff'>" . text($subtitle) . "</div>";
4147 // This loops once per field within a given group.
4148 while ($group_fields = sqlFetchArray($group_fields_query)) {
4149 $titlecols = $group_fields['titlecols'];
4150 $datacols = $group_fields['datacols'];
4151 $data_type = $group_fields['data_type'];
4152 $field_id = $group_fields['field_id'];
4153 $list_id = $group_fields['list_id'];
4154 $backup_list = $group_fields['list_backup_id'];
4157 $jump_new_row = isOption($group_fields['edit_options'], 'J');
4158 $prepend_blank_row = isOption($group_fields['edit_options'], 'K');
4159 $span_col_row = isOption($group_fields['edit_options'], 'SP');
4161 // Accumulate action conditions into a JSON expression for the browser side.
4162 accumActionConditions($group_fields, $condition_str);
4164 if ($formtype == 'DEM') {
4165 if (strpos($field_id, 'em_') === 0) {
4166 // Skip employer related fields, if it's disabled.
4167 if ($GLOBALS['omit_employers']) {
4171 $tmp = substr($field_id, 3);
4172 if (isset($result2[$tmp])) {
4173 $currvalue = $result2[$tmp];
4176 if (isset($result1[$field_id])) {
4177 $currvalue = $result1[$field_id];
4181 if (isset($result1[$field_id])) {
4182 $currvalue = $result1[$field_id];
4186 // Handle a data category (group) change.
4187 if (strcmp($this_group, $last_group) != 0) {
4188 // totally skip generating the employer category, if it's disabled.
4189 if ($group_name === 'Employer' && $GLOBALS['omit_employers']) {
4193 $last_group = $this_group;
4196 // Handle starting of a new row.
4197 if (($titlecols > 0 && $cell_count >= $CPR) ||
$cell_count == 0 ||
$prepend_blank_row ||
$jump_new_row) {
4199 $bs_cols = $CPR * intval(12 / $CPR);
4201 // Group subtitle exists and is not displayed yet.
4202 echo "<div class='form-row mb-2'>";
4203 echo "<div class='$BS_COL_CLASS-$bs_cols p-2 label' style='background-color: var(--gray300)'>" . text($subtitle) . "</div>";
4207 if ($prepend_blank_row) {
4208 echo "<div class='form-row'>";
4209 echo "<div class='$BS_COL_CLASS-$bs_cols label' style='font-size: 25%'> </div>";
4212 echo "<div class='form-row'>";
4215 if ($item_count == 0 && $titlecols == 0) {
4219 // Handle starting of a new label cell.
4220 if ($titlecols > 0 ||
$span_col_row) {
4222 $titlecols = $span_col_row ?
0 : $titlecols;
4223 $bs_cols = $titlecols * intval(12 / $CPR);
4224 echo "<div class='$BS_COL_CLASS-$bs_cols pt-1 label_custom' ";
4225 echo "id='label_id_" . attr($field_id) . "'";
4227 $cell_count +
= $titlecols;
4230 // $item_count is the number of title and data items in the current cell.
4233 if ($datacols == 0) {
4234 // Data will be in the same cell, so prevent wrapping to a new line.
4235 echo "<span class='text-nowrap mr-2'>";
4238 if (!$span_col_row) {
4239 if ($group_fields['title']) {
4240 $tmp = xl_layout_label($group_fields['title']);
4242 // Append colon only if label does not end with punctuation.
4243 if (strpos('?!.,:-=', substr($tmp, -1, 1)) === false) {
4251 // Handle starting of a new data cell.
4252 if ($datacols > 0) {
4254 $field_id = 'text_' . $group_fields['field_id'];
4255 $datacols = $span_col_row ?
$CPR : $datacols;
4256 $bs_cols = $datacols * intval(12 / $CPR);
4257 echo "<div class='$BS_COL_CLASS-$bs_cols'";
4258 echo " id='value_id_" . attr($field_id) . "'";
4260 $cell_count +
= $datacols;
4264 if ($item_count > 1) {
4267 // 'smallform' can be used to add arbitrary CSS classes. Note the leading space.
4268 $group_fields['smallform'] = ' form-control-sm mb-1 mw-100';
4269 echo generate_form_field($group_fields, $currvalue);
4270 if ($datacols == 0) {
4272 echo "</span> "; // space to allow wrap between spans
4274 } // End of fields for this group.
4276 bs_disp_end_row(); // TBD: Does this belong here?
4277 echo "</div>\n"; // end container-fluid
4279 } // End this group.
4281 // Close any groups still open.
4282 while (strlen($gs_group_levels) > 0) {
4283 $gs_group_name = $grparr[$gs_group_levels]['grp_title'];
4284 if (strlen($gs_group_levels) > 1) {
4285 // No div for an empty sub-group name.
4286 if (strlen($gs_group_name)) {
4290 // This is the top group level so ending this tab and will start a new one.
4293 $gs_group_levels = substr($gs_group_levels, 0, -1); // remove last character
4295 } // End this layout, there may be more in the case of history.
4298 // From the currently posted HTML form, this gets the value of the
4299 // field corresponding to the provided layout_options table row.
4301 function get_layout_form_value($frow, $prefix = 'form_')
4303 $maxlength = empty($frow['max_length']) ?
0 : intval($frow['max_length']);
4304 $data_type = $frow['data_type'];
4305 $field_id = $frow['field_id'];
4307 if (isset($_POST["$prefix$field_id"])) {
4308 if ($data_type == 4) {
4309 $modtmp = isOption($frow['edit_options'], 'F') === false ?
0 : 1;
4311 $value = DateToYYYYMMDD($_POST["$prefix$field_id"]);
4313 $value = DateTimeToYYYYMMDDHHMMSS($_POST["$prefix$field_id"]);
4315 } elseif ($data_type == 21) {
4316 if (!$frow['list_id']) {
4317 if (!empty($_POST["form_$field_id"])) {
4318 $value = xlt('Yes');
4321 // $_POST["$prefix$field_id"] is an array of checkboxes and its keys
4322 // must be concatenated into a |-separated string.
4323 foreach ($_POST["$prefix$field_id"] as $key => $val) {
4324 if (strlen($value)) {
4330 } elseif ($data_type == 22) {
4331 // $_POST["$prefix$field_id"] is an array of text fields to be imploded
4332 // into "key:value|key:value|...".
4333 foreach ($_POST["$prefix$field_id"] as $key => $val) {
4334 $val = str_replace('|', ' ', $val);
4335 if (strlen($value)) {
4339 $value .= "$key:$val";
4341 } elseif ($data_type == 23) {
4342 // $_POST["$prefix$field_id"] is an array of text fields with companion
4343 // radio buttons to be imploded into "key:n:notes|key:n:notes|...".
4344 foreach ($_POST["$prefix$field_id"] as $key => $val) {
4345 $restype = $_POST["radio_{$field_id}"][$key] ??
null;
4346 if (empty($restype)) {
4350 $val = str_replace('|', ' ', $val);
4351 if (strlen($value)) {
4355 $value .= "$key:$restype:$val";
4357 } elseif ($data_type == 25) {
4358 // $_POST["$prefix$field_id"] is an array of text fields with companion
4359 // checkboxes to be imploded into "key:n:notes|key:n:notes|...".
4360 foreach ($_POST["$prefix$field_id"] as $key => $val) {
4361 $restype = empty($_POST["check_{$field_id}"][$key]) ?
'0' : '1';
4362 $val = str_replace('|', ' ', $val);
4363 if (strlen($value)) {
4367 $value .= "$key:$restype:$val";
4369 } elseif ($data_type == 28 ||
$data_type == 32) {
4370 // $_POST["$prefix$field_id"] is an date text fields with companion
4371 // radio buttons to be imploded into "notes|type|date".
4372 $restype = $_POST["radio_{$field_id}"] ??
'';
4373 if (empty($restype)) {
4377 $resdate = DateToYYYYMMDD(str_replace('|', ' ', $_POST["date_$field_id"]));
4378 $resnote = str_replace('|', ' ', $_POST["$prefix$field_id"]);
4379 if ($data_type == 32) {
4380 //VicarePlus :: Smoking status data is imploded into "note|type|date|list".
4381 $reslist = str_replace('|', ' ', $_POST["$prefix$field_id"]);
4382 $res_text_note = str_replace('|', ' ', $_POST["{$prefix}text_$field_id"]);
4383 $value = "$res_text_note|$restype|$resdate|$reslist";
4385 $value = "$resnote|$restype|$resdate";
4387 } elseif ($data_type == 37) {
4388 // $_POST["form_$field_id"] is an array of arrays of 3 text fields with companion
4389 // radio button set to be encoded as json.
4391 foreach ($_POST["form_$field_id"] as $key => $valarr) {
4392 // Each $key here is a list item ID. $valarr has 3 text field values keyed on 0, 2 and 3.
4393 $tmparr[$key][0] = $valarr['0'];
4394 $tmparr[$key][1] = $_POST["radio_{$field_id}"][$key];
4395 $tmparr[$key][2] = $valarr['2'];
4396 $tmparr[$key][3] = $valarr['3'];
4398 $value .= json_encode($tmparr);
4399 } elseif ($data_type == 36 ||
$data_type == 44 ||
$data_type == 45 ||
$data_type == 33) {
4400 $value_array = $_POST["form_$field_id"];
4402 foreach ($value_array as $key => $valueofkey) {
4404 $value = $valueofkey;
4406 $value = $value . "|" . $valueofkey;
4411 } elseif ($data_type == 46) {
4412 $reslist = trim($_POST["$prefix$field_id"]);
4413 if (preg_match('/^comment_/', $reslist)) {
4414 $res_comment = str_replace('|', ' ', $_POST["{$prefix}text_$field_id"]);
4415 $value = $reslist . "|" . $res_comment;
4417 $value = $_POST["$prefix$field_id"];
4419 } elseif ($data_type == 52) {
4420 $value_array = $_POST["form_$field_id"];
4422 foreach ($value_array as $key => $valueofkey) {
4424 $value = $valueofkey;
4426 $value = $value . "|" . $valueofkey;
4432 $value = $_POST["$prefix$field_id"];
4436 // Better to die than to silently truncate data!
4437 if ($maxlength && $maxlength != 0 && mb_strlen(trim($value)) > $maxlength && !$frow['list_id']) {
4438 die(htmlspecialchars(xl('ERROR: Field') . " '$field_id' " . xl('is too long'), ENT_NOQUOTES
) .
4439 ":<br /> <br />" . htmlspecialchars($value, ENT_NOQUOTES
));
4442 if (is_string($value)) {
4443 return trim($value);
4449 // Generate JavaScript validation logic for the required fields.
4451 function generate_layout_validation($form_id)
4453 if ('HIS' == $form_id) {
4454 $form_id .= '%'; // TBD: DEM also?
4456 $pres = sqlStatement(
4457 "SELECT grp_form_id, grp_seq, grp_title " .
4458 "FROM layout_group_properties " .
4459 "WHERE grp_form_id LIKE ? AND grp_group_id = '' " .
4460 "ORDER BY grp_seq, grp_title, grp_form_id",
4463 while ($prow = sqlFetchArray($pres)) {
4464 $form_id = $prow['grp_form_id'];
4466 $fres = sqlStatement("SELECT * FROM layout_options " .
4467 "WHERE form_id = ? AND uor > 0 AND field_id != '' " .
4468 "ORDER BY group_id, seq", array($form_id));
4470 while ($frow = sqlFetchArray($fres)) {
4471 $data_type = $frow['data_type'];
4472 $field_id = $frow['field_id'];
4473 $fldtitle = $frow['title'];
4475 $fldtitle = $frow['description'];
4478 $fldname = attr("form_$field_id");
4480 if ($data_type == 40) {
4481 $fldid = "form_" . $field_id;
4482 // Move canvas image data to its hidden form field so the server will get it.
4484 " var canfld = f[" . js_escape($fldid) . "];\n" .
4485 " if (canfld) canfld.value = lbfCanvasGetData(" . js_escape($fldid) . ");\n";
4488 if ($data_type == 41 ||
$data_type == 42) {
4489 $fldid = "form_" . $field_id;
4490 // Move canvas image data to its hidden form field so the server will get it.
4491 echo " lbfSetSignature(" . js_escape($fldid) . ");\n";
4494 if ($frow['uor'] < 2) {
4498 echo " if (f.$fldname && !f.$fldname.disabled) {\n";
4499 switch ($data_type) {
4507 " if (f.$fldname.selectedIndex <= 0) {\n" .
4508 " alert(" . xlj('Please choose a value for') . " + " .
4509 "\":\\n\" + " . js_escape(xl_layout_label($fldtitle)) . ");\n" .
4510 " if (f.$fldname.focus) f.$fldname.focus();\n" .
4511 " return false;\n" .
4516 " if (f.$fldname.selectedIndex <= 0) {\n" .
4517 " if (f.$fldname.focus) f.$fldname.focus();\n" .
4518 " errMsgs[errMsgs.length] = " . js_escape(xl_layout_label($fldtitle)) . "; \n" .
4521 case 27: // radio buttons
4524 " for (; i < f.$fldname.length; ++i) if (f.{$fldname}[i].checked) break;\n" .
4525 " if (i >= f.$fldname.length) {\n" .
4526 " alert(" . xlj('Please choose a value for') . " + " .
4527 "\":\\n\" + " . js_escape(xl_layout_label($fldtitle)) . ");\n" .
4528 " return false;\n" .
4536 " if (trimlen(f.$fldname.value) == 0) {\n" .
4537 " if (f.$fldname.focus) f.$fldname.focus();\n" .
4538 " $('#" . $fldname . "').parents('div.tab').each( function(){ var tabHeader = $('#header_' + $(this).attr('id') ); tabHeader.css('color','var(--danger)'); } ); " .
4539 " $('#" . $fldname . "').attr('style','background: var(--danger)'); \n" .
4540 " errMsgs[errMsgs.length] = " . js_escape(xl_layout_label($fldtitle)) . "; \n" .
4542 " $('#" . $fldname . "').attr('style',''); " .
4543 " $('#" . $fldname . "').parents('div.tab').each( function(){ var tabHeader = $('#header_' + $(this).attr('id') ); tabHeader.css('color',''); } ); " .
4546 case 36: // multi select
4548 " var multi_select=f['$fldname" . "[]']; \n " .
4549 " var multi_choice_made=false; \n" .
4550 " for (var options_index=0; options_index < multi_select.length; options_index++) { " .
4551 " multi_choice_made=multi_choice_made || multi_select.options[options_index].selected; \n" .
4553 " if(!multi_choice_made)
4554 errMsgs[errMsgs.length] = " . js_escape(xl_layout_label($fldtitle)) . "; \n" .
4560 } // End this layout, there may be more in the case of history.
4564 * DROPDOWN FOR FACILITIES
4566 * build a dropdown with all facilities
4568 * @param string $selected - name of the currently selected facility
4569 * use '0' for "unspecified facility"
4570 * use '' for "All facilities" (the default)
4571 * @param string $name - the name/id for select form (defaults to "form_facility")
4572 * @param boolean $allow_unspecified - include an option for "unspecified" facility
4574 * @return void - just echo the html encoded string
4576 * Note: This should become a data-type at some point, according to Brady
4578 function dropdown_facility(
4580 $name = 'form_facility',
4581 $allow_unspecified = true,
4582 $allow_allfacilities = true,
4588 global $facilityService;
4590 $have_selected = false;
4591 $fres = $facilityService->getAllFacility();
4595 $name = $name . "[]";
4597 echo " <select class='form-control$class";
4599 echo " select-dropdown";
4601 echo "' name='" . attr($name) . "' id='" . attr($id) . "'";
4603 echo " onchange='$onchange'";
4607 echo " multiple='multiple'";
4610 echo " $disabled>\n";
4612 if ($allow_allfacilities) {
4614 $option_selected_attr = '';
4615 if ($selected == '') {
4616 $option_selected_attr = ' selected="selected"';
4617 $have_selected = true;
4620 $option_content = '-- ' . xl('All Facilities') . ' --';
4621 echo " <option value='" . attr($option_value) . "' $option_selected_attr>" . text($option_content) . "</option>\n";
4622 } elseif ($allow_unspecified) {
4623 $option_value = '0';
4624 $option_selected_attr = '';
4625 if ($selected == '0') {
4626 $option_selected_attr = ' selected="selected"';
4627 $have_selected = true;
4630 $option_content = '-- ' . xl('Unspecified') . ' --';
4631 echo " <option value='" . attr($option_value) . "' $option_selected_attr>" . text($option_content) . "</option>\n";
4634 foreach ($fres as $frow) {
4635 $facility_id = $frow['id'];
4636 $option_value = $facility_id;
4637 $option_selected_attr = '';
4639 $selectedValues = explode("|", $selected);
4641 if (in_array($facility_id, $selectedValues)) {
4642 $option_selected_attr = ' selected="selected"';
4643 $have_selected = true;
4646 if ($selected == $facility_id) {
4647 $option_selected_attr = ' selected="selected"';
4648 $have_selected = true;
4652 $option_content = $frow['name'];
4653 echo " <option value='" . attr($option_value) . "' $option_selected_attr>" . text($option_content) . "</option>\n";
4656 if ($allow_unspecified && $allow_allfacilities) {
4657 $option_value = '0';
4658 $option_selected_attr = '';
4659 if ($selected == '0') {
4660 $option_selected_attr = ' selected="selected"';
4661 $have_selected = true;
4664 $option_content = '-- ' . xl('Unspecified') . ' --';
4665 echo " <option value='" . attr($option_value) . "' $option_selected_attr>" . text($option_content) . "</option>\n";
4668 if (!$have_selected && !$multiple) {
4669 $option_value = $selected;
4670 $option_label = '(' . xl('Do not change') . ')';
4671 $option_content = xl('Missing or Invalid');
4672 echo " <option value='" . attr($option_value) . "' label='" . attr($option_label) . "' selected='selected'>" . text($option_content) . "</option>\n";
4675 echo " </select>\n";
4679 * Expand Collapse Widget
4680 * This forms the header and functionality component of the widget. The information that is displayed
4681 * then follows this function followed by a closing div tag
4683 * @var $title is the title of the section (already translated)
4684 * @var $label is identifier used in the tag id's and sql columns
4685 * @var $buttonLabel is the button label text (already translated)
4686 * @var $buttonLink is the button link information
4687 * @var $buttonClass is any additional needed class elements for the button tag
4688 * @var $linkMethod is the button link method ('javascript' vs 'html')
4689 * @var $bodyClass is to set class(es) of the body
4690 * @var $auth is a flag to decide whether to show the button
4691 * @var $fixedWidth is to flag whether width is fixed
4692 * @var $forceExpandAlways is a flag to force the widget to always be expanded
4694 * @todo Convert to a modern layout
4696 function expand_collapse_widget($title, $label, $buttonLabel, $buttonLink, $buttonClass, $linkMethod, $bodyClass, $auth, $fixedWidth, $forceExpandAlways = false)
4699 echo "<div class='section-header'>";
4701 echo "<div class='section-header-dynamic'>";
4706 // show button, since authorized
4707 // first prepare class string
4709 $class_string = "btn btn-primary btn-sm " . $buttonClass;
4711 $class_string = "btn btn-primary btn-sm";
4714 // next, create the link
4715 if ($linkMethod == "javascript") {
4716 echo "<td><a class='" . attr($class_string) . "' href='javascript:;' onclick='" . $buttonLink . "'";
4718 echo "<td><a class='" . attr($class_string) . "' href='" . $buttonLink . "'";
4719 if (!isset($_SESSION['patient_portal_onsite_two'])) {
4720 // prevent an error from occuring when calling the function from the patient portal
4721 echo " onclick='top.restoreSession()'";
4726 text($buttonLabel) . "</span></a></td>";
4729 if ($forceExpandAlways) {
4730 // Special case to force the widget to always be expanded
4731 echo "<td><span class='text font-weight-bold'>" . text($title) . "</span>";
4732 $indicatorTag = "style='display: none'";
4735 $indicatorTag = isset($indicatorTag) ?
$indicatorTag : "";
4736 echo "<td><a " . $indicatorTag . " href='javascript:;' class='small' onclick='toggleIndicator(this," .
4737 attr_js($label . "_ps_expand") . ")'><span class='text font-weight-bold'>";
4738 echo text($title) . "</span>";
4740 if (isset($_SESSION['patient_portal_onsite_two'])) {
4741 // collapse all entries in the patient portal
4742 $text = xl('expand');
4743 } elseif (getUserSetting($label . "_ps_expand")) {
4744 $text = xl('collapse');
4746 $text = xl('expand');
4749 echo " (<span class='indicator'>" . text($text) .
4750 "</span>)</a></td>";
4751 echo "</tr></table>";
4753 if ($forceExpandAlways) {
4754 // Special case to force the widget to always be expanded
4756 } elseif (isset($_SESSION['patient_portal_onsite_two'])) {
4757 // collapse all entries in the patient portal
4758 $styling = "style='display: none'";
4759 } elseif (getUserSetting($label . "_ps_expand")) {
4762 $styling = "style='display: none'";
4766 $styling .= " class='" . attr($bodyClass) . "'";
4769 //next, create the first div tag to hold the information
4770 // note the code that calls this function will then place the ending div tag after the data
4771 echo "<div id='" . attr($label) . "_ps_expand' " . $styling . ">";
4774 //billing_facility fuction will give the dropdown list which contain billing faciliies.
4775 function billing_facility($name, $select)
4777 global $facilityService;
4779 $fres = $facilityService->getAllBillingLocations();
4780 echo " <select id='" . htmlspecialchars($name, ENT_QUOTES
) . "' class='form-control' name='" . htmlspecialchars($name, ENT_QUOTES
) . "'>";
4781 foreach ($fres as $facrow) {
4782 $selected = ( $facrow['id'] == $select ) ?
'selected="selected"' : '' ;
4783 echo "<option value=" . htmlspecialchars($facrow['id'], ENT_QUOTES
) . " $selected>" . htmlspecialchars($facrow['name'], ENT_QUOTES
) . "</option>";
4789 // Generic function to get the translated title value for a particular list option.
4791 function getListItemTitle($list, $option)
4793 return LayoutsUtils
::getListItemTitle($list, $option);
4796 //function to get the translated title value in Patient Transactions
4797 function getLayoutTitle($list, $option)
4799 $row = sqlQuery("SELECT grp_title FROM layout_group_properties " .
4800 "WHERE grp_mapping = ? AND grp_form_id = ? ", array($list, $option));
4802 if (empty($row['grp_title'])) {
4805 return xl_list_label($row['grp_title']);
4807 //Added on 5-jun-2k14 (regarding get the smoking code descriptions)
4808 function getSmokeCodes()
4810 $smoking_codes_arr = array();
4811 $smoking_codes = sqlStatement("SELECT option_id,codes FROM list_options WHERE list_id='smoking_status' AND activity = 1");
4812 while ($codes_row = sqlFetchArray($smoking_codes)) {
4813 $smoking_codes_arr[$codes_row['option_id']] = $codes_row['codes'];
4816 return $smoking_codes_arr;
4819 // Get the current value for a layout based form field.
4820 // Depending on options this might come from lbf_data, patient_data,
4821 // form_encounter, shared_attributes or elsewhere.
4822 // Returns FALSE if the field ID is invalid (layout error).
4824 function lbf_current_value($frow, $formid, $encounter)
4827 $formname = $frow['form_id'];
4828 $field_id = $frow['field_id'];
4829 $source = $frow['source'];
4831 $deffname = $formname . '_default_' . $field_id;
4832 if ($source == 'D' ||
$source == 'H') {
4833 // Get from patient_data, employer_data or history_data.
4834 if ($source == 'H') {
4835 $table = 'history_data';
4836 $orderby = 'ORDER BY date DESC LIMIT 1';
4837 } elseif (strpos($field_id, 'em_') === 0) {
4838 $field_id = substr($field_id, 3);
4839 $table = 'employer_data';
4840 $orderby = 'ORDER BY date DESC LIMIT 1';
4842 $table = 'patient_data';
4846 // It is an error if the field does not exist, but don't crash.
4847 $tmp = sqlQuery("SHOW COLUMNS FROM " . escape_table_name($table) . " WHERE Field = ?", array($field_id));
4852 $pdrow = sqlQuery("SELECT `$field_id` AS field_value FROM " . escape_table_name($table) . " WHERE pid = ? $orderby", array($pid));
4853 if (isset($pdrow)) {
4854 $currvalue = $pdrow['field_value'];
4856 } elseif ($source == 'E') {
4859 // Get value from shared_attributes of the current encounter.
4861 "SELECT field_value FROM shared_attributes WHERE " .
4862 "pid = ? AND encounter = ? AND field_id = ?",
4863 array($pid, $encounter, $field_id)
4865 if (!empty($sarow)) {
4866 $currvalue = $sarow['field_value'];
4868 } elseif ($formid) {
4869 // Get from shared_attributes of the encounter that this form is linked to.
4870 // Note the importance of having an index on forms.form_id.
4872 "SELECT sa.field_value " .
4873 "FROM forms AS f, shared_attributes AS sa WHERE " .
4874 "f.form_id = ? AND f.formdir = ? AND f.deleted = 0 AND " .
4875 "sa.pid = f.pid AND sa.encounter = f.encounter AND sa.field_id = ?",
4876 array($formid, $formname, $field_id)
4878 if (!empty($sarow)) {
4879 $currvalue = $sarow['field_value'];
4882 // New form and encounter not available, this should not happen.
4884 if (empty($sarow) && !$formid) {
4885 // New form, see if there is a custom default from a plugin.
4886 if (function_exists($deffname)) {
4887 $currvalue = call_user_func($deffname);
4890 } elseif ($source == 'V') {
4892 // Get value from the current encounter's form_encounter.
4894 "SELECT * FROM form_encounter WHERE " .
4895 "pid = ? AND encounter = ?",
4896 array($pid, $encounter)
4898 if (isset($ferow[$field_id])) {
4899 $currvalue = $ferow[$field_id];
4901 } elseif ($formid) {
4902 // Get value from the form_encounter that this form is linked to.
4905 "FROM forms AS f, form_encounter AS fe WHERE " .
4906 "f.form_id = ? AND f.formdir = ? AND f.deleted = 0 AND " .
4907 "fe.pid = f.pid AND fe.encounter = f.encounter",
4908 array($formid, $formname)
4910 if (isset($ferow[$field_id])) {
4911 $currvalue = $ferow[$field_id];
4914 // New form and encounter not available, this should not happen.
4916 } elseif ($formid) {
4917 // This is a normal form field.
4918 $ldrow = sqlQuery("SELECT field_value FROM lbf_data WHERE " .
4919 "form_id = ? AND field_id = ?", array($formid, $field_id));
4920 if (!empty($ldrow)) {
4921 $currvalue = $ldrow['field_value'];
4924 // New form, see if there is a custom default from a plugin.
4925 if (function_exists($deffname)) {
4926 $currvalue = call_user_func($deffname);
4933 function signer_head()
4936 <link href="{$GLOBALS['web_root']}/portal/sign/css/signer_modal.css?v={$GLOBALS['v_js_includes']}" rel="stylesheet"/>
4937 <script src="{$GLOBALS['web_root']}/portal/sign/assets/signature_pad.umd.js?v={$GLOBALS['v_js_includes']}"></script>
4938 <script src="{$GLOBALS['web_root']}/portal/sign/assets/signer_api.js?v={$GLOBALS['v_js_includes']}"></script>
4942 // This returns stuff that needs to go into the <head> section of a caller using
4943 // the drawable image field type in a form.
4944 // A TRUE argument makes the widget controls smaller.
4946 function lbf_canvas_head($small = true)
4949 <link href="{$GLOBALS['assets_static_relative']}/literallycanvas/css/literallycanvas.css" rel="stylesheet" />
4950 <script src="{$GLOBALS['assets_static_relative']}/react/build/react-with-addons.min.js"></script>
4951 <script src="{$GLOBALS['assets_static_relative']}/react/build/react-dom.min.js"></script>
4952 <script src="{$GLOBALS['assets_static_relative']}/literallycanvas/js/literallycanvas.min.js"></script>
4957 /* Custom LiterallyCanvas styling.
4958 * This makes the widget 25% less tall and adjusts some other things accordingly.
4962 min-width: 300px; /* Was 400, unspecified */
4964 .literally .lc-picker .toolbar-button {
4967 line-height: 20px; /* Was 26, 26, 26 */
4969 .literally .color-well {
4971 width: 49px; /* Was 10, 60 */
4973 .literally .color-well-color-container {
4975 height: 21px; /* Was 28, 28 */
4977 .literally .lc-picker {
4978 width: 50px; /* Was 61 */
4980 .literally .lc-drawing.with-gui {
4981 left: 50px; /* Was 61 */
4983 .literally .lc-options {
4984 left: 50px; /* Was 61 */
4986 .literally .color-picker-popup {
4988 bottom: 0px; /* Was 60, 31 */
4998 * Test if modifier($test) is in array of options for data type.
5000 * @param json array $options ["G","P","T"], ["G"] or could be legacy string with form "GPT", "G", "012"
5001 * @param string $test
5004 function isOption($options, string $test): bool
5006 if (empty($options) ||
!isset($test) ||
$options == "null") {
5007 return false; // why bother?
5009 if (strpos($options, ',') === false) { // not json array of modifiers.
5010 // could be string of char's or single element of json ["RO"] or "TP" or "P" e.t.c.
5011 json_decode($options, true); // test if options json. json_last_error() will return JSON_ERROR_SYNTAX if not.
5012 // if of form ["RO"] (single modifier) means not legacy so continue on.
5013 if (is_string($options) && (json_last_error() !== JSON_ERROR_NONE
)) { // nope, it's string.
5014 $t = str_split(trim($options)); // very good chance it's legacy modifier string.
5015 $options = json_encode($t); // make it json array to convert from legacy to new modifier json schema.
5019 $options = json_decode($options, true); // all should now be json
5021 return is_array($options) && in_array($test, $options, true); // finally the truth!