Site Id intermittent error. (#4492)
[openemr.git] / interface / main / tabs / main.php
blob29d3fb89c01a544ace28dcf1114fd75a2fe80814
1 <?php
3 /**
4 * main.php
6 * @package OpenEMR
7 * @link http://www.open-emr.org
8 * @author Kevin Yeh <kevin.y@integralemr.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 * @copyright Copyright (c) 2016 Kevin Yeh <kevin.y@integralemr.com>
13 * @copyright Copyright (c) 2016-2019 Brady Miller <brady.g.miller@gmail.com>
14 * @copyright Copyright (c) 2019 Ranganath Pathak <pathak@scrs1.org>
15 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
18 $sessionAllowWrite = true;
19 require_once(__DIR__ . '/../../globals.php');
20 require_once $GLOBALS['srcdir'] . '/ESign/Api.php';
22 use Esign\Api;
23 use OpenEMR\Common\Acl\AclMain;
24 use OpenEMR\Common\Csrf\CsrfUtils;
25 use OpenEMR\Core\Header;
27 // Ensure token_main matches so this script can not be run by itself
28 // If do not match, then destroy the session and go back to login screen
29 if (
30 (empty($_SESSION['token_main_php'])) ||
31 (empty($_GET['token_main'])) ||
32 ($_GET['token_main'] != $_SESSION['token_main_php'])
33 ) {
34 // Below functions are from auth.inc, which is included in globals.php
35 authCloseSession();
36 authLoginScreen(false);
38 // this will not allow copy/paste of the link to this main.php page or a refresh of this main.php page
39 // (default behavior, however, this behavior can be turned off in the prevent_browser_refresh global)
40 if ($GLOBALS['prevent_browser_refresh'] > 1) {
41 unset($_SESSION['token_main_php']);
44 $esignApi = new Api();
46 <!DOCTYPE html>
47 <html>
48 <head>
49 <title><?php echo text($openemr_name); ?></title>
51 <script>
52 // This is to prevent users from losing data by refreshing or backing out of OpenEMR.
53 // (default behavior, however, this behavior can be turned off in the prevent_browser_refresh global)
54 <?php if ($GLOBALS['prevent_browser_refresh'] > 0) { ?>
55 window.addEventListener('beforeunload', (event) => {
56 if (!timed_out) {
57 event.returnValue = <?php echo xlj('Recommend not leaving or refreshing or you may lose data.'); ?>;
59 });
60 <?php } ?>
62 <?php require($GLOBALS['srcdir'] . "/restoreSession.php"); ?>
64 // Since this should be the parent window, this is to prevent calls to the
65 // window that opened this window. For example when a new window is opened
66 // from the Patient Flow Board or the Patient Finder.
67 window.opener = null;
68 window.name = "main";
70 // This flag indicates if another window or frame is trying to reload the login
71 // page to this top-level window. It is set by javascript returned by auth.inc
72 // and is checked by handlers of beforeunload events.
73 var timed_out = false;
74 // some globals to access using top.variable
75 // note that 'let' or 'const' does not allow global scope here.
76 // only use var
77 var isPortalEnabled = "<?php echo $GLOBALS['portal_onsite_two_enable'] ?>";
78 // Set the csrf_token_js token that is used in the below js/tabs_view_model.js script
79 var csrf_token_js = <?php echo js_escape(CsrfUtils::collectCsrfToken()); ?>;
80 var userDebug = <?php echo js_escape($GLOBALS['user_debug']); ?>;
81 var webroot_url = <?php echo js_escape($web_root); ?>;
82 var jsLanguageDirection = <?php echo js_escape($_SESSION['language_direction']); ?>;
83 var jsGlobals = {};
84 // used in tabs_view_model.js.
85 jsGlobals.enable_group_therapy = <?php echo js_escape($GLOBALS['enable_group_therapy']); ?>
87 function goRepeaterServices() {
88 // Ensure send the skip_timeout_reset parameter to not count this as a manual entry in the
89 // timing out mechanism in OpenEMR.
91 // Send the skip_timeout_reset parameter to not count this as a manual entry in the
92 // timing out mechanism in OpenEMR. Notify App for various portal and reminder alerts.
93 // Combined portal and reminders ajax to fetch sjp 06-07-2020.
94 // Incorporated timeout mechanism in 2021
95 restoreSession();
96 let request = new FormData;
97 request.append("skip_timeout_reset", "1");
98 request.append("isPortal", isPortalEnabled);
99 request.append("csrf_token_form", csrf_token_js);
100 fetch(webroot_url + "/library/ajax/dated_reminders_counter.php", {
101 method: 'POST',
102 credentials: 'same-origin',
103 body: request
104 }).then((response) => {
105 if (response.status !== 200) {
106 console.log('Reminders start failed. Status Code: ' + response.status);
107 return;
109 return response.json();
110 }).then((data) => {
111 if (data.timeoutMessage && (data.timeoutMessage == 'timeout')) {
112 // timeout has happened, so logout
113 timeoutLogout();
115 if (isPortalEnabled) {
116 let mail = data.mailCnt;
117 let chats = data.chatCnt;
118 let audits = data.auditCnt;
119 let payments = data.paymentCnt;
120 let total = data.total;
121 let enable = ((1 * mail) + (1 * audits)); // payments are among audits.
122 // Send portal counts to notification button model
123 // Will turn off button display if no notification!
124 app_view_model.application_data.user().portal(enable);
125 if (enable > 0) {
126 app_view_model.application_data.user().portalAlerts(total);
127 app_view_model.application_data.user().portalAudits(audits);
128 app_view_model.application_data.user().portalMail(mail);
129 app_view_model.application_data.user().portalChats(chats);
130 app_view_model.application_data.user().portalPayments(payments);
133 // Always send reminder count text to model
134 app_view_model.application_data.user().messages(data.reminderText);
135 }).catch(function (error) {
136 console.log('Request failed', error);
139 // run background-services
140 // delay 10 seconds to prevent both utility trigger at close to same time.
141 // Both call globals so that is my concern.
142 setTimeout(function () {
143 restoreSession();
144 request = new FormData;
145 request.append("skip_timeout_reset", "1");
146 request.append("ajax", "1");
147 request.append("csrf_token_form", csrf_token_js);
148 fetch(webroot_url + "/library/ajax/execute_background_services.php", {
149 method: 'POST',
150 credentials: 'same-origin',
151 body: request
152 }).then((response) => {
153 if (response.status !== 200) {
154 console.log('Background Service start failed. Status Code: ' + response.status);
156 }).catch(function (error) {
157 console.log('HTML Background Service start Request failed: ', error);
159 }, 10000);
161 // auto run this function every 60 seconds
162 var repeater = setTimeout("goRepeaterServices()", 60000);
165 function isEncounterLocked(encounterId) {
166 <?php if ($esignApi->lockEncounters()) { ?>
167 // If encounter locking is enabled, make a syncronous call (async=false) to check the
168 // DB to see if the encounter is locked.
169 // Call restore session, just in case
170 // @TODO next clean up pass, turn into await promise then modify tabs_view_model.js L-309
171 restoreSession();
172 let url = webroot_url + "/interface/esign/index.php?module=encounter&method=esign_is_encounter_locked";
173 $.ajax({
174 type: 'POST',
175 url: url,
176 data: {encounterId: encounterId},
177 success: function (data) {
178 encounter_locked = data;
180 dataType: 'json',
181 async: false
183 return encounter_locked;
184 <?php } else { ?>
185 // If encounter locking isn't enabled then always return false
186 return false;
187 <?php } ?>
189 </script>
191 <?php Header::setupHeader(['knockout', 'tabs-theme', 'i18next']); ?>
192 <script>
193 // set up global translations for js
194 function setupI18n(lang_id) {
195 restoreSession();
196 return fetch(<?php echo js_escape($GLOBALS['webroot'])?> +"/library/ajax/i18n_generator.php?lang_id=" + encodeURIComponent(lang_id) + "&csrf_token_form=" + encodeURIComponent(csrf_token_js), {
197 credentials: 'same-origin',
198 method: 'GET'
199 }).then(response => response.json())
201 setupI18n(<?php echo js_escape($_SESSION['language_choice']); ?>).then(translationsJson => {
202 i18next.init({
203 lng: 'selected',
204 debug: false,
205 nsSeparator: false,
206 keySeparator: false,
207 resources: {
208 selected: {
209 translation: translationsJson
213 }).catch(error => {
214 console.log(error.message);
216 </script>
218 <script src="js/custom_bindings.js?v=<?php echo $v_js_includes; ?>"></script>
219 <script src="js/user_data_view_model.js?v=<?php echo $v_js_includes; ?>"></script>
220 <script src="js/patient_data_view_model.js?v=<?php echo $v_js_includes; ?>"></script>
221 <script src="js/therapy_group_data_view_model.js?v=<?php echo $v_js_includes; ?>"></script>
222 <script src="js/tabs_view_model.js?v=<?php echo $v_js_includes; ?>"></script>
223 <script src="js/application_view_model.js?v=<?php echo $v_js_includes; ?>"></script>
224 <script src="js/frame_proxies.js?v=<?php echo $v_js_includes; ?>"></script>
225 <script src="js/dialog_utils.js?v=<?php echo $v_js_includes; ?>"></script>
227 <?php
228 // Below code block is to prepare certain elements for deciding what links to show on the menu
230 // prepare newcrop globals that are used in creating the menu
231 if ($GLOBALS['erx_enable']) {
232 $newcrop_user_role_sql = sqlQuery("SELECT `newcrop_user_role` FROM `users` WHERE `username` = ?", array($_SESSION['authUser']));
233 $GLOBALS['newcrop_user_role'] = $newcrop_user_role_sql['newcrop_user_role'];
234 if ($GLOBALS['newcrop_user_role'] === 'erxadmin') {
235 $GLOBALS['newcrop_user_role_erxadmin'] = 1;
239 // prepare track anything to be used in creating the menu
240 $track_anything_sql = sqlQuery("SELECT `state` FROM `registry` WHERE `directory` = 'track_anything'");
241 $GLOBALS['track_anything_state'] = ($track_anything_sql['state'] ?? 0);
242 // prepare Issues popup link global that is used in creating the menu
243 $GLOBALS['allow_issue_menu_link'] = ((AclMain::aclCheckCore('encounters', 'notes', '', 'write') || AclMain::aclCheckCore('encounters', 'notes_a', '', 'write')) &&
244 AclMain::aclCheckCore('patients', 'med', '', 'write'));
247 <?php require_once("templates/tabs_template.php"); ?>
248 <?php require_once("templates/menu_template.php"); ?>
249 <?php require_once("templates/patient_data_template.php"); ?>
250 <?php require_once("templates/therapy_group_template.php"); ?>
251 <?php require_once("templates/user_data_template.php"); ?>
252 <?php require_once("menu/menu_json.php"); ?>
253 <?php $userQuery = sqlQuery("select * from users where username = ?", array($_SESSION['authUser'])); ?>
255 <script>
256 <?php if (!empty($_SESSION['frame1url']) && !empty($_SESSION['frame1target'])) { ?>
257 // Use session variables and tabStatus object to set up initial/default first tab
258 app_view_model.application_data.tabs.tabsList.push(new tabStatus(<?php echo xlj("Loading"); ?> +"...",<?php echo json_encode("../" . $_SESSION['frame1url']); ?>,<?php echo json_encode($_SESSION['frame1target']); ?>,<?php echo xlj("Loading"); ?> +" " + <?php echo json_encode($_SESSION['frame1label']); ?>, true, true, false));
259 <?php } ?>
261 <?php if (!empty($_SESSION['frame2url']) && !empty($_SESSION['frame2target'])) { ?>
262 // Use session variables and tabStatus object to set up initial/default second tab, if none is set in globals, this tab will not be displayed initially
263 app_view_model.application_data.tabs.tabsList.push(new tabStatus(<?php echo xlj("Loading"); ?> +"...",<?php echo json_encode("../" . $_SESSION['frame2url']); ?>,<?php echo json_encode($_SESSION['frame2target']); ?>,<?php echo xlj("Loading"); ?> +" " + <?php echo json_encode($_SESSION['frame2label']); ?>, true, false, false));
264 <?php } ?>
266 app_view_model.application_data.user(new user_data_view_model(<?php echo json_encode($_SESSION["authUser"])
267 . ',' . json_encode($userQuery['fname'])
268 . ',' . json_encode($userQuery['lname'])
269 . ',' . json_encode($_SESSION['authProvider']); ?>));
271 </script>
272 <style>
273 html, body {
274 width: max-content;
275 min-height: 100% !important;
276 height: 100% !important;
278 </style>
279 </head>
280 <body class="min-vw-100">
281 <!-- Below iframe is to support logout, which needs to be run in an inner iframe to work as intended -->
282 <iframe name="logoutinnerframe" id="logoutinnerframe" style="visibility:hidden; position:absolute; left:0; top:0; height:0; width:0; border:none;" src="about:blank"></iframe>
283 <?php // mdsupport - app settings
284 $disp_mainBox = '';
285 if (isset($_SESSION['app1'])) {
286 $rs = sqlquery(
287 "SELECT title app_url FROM list_options WHERE activity=1 AND list_id=? AND option_id=?",
288 array('apps', $_SESSION['app1'])
290 if ($rs['app_url'] != "main/main_screen.php") {
291 echo '<iframe name="app1" src="../../' . attr($rs['app_url']) . '"
292 style="position: absolute; left: 0; top: 0; height: 100%; width: 100%; border: none;" />';
293 $disp_mainBox = 'style="display: none;"';
297 <div id="mainBox" <?php echo $disp_mainBox ?> >
298 <nav class="navbar navbar-expand-xl navbar-light bg-light py-0">
299 <a class="navbar-brand mt-2 mt-xl-0 mr-3 mr-xl-2" href="https://www.open-emr.org" title="OpenEMR <?php echo xla("Website"); ?>" rel="noopener" target="_blank">
300 <?php echo file_get_contents($GLOBALS['images_static_absolute'] . "/menu-logo.svg"); ?>
301 </a>
302 <button class="navbar-toggler mr-auto" type="button" data-toggle="collapse" data-target="#mainMenu" aria-controls="mainMenu" aria-expanded="false" aria-label="Toggle navigation">
303 <span class="navbar-toggler-icon"></span>
304 </button>
305 <div class="collapse navbar-collapse" id="mainMenu" data-bind="template: {name: 'menu-template', data: application_data}"></div>
306 <span id="userData" data-bind="template: {name: 'user-data-template', data: application_data}"></span>
307 </nav>
308 <div id="attendantData" class="body_title acck" data-bind="template: {name: app_view_model.attendant_template_type, data: application_data}">
309 </div>
311 <div class="body_title" id="tabs_div" data-bind="template: {name: 'tabs-controls', data: application_data}"></div>
313 <div class="mainFrames d-flex flex-row" id="mainFrames_div">
314 <div id="framesDisplay" data-bind="template: {name: 'tabs-frames', data: application_data}"></div>
315 </div>
316 </div>
317 <script>
318 ko.applyBindings(app_view_model);
320 $(function () {
321 $('.dropdown-toggle').dropdown();
322 $('#patient_caret').click(function () {
323 $('#attendantData').slideToggle();
324 $('#patient_caret').toggleClass('fa-caret-down').toggleClass('fa-caret-up');
326 if($('body').css('direction') == "rtl") {
327 $('.dropdown-menu-right').each(function() {
328 $(this).removeClass('dropdown-menu-right');
332 $(function () {
333 $('#logo_menu').focus();
335 $('#anySearchBox').keypress(function (event) {
336 if (event.which === 13 || event.keyCode === 13) {
337 event.preventDefault();
338 $('#search_globals').mousedown();
341 document.addEventListener('touchstart', {}); //specifically added for iOS devices, especially in iframes
342 $(function () {
343 goRepeaterServices();
345 </script>
346 </body>
347 </html>