4 * Script for the globals editor.
7 * @link http://www.open-emr.org
8 * @author Rod Roark <rod@sunsetsystems.com>
9 * @author Brady Miller <brady.g.miller@gmail.com>
10 * @author Ranganath Pathak <pathak@scrs1.org>
11 * @author Jerry Padgett <sjpadgett@gmail.com>
12 * @author Stephen Nielson <snielson@discoverandchange.com>
13 * @copyright Copyright (c) 2010 Rod Roark <rod@sunsetsystems.com>
14 * @copyright Copyright (c) 2016-2019 Brady Miller <brady.g.miller@gmail.com>
15 * @copyright Copyright (c) 2019 Ranganath Pathak <pathak@scrs1.org>
16 * @copyright Copyright (c) 2020-2024 Jerry Padgett <sjpadgett@gmail.com>
17 * @copyright Copyright (c) 2022 Discover and Change <snielson@discoverandchange.com>
18 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
21 require_once("../globals.php");
22 require_once("../../custom/code_types.inc.php");
23 require_once("$srcdir/globals.inc.php");
24 require_once("$srcdir/user.inc.php");
26 use OpenEMR\Common\Acl\AclMain
;
27 use OpenEMR\Common\Auth\AuthHash
;
28 use OpenEMR\Common\Crypto\CryptoGen
;
29 use OpenEMR\Common\Csrf\CsrfUtils
;
30 use OpenEMR\Common\Logging\EventAuditLogger
;
31 use OpenEMR\Common\Twig\TwigContainer
;
32 use OpenEMR\Core\Header
;
33 use OpenEMR\FHIR\Config\ServerConfig
;
34 use OpenEMR\OeUI\OemrUI
;
35 use OpenEMR\Services\Globals\GlobalSetting
;
39 // Set up crypto object
40 $cryptoGen = new CryptoGen();
42 $userMode = (array_key_exists('mode', $_GET) && $_GET['mode'] == 'user');
45 // Check authorization.
46 $thisauth = AclMain
::aclCheckCore('admin', 'super');
48 echo (new TwigContainer(null, $GLOBALS['kernel']))->getTwig()->render('core/unauthorized.html.twig', ['pageTitle' => xl("Configuration")]);
53 function checkCreateCDB()
55 $globalsres = sqlStatement("SELECT gl_name, gl_index, gl_value FROM globals WHERE gl_name IN
56 ('couchdb_host','couchdb_user','couchdb_pass','couchdb_port','couchdb_dbase','document_storage_method')");
58 while ($globalsrow = sqlFetchArray($globalsres)) {
59 $GLOBALS[$globalsrow['gl_name']] = $globalsrow['gl_value'];
62 $directory_created = false;
63 if (!empty($GLOBALS['document_storage_method'])) {
64 // /documents/temp/ folder is required for CouchDB
65 if (!is_dir($GLOBALS['OE_SITE_DIR'] . '/documents/temp/')) {
66 $directory_created = mkdir($GLOBALS['OE_SITE_DIR'] . '/documents/temp/', 0777, true);
67 if (!$directory_created) {
68 echo xlt("Failed to create temporary folder. CouchDB will not work.");
72 $couch = new CouchDB();
73 if (!$couch->check_connection()) {
74 echo "<script>alert(" . xlj("CouchDB Connection Failed.") . ");</script>";
78 if ($GLOBALS['couchdb_host'] ||
$GLOBALS['couchdb_port'] ||
$GLOBALS['couchdb_dbase']) {
87 * Update background_services table for a specific service following globals save.
90 function updateBackgroundService($name, $active, $interval)
92 //order important here: next_run change dependent on _old_ value of execute_interval so it comes first
93 $sql = 'UPDATE background_services SET active=?, '
94 . 'next_run = next_run + INTERVAL (? - execute_interval) MINUTE, execute_interval=? WHERE name=?';
95 return sqlStatement($sql, array($active,$interval,$interval,$name));
99 * Make any necessary changes to background_services table when globals are saved.
100 * To prevent an unexpected service call during startup or shutdown, follow these rules:
101 * 1. Any "startup" operations should occur _before_ the updateBackgroundService() call.
102 * 2. Any "shutdown" operations should occur _after_ the updateBackgroundService() call. If these operations
103 * would cause errors in a running service call, it would be best to make the shutdown function itself is
104 * a background service that is activated here, does nothing if active=1 or running=1 for the
105 * parent service. Then it deactivates itself by setting active=0 when it is done shutting the parent service
106 * down. This will prevent non-responsiveness to the user by waiting for a service to finish.
107 * 3. If any "previous" values for globals are required for startup/shutdown logic, they need to be
108 * copied to a temp variable before the while($globalsrow...) loop.
111 function checkBackgroundServices()
113 //load up any necessary globals
114 $bgservices = sqlStatement(
115 "SELECT gl_name, gl_index, gl_value FROM globals WHERE gl_name IN
119 'auto_sftp_claims_to_x12_partner',
123 while ($globalsrow = sqlFetchArray($bgservices)) {
124 $GLOBALS[$globalsrow['gl_name']] = $globalsrow['gl_value'];
127 //Set up phimail service
128 $phimail_active = empty($GLOBALS['phimail_enable']) ?
'0' : '1';
129 $phimail_interval = max(0, (int) $GLOBALS['phimail_interval']);
130 updateBackgroundService('phimail', $phimail_active, $phimail_interval);
132 // When auto SFTP is enabled in globals, set up background task to run every minute
133 // to check for claims in the 'waiting' status.
134 // See library/billing_sftp_service.php for the entry point to this service.
135 // It is very lightweight if there is no work to do, so running every minute should
136 // be OK to provider users with the best experience.
137 $auto_sftp_x12 = empty($GLOBALS['auto_sftp_claims_to_x12_partner']) ?
'0' : '1';
138 updateBackgroundService('X12_SFTP', $auto_sftp_x12, 1);
141 * Setup background services for Weno when it is enabled
142 * this is to sync the prescription logs
144 $wenoservices = ($GLOBALS['weno_rx_enable'] ??
'') == 1 ?
'1' : '0';
145 updateBackgroundService('WenoExchange', $wenoservices, 60);
146 updateBackgroundService('WenoExchangePharmacies', $wenoservices, 1440);
153 // If we are saving user_specific globals.
155 if (array_key_exists('form_save', $_POST) && $_POST['form_save'] && $userMode) {
157 if (!CsrfUtils
::verifyCsrfToken($_POST["csrf_token_form"])) {
158 CsrfUtils
::csrfNotVerified();
162 foreach ($GLOBALS_METADATA as $grpname => $grparr) {
163 if (in_array($grpname, $USER_SPECIFIC_TABS)) {
164 foreach ($grparr as $fldid => $fldarr) {
165 if (in_array($fldid, $USER_SPECIFIC_GLOBALS)) {
166 list($fldname, $fldtype, $flddef, $flddesc) = $fldarr;
167 $label = "global:" . $fldid;
168 if ($fldtype == "encrypted") {
169 if (empty(trim($_POST["form_$i"]))) {
172 $fldvalue = $cryptoGen->encryptStandard(trim($_POST["form_$i"]));
174 } elseif ($fldtype == "encrypted_hash") {
175 $tmpValue = trim($_POST["form_$i"]);
176 if (empty($tmpValue)) {
179 if (!AuthHash
::hashValid($tmpValue)) {
180 // a new value has been inputted, so create the hash that will then be stored
181 $tmpValue = (new AuthHash())->passwordHash($tmpValue);
183 $fldvalue = $cryptoGen->encryptStandard($tmpValue);
186 $fldvalue = trim($_POST["form_$i"] ??
'');
188 setUserSetting($label, $fldvalue, $_SESSION['authUserID'], false);
189 if ($_POST["toggle_$i"] ??
'' == "YES") {
190 removeUserSetting($label);
200 echo "if (parent.left_nav.location) {";
201 echo " parent.left_nav.location.reload();";
202 echo " parent.Title.location.reload();";
203 echo " if(self.name=='RTop'){";
204 echo " parent.RBot.location.reload();";
206 echo " parent.RTop.location.reload();";
209 echo "self.location.href='edit_globals.php?mode=user&unique=yes';";
215 // If we are saving main globals.
217 if (array_key_exists('form_save', $_POST) && $_POST['form_save'] && !$userMode) {
219 if (!CsrfUtils
::verifyCsrfToken($_POST["csrf_token_form"])) {
220 CsrfUtils
::csrfNotVerified();
223 // Aug 22, 2014: Ensoftek: For Auditable events and tamper-resistance (MU2)
224 // Check the current status of Audit Logging
225 $auditLogStatusFieldOld = $GLOBALS['enable_auditlog'];
226 $forceBreakglassLogStatusFieldOld = $GLOBALS['gbl_force_log_breakglass'];
229 * Compare form values with old database values.
230 * Only save if values differ. Improves speed.
233 // Get all the globals from DB
234 $old_globals = sqlGetAssoc('SELECT gl_name, gl_index, gl_value FROM `globals` ORDER BY gl_name, gl_index', false, true);
236 sqlStatementNoLog('SET autocommit=0');
237 sqlStatementNoLog('START TRANSACTION');
239 foreach ($GLOBALS_METADATA as $grpname => $grparr) {
240 foreach ($grparr as $fldid => $fldarr) {
241 list($fldname, $fldtype, $flddef, $flddesc) = $fldarr;
242 /* Multiple choice fields - do not compare , overwrite */
243 if (!is_array($fldtype) && substr($fldtype, 0, 2) == 'm_') {
244 if (isset($_POST["form_$i"])) {
247 sqlStatement("DELETE FROM globals WHERE gl_name = ?", array( $fldid ));
249 foreach ($_POST["form_$i"] as $fldvalue) {
250 $fldvalue = trim($fldvalue);
251 sqlStatement('INSERT INTO `globals` ( gl_name, gl_index, gl_value ) VALUES ( ?,?,?)', array( $fldid, $fldindex, $fldvalue ));
256 /* check value of single field. Don't update if the database holds the same value */
257 if (isset($_POST["form_$i"])) {
258 $fldvalue = trim($_POST["form_$i"]);
263 if ($fldtype == 'encrypted') {
264 if (empty(trim($fldvalue))) {
267 $fldvalue = $cryptoGen->encryptStandard($fldvalue);
269 } elseif ($fldtype == 'encrypted_hash') {
270 $tmpValue = trim($fldvalue);
271 if (empty($tmpValue)) {
274 if (!AuthHash
::hashValid($tmpValue)) {
275 // a new value has been inputted, so create the hash that will then be stored
276 $tmpValue = (new AuthHash())->passwordHash($tmpValue);
278 $fldvalue = $cryptoGen->encryptStandard($tmpValue);
282 // We rely on the fact that set of keys in globals.inc.php === set of keys in `globals` table!
284 !isset($old_globals[$fldid]) // if the key not found in database - update database
286 ( isset($old_globals[$fldid]) && $old_globals[ $fldid ]['gl_value'] !== $fldvalue ) // if the value in database is different
288 // special treatment for some vars
290 case 'first_day_week':
291 // update PostCalendar config as well
292 sqlStatement("UPDATE openemr_module_vars SET pn_value = ? WHERE pn_name = 'pcFirstDayOfWeek'", array($fldvalue));
296 // Replace old values
297 sqlStatement('DELETE FROM `globals` WHERE gl_name = ?', array( $fldid ));
298 sqlStatement('INSERT INTO `globals` ( gl_name, gl_index, gl_value ) VALUES ( ?, ?, ? )', array( $fldid, 0, $fldvalue ));
300 //error_log("No need to update $fldid");
307 // end of transaction
308 sqlStatementNoLog('COMMIT');
309 sqlStatementNoLog('SET autocommit=1');
312 checkBackgroundServices();
314 // July 1, 2014: Ensoftek: For Auditable events and tamper-resistance (MU2)
315 // If Audit Logging status has changed, log it.
316 $auditLogStatusNew = sqlQuery("SELECT `gl_value` FROM `globals` WHERE `gl_name` = 'enable_auditlog'");
317 $auditLogStatusFieldNew = $auditLogStatusNew['gl_value'];
318 if ($auditLogStatusFieldOld != $auditLogStatusFieldNew) {
319 EventAuditLogger
::instance()->auditSQLAuditTamper('enable_auditlog', $auditLogStatusFieldNew);
321 $forceBreakglassLogStatusNew = sqlQuery("SELECT `gl_value` FROM `globals` WHERE `gl_name` = 'gbl_force_log_breakglass'");
322 $forceBreakglassLogStatusFieldNew = $forceBreakglassLogStatusNew['gl_value'];
323 if ($forceBreakglassLogStatusFieldOld != $forceBreakglassLogStatusFieldNew) {
324 EventAuditLogger
::instance()->auditSQLAuditTamper('gbl_force_log_breakglass', $forceBreakglassLogStatusFieldNew);
328 echo "if (parent.left_nav.location) {";
329 echo " parent.left_nav.location.reload();";
330 echo " parent.Title.location.reload();";
331 echo " if(self.name=='RTop'){";
332 echo " parent.RBot.location.reload();";
334 echo " parent.RTop.location.reload();";
337 echo "self.location.href='edit_globals.php?unique=yes';";
341 $title = ($userMode) ?
xlt("User Settings") : xlt("Configuration");
343 <title
><?php
echo $title; ?
></title
>
344 <?php Header
::setupHeader(['common','jscolor']); ?
>
352 @media
(max
-width
: 576px
) {
357 #globals-div .tabContainer {
363 $heading_title = ($userMode) ?
xl("Edit User Settings") : xl("Edit Configuration");
365 $arrOeUiSettings = array(
366 'heading_title' => $heading_title,
367 'include_patient_name' => false,// use only in appropriate pages
368 'expandable' => true,
369 'expandable_files' => array("edit_globals_xpd"),//all file names need suffix _xpd
370 'action' => "",//conceal, reveal, search, reset, link or back
371 'action_title' => "",
372 'action_href' => "",//only for actions - reset, link or back
373 'show_help_icon' => false,
374 'help_file_name' => ""
376 $oemr_ui = new OemrUI($arrOeUiSettings);
377 $serverConfig = new ServerConfig();
378 $apiUrl = $serverConfig->getInternalBaseApiUrl();
380 <script src
="edit_globals.js" type
="text/javascript"></script
>
382 window
.oeUI
.api
.setApiUrlAndCsrfToken(<?php
echo js_escape($apiUrl); ?
>, <?php
echo js_escape(CsrfUtils
::collectCsrfToken('api')); ?
>);
386 <body
<?php
if ($userMode) {
387 echo 'style="min-width: 700px;"';
390 <div id
="container_div" class="<?php echo $oemr_ui->oeContainer();?> mt-2">
392 <div
class="col-sm-12 px-0 my-2">
393 <?php
echo $oemr_ui->pageHeading() . "\r\n"; ?
>
397 <div
class="col-sm-12 px-0">
398 <?php
if ($userMode) { ?
>
399 <form method
='post' name
='theform' id
='theform' class='form-horizontal' action
='edit_globals.php?mode=user' onsubmit
='return top.restoreSession()'>
401 <form method
='post' name
='theform' id
='theform' class='form-horizontal' action
='edit_globals.php' onsubmit
='return top.restoreSession()'>
403 <input type
="hidden" name
="csrf_token_form" value
="<?php echo attr(CsrfUtils::collectCsrfToken()); ?>" />
404 <div
class="clearfix">
405 <div
class="btn-group oe-margin-b-10">
406 <button type
='submit' class='btn btn-primary btn-save oe-pull-toward' name
='form_save' value
='<?php echo xla('Save
'); ?>'><?php
echo xlt('Save'); ?
></button
>
408 <div
class="input-group col-sm-4 oe-pull-away p-0">
409 <?php
// mdsupport - Optional server based searching mechanism for large number of fields on this screen.
411 $placeholder = xla('Search configuration');
413 $placeholder = xla('Search user settings');
416 <input name
='srch_desc' id
='srch_desc' class='form-control' type
='text' placeholder
='<?php echo $placeholder; ?>' value
='<?php echo (!empty($_POST['srch_desc
']) ? attr($_POST['srch_desc
']) : '') ?>' />
417 <span
class="input-group-append">
418 <button
class="btn btn-secondary btn-search" type
='submit' id
='globals_form_search' name
='form_search'><?php
echo xlt('Search'); ?
></button
>
420 </div
><!-- /input
-group
-->
423 <div id
="globals-div">
424 <ul
class="tabNav tabWidthWide sticky-top" id
="oe-nav-ul">
427 foreach ($GLOBALS_METADATA as $grpname => $grparr) {
428 if (!$userMode ||
in_array($grpname, $USER_SPECIFIC_TABS)) {
429 echo " <li" . ($i ?
"" : " class='current'") .
431 xlt($grpname) . "</a></li>\n";
437 <div
class="tabContainer">
441 foreach ($GLOBALS_METADATA as $grpname => $grparr) {
442 if (!$userMode ||
in_array($grpname, $USER_SPECIFIC_TABS)) {
443 echo " <div class='tab w-100 h-auto" . ($i ?
"" : " current") . "' style='font-size: 0.9rem'>\n";
445 echo "<div class=''>";
446 $addendum = $grpname == 'Appearance' ?
' (*' . xl("need to logout/login after changing these settings") . ')' : '';
447 echo "<div class='col-sm-12 oe-global-tab-heading'><div class='oe-pull-toward' style='font-size: 1.4rem'>" . xlt($grpname) . " </div><div style='margin-top: 5px'>" . text($addendum) . "</div></div>";
448 echo "<div class='clearfix'></div>";
450 echo "<div class='row'>";
451 echo "<div class='col-sm-4'> </div>";
452 echo "<div class='col-sm-4 font-weight-bold'>" . xlt('User Specific Setting') . "</div>";
453 echo "<div class='col-sm-2 font-weight-bold'>" . xlt('Default Setting') . "</div>";
454 echo "<div class='col-sm-2 font-weight-bold'>" . xlt('Default') . "</div>";
458 foreach ($grparr as $fldid => $fldarr) {
459 if (!$userMode ||
in_array($fldid, $USER_SPECIFIC_GLOBALS)) {
460 list($fldname, $fldtype, $flddef, $flddesc) = $fldarr;
462 // if the setting defines field options for our global setting we grab it, otherwise we default empty
463 $fldoptions = $fldarr[4] ??
[];
465 // mdsupport - Check for matches
467 $highlight_search = false;
469 if (!empty($_POST['srch_desc']) && (stristr(($fldname . $flddesc), $_POST['srch_desc']) !== false)) {
472 $highlight_search = true;
475 // Most parameters will have a single value, but some will be arrays.
476 // Here we cater to both possibilities.
477 $glres = sqlStatement("SELECT gl_index, gl_value FROM globals WHERE " .
478 "gl_name = ? ORDER BY gl_index", array($fldid));
480 while ($glrow = sqlFetchArray($glres)) {
484 // $fldvalue is meaningful only for the single-value cases.
485 $fldvalue = count($glarr) ?
$glarr[0]['gl_value'] : $flddef;
487 // Collect user specific setting if mode set to user
489 $settingDefault = "checked='checked'";
491 $userSettingArray = sqlQuery("SELECT * FROM user_settings WHERE setting_user=? AND setting_label=?", array($_SESSION['authUserID'],"global:" . $fldid));
492 $userSetting = $userSettingArray['setting_value'] ??
'';
493 $globalValue = $fldvalue;
494 if (!empty($userSettingArray)) {
495 $fldvalue = $userSetting;
496 $settingDefault = "";
499 if ($fldtype == GlobalSetting
::DATA_TYPE_HTML_DISPLAY_SECTION
) {
500 // if the field is an html display box we want to take over the entire real estate so we will continue from here.
501 include_once 'templates/field_html_display_section.php';
502 ++
$i; // make sure we advance the iterator here...
507 echo " <div class='row form-group" . $srch_cl . "'><div class='col-sm-4'>" . ($highlight_search ?
'<mark>' : '') . text($fldname) . ($highlight_search ?
'</mark>' : '') . "</div><div class='col-sm-4 oe-input' title='" . attr($flddesc) . "'>\n";
509 echo " <div class='row form-group" . $srch_cl . "'><div class='col-sm-6'>" . ($highlight_search ?
'<mark>' : '') . text($fldname) . ($highlight_search ?
'</mark>' : '') . "</div><div class='col-sm-6 oe-input' title='" . attr($flddesc) . "'>\n";
512 if (is_array($fldtype)) {
513 echo " <select class='form-control' name='form_$i' id='form_$i'>\n";
514 foreach ($fldtype as $key => $value) {
516 if ($globalValue == $key) {
517 $globalTitle = $value;
521 echo " <option value='" . attr($key) . "'";
523 //Casting value to string so the comparison will be always the same type and the only thing that will check is the value
524 //Tried to use === but it will fail in already existing variables
525 if ((string)$key == (string)$fldvalue) {
534 } elseif ($fldtype == GlobalSetting
::DATA_TYPE_BOOL
) {
536 if ($globalValue == 1) {
537 $globalTitle = xlt('Checked');
539 $globalTitle = xlt('Not Checked');
542 echo " <input type='checkbox' class='checkbox' name='form_$i' id='form_$i' value='1'";
547 } elseif ($fldtype == GlobalSetting
::DATA_TYPE_NUMBER
) {
549 $globalTitle = $globalValue;
551 echo " <input type='text' class='form-control' name='form_$i' id='form_$i' " .
552 "maxlength='15' value='" . attr($fldvalue) . "' />\n";
553 } elseif ($fldtype == GlobalSetting
::DATA_TYPE_TEXT
) {
555 $globalTitle = $globalValue;
557 echo " <input type='text' class='form-control' name='form_$i' id='form_$i' " .
558 "maxlength='255' value='" . attr($fldvalue) . "' />\n";
559 } elseif ($fldtype == GlobalSetting
::DATA_TYPE_DEFAULT_RANDOM_UUID
) {
561 $globalTitle = $globalValue;
563 if (empty($fldvalue)) {
564 // if empty, then create a random uuid
565 $uuid4 = Uuid
::uuid4();
566 $fldvalue = $uuid4->toString();
568 echo " <input type='text' class='form-control' name='form_$i' id='form_$i' " .
569 "maxlength='255' value='" . attr($fldvalue) . "' />\n";
570 } elseif (($fldtype == GlobalSetting
::DATA_TYPE_ENCRYPTED
) ||
($fldtype == GlobalSetting
::DATA_TYPE_ENCRYPTED_HASH
)) {
571 if (empty($fldvalue)) {
573 $fldvalueDecrypted = '';
574 } elseif ($cryptoGen->cryptCheckStandard($fldvalue)) {
575 // normal behavior when not empty
576 $fldvalueDecrypted = $cryptoGen->decryptStandard($fldvalue);
578 // this is used when value has not yet been encrypted (only happens once when upgrading)
579 $fldvalueDecrypted = $fldvalue;
581 echo " <input type='password' class='form-control' name='form_$i' id='form_$i' " .
582 "maxlength='255' value='" . attr($fldvalueDecrypted) . "' />\n";
584 if (empty($globalValue)) {
587 } elseif ($cryptoGen->cryptCheckStandard($globalValue)) {
588 // normal behavior when not empty
589 $globalTitle = $cryptoGen->decryptStandard($globalValue);
591 // this is used when value has not yet been encrypted (only happens once when upgrading)
592 $globalTitle = $globalValue;
595 $fldvalueDecrypted = '';
596 } elseif ($fldtype == GlobalSetting
::DATA_TYPE_PASS
) {
598 $globalTitle = $globalValue;
600 echo " <input type='password' class='form-control' name='form_$i' " .
601 "maxlength='255' value='" . attr($fldvalue) . "' />\n";
602 } elseif ($fldtype == GlobalSetting
::DATA_TYPE_LANGUAGE
) {
603 $res = sqlStatement("SELECT * FROM lang_languages ORDER BY lang_description");
604 echo " <select class='form-control' name='form_$i' id='form_$i'>\n";
605 while ($row = sqlFetchArray($res)) {
606 echo " <option value='" . attr($row['lang_description']) . "'";
607 if ($row['lang_description'] == $fldvalue) {
612 echo xlt($row['lang_description']);
617 } elseif ($fldtype == GlobalSetting
::DATA_TYPE_CODE_TYPES
) {
619 echo " <select class='form-control' name='form_$i' id='form_$i'>\n";
620 foreach (array_keys($code_types) as $code_key) {
621 echo " <option value='" . attr($code_key) . "'";
622 if ($code_key == $fldvalue) {
627 echo xlt($code_types[$code_key]['label']);
632 } elseif ($fldtype == GlobalSetting
::DATA_TYPE_MULTI_LANGUAGE_SELECT
) {
633 $res = sqlStatement("SELECT * FROM lang_languages ORDER BY lang_description");
634 echo " <select multiple class='form-control' name='form_{$i}[]' id='form_{$i}[]' size='3'>\n";
635 while ($row = sqlFetchArray($res)) {
636 echo " <option value='" . attr($row['lang_description']) . "'";
637 foreach ($glarr as $glrow) {
638 if ($glrow['gl_value'] == $row['lang_description']) {
644 echo xlt($row['lang_description']);
648 } elseif ($fldtype == GlobalSetting
::DATA_TYPE_MULTI_DASHBOARD_CARDS
) {
650 $ret = sqlStatement("SELECT gl_value FROM `globals` WHERE `gl_name` = 'hide_dashboard_cards'");
651 while ($row = sqlFetchArray($ret)) {
652 $hiddenList[] = $row['gl_value'];
654 // The list of cards to hide. For now add to array new cards.
656 ['card_abrev' => '', 'card_name' => xlt('None or Reset')],
657 ['card_abrev' => attr('card_allergies'), 'card_name' => xlt('Allergies')],
658 ['card_abrev' => attr('card_amendments'), 'card_name' => xlt('Amendments')],
659 ['card_abrev' => attr('card_disclosure'), 'card_name' => xlt('Disclosures')],
660 ['card_abrev' => attr('card_insurance'), 'card_name' => xlt('Insurance')],
661 ['card_abrev' => attr('card_lab'), 'card_name' => xlt('Labs')],
662 ['card_abrev' => attr('card_medicalproblems'), 'card_name' => xlt('Medical Problems')],
663 ['card_abrev' => attr('card_medication'), 'card_name' => xlt('Medications')],
664 ['card_abrev' => 'card_prescriptions', 'card_name' => 'Prescriptions'], // For now don't hide because can be disabled as feature.
665 ['card_abrev' => attr('card_vitals'), 'card_name' => xlt('Vitals')]
667 echo " <select multiple class='form-control' name='form_{$i}[]' id='form_{$i}[]' size='10'>\n";
668 foreach ($res as $row) {
669 echo " <option value='" . attr($row['card_abrev']) . "'";
670 foreach ($glarr as $glrow) {
671 if ($glrow['gl_value'] == $row['card_abrev']) {
677 echo xlt($row['card_name']);
681 } elseif ($fldtype == GlobalSetting
::DATA_TYPE_COLOR_CODE
) {
683 $globalTitle = $globalValue;
685 echo " <input type='text' class='form-control jscolor {hash:true}' name='form_$i' id='form_$i' " .
686 "maxlength='15' value='" . attr($fldvalue) . "' />" .
687 "<input type='button' value='" . xla('Default') . "' onclick=\"document.forms[0].form_$i.jscolor.fromString(" . attr_js($flddef) . ")\">\n";
688 } elseif ($fldtype == GlobalSetting
::DATA_TYPE_DEFAULT_VISIT_CATEGORY
) {
689 $sql = "SELECT pc_catid, pc_catname, pc_cattype
690 FROM openemr_postcalendar_categories
691 WHERE pc_active = 1 ORDER BY pc_seq";
692 $result = sqlStatement($sql);
693 echo "<select class='form-control' name='form_{$i}' id='form_{$i}'>\n";
694 echo "<option value='_blank'>" . xlt('None{{Category}}') . "</option>";
695 while ($row = sqlFetchArray($result)) {
696 $catId = $row['pc_catid'];
697 $name = $row['pc_catname'];
698 if ($catId < 9 && $catId != "5") {
702 if ($row['pc_cattype'] == 3 && !$GLOBALS['enable_group_therapy']) {
706 $optionStr = '<option value="%pc_catid%"%selected%>%pc_catname%</option>';
707 $optionStr = str_replace("%pc_catid%", attr($catId), $optionStr);
708 $optionStr = str_replace("%pc_catname%", text(xl_appt_category($name)), $optionStr);
709 $selected = ($fldvalue == $catId) ?
" selected" : "";
710 $optionStr = str_replace("%selected%", $selected, $optionStr);
714 } elseif ($fldtype == GlobalSetting
::DATA_TYPE_CSS ||
$fldtype == GlobalSetting
::DATA_TYPE_TABS_CSS
) {
716 $globalTitle = $globalValue;
718 $themedir = "$webserver_root/public/themes";
719 $dh = opendir($themedir);
722 $styleArray = array();
723 while (false !== ($tfname = readdir($dh))) {
724 // Only show files that contain tabs_style_ or style_ as options
725 if ($fldtype == 'tabs_css') {
726 $patternStyle = 'tabs_style_';
729 $patternStyle = 'style_';
732 $tfname == 'style_blue.css' ||
733 $tfname == 'style_pdf.css' ||
734 !preg_match("/^" . $patternStyle . ".*\.css$/", $tfname)
739 if ($fldtype == GlobalSetting
::DATA_TYPE_TABS_CSS
) {
740 // Drop the "tabs_style_" part and any replace any underscores with spaces
741 $styleDisplayName = str_replace("_", " ", substr($tfname, 11));
742 } else { // $fldtype == 'css'
743 // Drop the "style_" part and any replace any underscores with spaces
744 $styleDisplayName = str_replace("_", " ", substr($tfname, 6));
746 // Strip the ".css" and uppercase the first character
747 $styleDisplayName = ucfirst(str_replace(".css", "", $styleDisplayName));
749 $styleArray[$tfname] = $styleDisplayName;
751 // Alphabetize styles
753 // Generate style selector
754 echo "<select class='form-control' name='form_$i' id='form_$i'>\n";
755 foreach ($styleArray as $styleKey => $styleValue) {
756 echo "<option value='" . attr($styleKey) . "'";
757 if ($styleKey == $fldvalue) {
761 echo text($styleValue);
767 } elseif ($fldtype == GlobalSetting
::DATA_TYPE_HOUR
) {
769 $globalTitle = $globalValue;
772 echo " <select class='form-control' name='form_$i' id='form_$i'>\n";
773 for ($h = 0; $h < 24; ++
$h) {
774 echo "<option value='$h'";
775 if ($h == $fldvalue) {
784 } elseif ($h == 12) {
787 echo ($h - 12) . " PM";
794 } elseif ($fldtype == GlobalSetting
::DATA_TYPE_MULTI_SORTED_LIST_SELECTOR
) {
795 include 'templates/field_multi_sorted_list_selector.php';
796 } else if ($fldtype == GlobalSetting
::DATA_TYPE_ADDRESS_BOOK
) {
797 include 'templates/globals-address-book.php';
802 echo "<div class='col-sm-2 text-danger'>" . text($globalTitle) . "</div>\n";
803 echo "<div class='col-sm-2 '><input type='checkbox' value='YES' name='toggle_" . $i . "' id='toggle_" . $i . "' " . $settingDefault . "/></div>\n";
804 if (($fldtype == 'encrypted') ||
($fldtype == 'encrypted_hash')) {
805 echo "<input type='hidden' id='globaldefault_" . $i . "' value='" . attr($globalTitle) . "' />\n";
807 echo "<input type='hidden' id='globaldefault_" . $i . "' value='" . attr($globalValue) . "' />\n";
811 echo " </div></div>\n";
817 echo "<div class='btn-group oe-margin-b-10'>" .
818 "<button type='submit' class='btn btn-primary btn-save oe-pull-toward' name='form_save'" .
819 "value='" . xla('Save') . "'>" . xlt('Save') . "</button></div>";
820 echo "<div class='oe-pull-away oe-margin-t-10' style=''>" . xlt($grpname) . " <a href='#' class='text-dark text-decoration-none fa fa-lg fa-arrow-circle-up oe-help-redirect scroll' aria-hidden='true'></a></div><div class='clearfix'></div></div>";
825 </div
><!--End of tabContainer div
-->
826 </div
><!--End of globals
-div div
-->
830 </div
><!--End of container div
-->
831 <?php
$oemr_ui->oeBelowContainerDiv();?
>
834 $post_srch_desc = $_POST['srch_desc'] ??
'';
835 if (!empty($post_srch_desc) && $srch_item == 0) {
836 echo "<script>alert(" . js_escape($post_srch_desc . " - " . xl('search term was not found, please try another search')) . ");</script>";
843 <?php
// mdsupport - Highlight search results ?>
844 $
('.srch div.control-label').wrapInner("<mark></mark>");
845 $
('.tab .row.srch :first-child').closest('.tab').each(function() {
846 $
('.tabNav li:nth-child(' +
($
(this
).index() +
1) +
') a').wrapInner("<mark></mark>");
848 // Use the counter ($i) to make the form user friendly for user-specific globals use
851 for ($j = 0; $j <= $i; $j++
) { ?
>
852 $
("#form_<?php echo $j ?>").change(function() {
853 $
("#toggle_<?php echo $j ?>").prop('checked', false);
855 $
("#toggle_<?php echo $j ?>").change(function() {
856 if ($
('#toggle_<?php echo $j ?>').prop('checked')) {
857 var defaultGlobal
= $
("#globaldefault_<?php echo $j ?>").val();
858 $
("#form_<?php echo $j ?>").val(defaultGlobal
);
865 $
('#srch_desc').keypress(function (event
) {
866 if (event
.which
=== 13 || event
.keyCode
=== 13) {
867 event
.preventDefault();
868 $
('#globals_form_search').click();
872 $
('.scroll').click(function() {
873 if ($
(window
).scrollTop() == 0) {
874 alert(<?php
echo xlj("Already at the top of the page"); ?
>);
876 window
.parent
.scrollTo({