.inc files migration to .inc.php (#5897)
[openemr.git] / interface / main / tabs / main.php
blobdf7c318b38323f5d33975fd5f4e98dda0d659d0a
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;
26 use OpenEMR\Events\Main\Tabs\RenderEvent;
28 // Ensure token_main matches so this script can not be run by itself
29 // If do not match, then destroy the session and go back to login screen
30 if (
31 (empty($_SESSION['token_main_php'])) ||
32 (empty($_GET['token_main'])) ||
33 ($_GET['token_main'] != $_SESSION['token_main_php'])
34 ) {
35 // Below functions are from auth.inc, which is included in globals.php
36 authCloseSession();
37 authLoginScreen(false);
39 // this will not allow copy/paste of the link to this main.php page or a refresh of this main.php page
40 // (default behavior, however, this behavior can be turned off in the prevent_browser_refresh global)
41 if ($GLOBALS['prevent_browser_refresh'] > 1) {
42 unset($_SESSION['token_main_php']);
45 $esignApi = new Api();
47 <!DOCTYPE html>
48 <html>
50 <head>
51 <title><?php echo text($openemr_name); ?></title>
53 <script>
54 // This is to prevent users from losing data by refreshing or backing out of OpenEMR.
55 // (default behavior, however, this behavior can be turned off in the prevent_browser_refresh global)
56 <?php if ($GLOBALS['prevent_browser_refresh'] > 0) { ?>
57 window.addEventListener('beforeunload', (event) => {
58 if (!timed_out) {
59 event.returnValue = <?php echo xlj('Recommend not leaving or refreshing or you may lose data.'); ?>;
61 });
62 <?php } ?>
64 <?php require($GLOBALS['srcdir'] . "/restoreSession.php"); ?>
66 // Since this should be the parent window, this is to prevent calls to the
67 // window that opened this window. For example when a new window is opened
68 // from the Patient Flow Board or the Patient Finder.
69 window.opener = null;
70 window.name = "main";
72 // This flag indicates if another window or frame is trying to reload the login
73 // page to this top-level window. It is set by javascript returned by auth.inc.php
74 // and is checked by handlers of beforeunload events.
75 var timed_out = false;
76 // some globals to access using top.variable
77 // note that 'let' or 'const' does not allow global scope here.
78 // only use var
79 var isPortalEnabled = "<?php echo $GLOBALS['portal_onsite_two_enable'] ?>";
80 // Set the csrf_token_js token that is used in the below js/tabs_view_model.js script
81 var csrf_token_js = <?php echo js_escape(CsrfUtils::collectCsrfToken()); ?>;
82 var userDebug = <?php echo js_escape($GLOBALS['user_debug']); ?>;
83 var webroot_url = <?php echo js_escape($web_root); ?>;
84 var jsLanguageDirection = <?php echo js_escape($_SESSION['language_direction']); ?>;
85 var jsGlobals = {};
86 // used in tabs_view_model.js.
87 jsGlobals.enable_group_therapy = <?php echo js_escape($GLOBALS['enable_group_therapy']); ?>
89 var WindowTitleAddPatient = <?php echo ($GLOBALS['window_title_add_patient_name'] ? 'true' : 'false' ); ?>;
90 var WindowTitleBase = <?php echo js_escape($openemr_name); ?>;
92 function goRepeaterServices() {
93 // Ensure send the skip_timeout_reset parameter to not count this as a manual entry in the
94 // timing out mechanism in OpenEMR.
96 // Send the skip_timeout_reset parameter to not count this as a manual entry in the
97 // timing out mechanism in OpenEMR. Notify App for various portal and reminder alerts.
98 // Combined portal and reminders ajax to fetch sjp 06-07-2020.
99 // Incorporated timeout mechanism in 2021
100 restoreSession();
101 let request = new FormData;
102 request.append("skip_timeout_reset", "1");
103 request.append("isPortal", isPortalEnabled);
104 request.append("csrf_token_form", csrf_token_js);
105 fetch(webroot_url + "/library/ajax/dated_reminders_counter.php", {
106 method: 'POST',
107 credentials: 'same-origin',
108 body: request
109 }).then((response) => {
110 if (response.status !== 200) {
111 console.log('Reminders start failed. Status Code: ' + response.status);
112 return;
114 return response.json();
115 }).then((data) => {
116 if (data.timeoutMessage && (data.timeoutMessage == 'timeout')) {
117 // timeout has happened, so logout
118 timeoutLogout();
120 if (isPortalEnabled) {
121 let mail = data.mailCnt;
122 let chats = data.chatCnt;
123 let audits = data.auditCnt;
124 let payments = data.paymentCnt;
125 let total = data.total;
126 let enable = ((1 * mail) + (1 * audits)); // payments are among audits.
127 // Send portal counts to notification button model
128 // Will turn off button display if no notification!
129 app_view_model.application_data.user().portal(enable);
130 if (enable > 0) {
131 app_view_model.application_data.user().portalAlerts(total);
132 app_view_model.application_data.user().portalAudits(audits);
133 app_view_model.application_data.user().portalMail(mail);
134 app_view_model.application_data.user().portalChats(chats);
135 app_view_model.application_data.user().portalPayments(payments);
138 // Always send reminder count text to model
139 app_view_model.application_data.user().messages(data.reminderText);
140 }).catch(function(error) {
141 console.log('Request failed', error);
144 // run background-services
145 // delay 10 seconds to prevent both utility trigger at close to same time.
146 // Both call globals so that is my concern.
147 setTimeout(function() {
148 restoreSession();
149 request = new FormData;
150 request.append("skip_timeout_reset", "1");
151 request.append("ajax", "1");
152 request.append("csrf_token_form", csrf_token_js);
153 fetch(webroot_url + "/library/ajax/execute_background_services.php", {
154 method: 'POST',
155 credentials: 'same-origin',
156 body: request
157 }).then((response) => {
158 if (response.status !== 200) {
159 console.log('Background Service start failed. Status Code: ' + response.status);
161 }).catch(function(error) {
162 console.log('HTML Background Service start Request failed: ', error);
164 }, 10000);
166 // auto run this function every 60 seconds
167 var repeater = setTimeout("goRepeaterServices()", 60000);
170 function isEncounterLocked(encounterId) {
171 <?php if ($esignApi->lockEncounters()) { ?>
172 // If encounter locking is enabled, make a syncronous call (async=false) to check the
173 // DB to see if the encounter is locked.
174 // Call restore session, just in case
175 // @TODO next clean up pass, turn into await promise then modify tabs_view_model.js L-309
176 restoreSession();
177 let url = webroot_url + "/interface/esign/index.php?module=encounter&method=esign_is_encounter_locked";
178 $.ajax({
179 type: 'POST',
180 url: url,
181 data: {
182 encounterId: encounterId
184 success: function(data) {
185 encounter_locked = data;
187 dataType: 'json',
188 async: false
190 return encounter_locked;
191 <?php } else { ?>
192 // If encounter locking isn't enabled then always return false
193 return false;
194 <?php } ?>
196 </script>
198 <?php Header::setupHeader(['knockout', 'tabs-theme', 'i18next', 'hotkeys']); ?>
199 <script>
200 // set up global translations for js
201 function setupI18n(lang_id) {
202 restoreSession();
203 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), {
204 credentials: 'same-origin',
205 method: 'GET'
206 }).then((response) => {
207 if (response.status !== 200) {
208 console.log('I18n setup failed. Status Code: ' + response.status);
209 return [];
211 return response.json();
214 setupI18n(<?php echo js_escape($_SESSION['language_choice']); ?>).then(translationsJson => {
215 i18next.init({
216 lng: 'selected',
217 debug: false,
218 nsSeparator: false,
219 keySeparator: false,
220 resources: {
221 selected: {
222 translation: translationsJson
226 }).catch(error => {
227 console.log(error.message);
231 * Assign and persist documents to portal patients
232 * @var int patientId pid
234 function assignPatientDocuments(patientId) {
235 let url = top.webroot_url + '/portal/import_template_ui.php?from_demo_pid=' + encodeURIComponent(patientId);
236 dlgopen(url, 'pop-assignments', 'modal-lg', 850, '', '', {
237 allowDrag: true,
238 allowResize: true,
239 sizeHeight: 'full',
242 </script>
244 <script src="js/custom_bindings.js?v=<?php echo $v_js_includes; ?>"></script>
245 <script src="js/user_data_view_model.js?v=<?php echo $v_js_includes; ?>"></script>
246 <script src="js/patient_data_view_model.js?v=<?php echo $v_js_includes; ?>"></script>
247 <script src="js/therapy_group_data_view_model.js?v=<?php echo $v_js_includes; ?>"></script>
248 <script src="js/tabs_view_model.js?v=<?php echo $v_js_includes; ?>"></script>
249 <script src="js/application_view_model.js?v=<?php echo $v_js_includes; ?>"></script>
250 <script src="js/frame_proxies.js?v=<?php echo $v_js_includes; ?>"></script>
251 <script src="js/dialog_utils.js?v=<?php echo $v_js_includes; ?>"></script>
252 <script src="js/shortcuts.js?v=<?php echo $v_js_includes; ?>"></script>
254 <?php
255 // Below code block is to prepare certain elements for deciding what links to show on the menu
257 // prepare newcrop globals that are used in creating the menu
258 if ($GLOBALS['erx_enable']) {
259 $newcrop_user_role_sql = sqlQuery("SELECT `newcrop_user_role` FROM `users` WHERE `username` = ?", array($_SESSION['authUser']));
260 $GLOBALS['newcrop_user_role'] = $newcrop_user_role_sql['newcrop_user_role'];
261 if ($GLOBALS['newcrop_user_role'] === 'erxadmin') {
262 $GLOBALS['newcrop_user_role_erxadmin'] = 1;
266 // prepare track anything to be used in creating the menu
267 $track_anything_sql = sqlQuery("SELECT `state` FROM `registry` WHERE `directory` = 'track_anything'");
268 $GLOBALS['track_anything_state'] = ($track_anything_sql['state'] ?? 0);
269 // prepare Issues popup link global that is used in creating the menu
270 $GLOBALS['allow_issue_menu_link'] = ((AclMain::aclCheckCore('encounters', 'notes', '', 'write') || AclMain::aclCheckCore('encounters', 'notes_a', '', 'write')) &&
271 AclMain::aclCheckCore('patients', 'med', '', 'write'));
274 <?php require_once("templates/tabs_template.php"); ?>
275 <?php require_once("templates/menu_template.php"); ?>
276 <?php require_once("templates/patient_data_template.php"); ?>
277 <?php require_once("templates/therapy_group_template.php"); ?>
278 <?php require_once("templates/user_data_template.php"); ?>
279 <?php require_once("menu/menu_json.php"); ?>
280 <?php $userQuery = sqlQuery("select * from users where username = ?", array($_SESSION['authUser'])); ?>
282 <script>
283 <?php if (!empty($_SESSION['frame1url']) && !empty($_SESSION['frame1target'])) { ?>
284 // Use session variables and tabStatus object to set up initial/default first tab
285 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));
286 <?php } ?>
288 <?php if (!empty($_SESSION['frame2url']) && !empty($_SESSION['frame2target'])) { ?>
289 // 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
290 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));
291 <?php } ?>
293 app_view_model.application_data.user(new user_data_view_model(<?php echo json_encode($_SESSION["authUser"])
294 . ',' . json_encode($userQuery['fname'])
295 . ',' . json_encode($userQuery['lname'])
296 . ',' . json_encode($_SESSION['authProvider']); ?>));
297 </script>
298 <style>
299 html,
300 body {
301 width: max-content;
302 min-height: 100% !important;
303 height: 100% !important;
305 </style>
306 </head>
308 <body class="min-vw-100">
309 <?php
310 // fire off an event here
311 if (!empty($GLOBALS['kernel']->getEventDispatcher())) {
313 * @var \Symfony\Component\EventDispatcher\EventDispatcher
315 $dispatcher = $GLOBALS['kernel']->getEventDispatcher();
316 $dispatcher->dispatch(new RenderEvent(), RenderEvent::EVENT_BODY_RENDER_PRE);
319 <!-- Below iframe is to support logout, which needs to be run in an inner iframe to work as intended -->
320 <iframe name="logoutinnerframe" id="logoutinnerframe" style="visibility:hidden; position:absolute; left:0; top:0; height:0; width:0; border:none;" src="about:blank"></iframe>
321 <?php // mdsupport - app settings
322 $disp_mainBox = '';
323 if (isset($_SESSION['app1'])) {
324 $rs = sqlquery(
325 "SELECT title app_url FROM list_options WHERE activity=1 AND list_id=? AND option_id=?",
326 array('apps', $_SESSION['app1'])
328 if ($rs['app_url'] != "main/main_screen.php") {
329 echo '<iframe name="app1" src="../../' . attr($rs['app_url']) . '"
330 style="position: absolute; left: 0; top: 0; height: 100%; width: 100%; border: none;" />';
331 $disp_mainBox = 'style="display: none;"';
335 <div id="mainBox" <?php echo $disp_mainBox ?>>
336 <nav class="navbar navbar-expand-xl navbar-light bg-light py-0">
337 <?php if ($GLOBALS['display_main_menu_logo'] === '1') : ?>
338 <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">
339 <?php echo file_get_contents($GLOBALS['images_static_absolute'] . "/menu-logo.svg"); ?>
340 </a>
341 <?php endif; ?>
342 <button class="navbar-toggler mr-auto" type="button" data-toggle="collapse" data-target="#mainMenu" aria-controls="mainMenu" aria-expanded="false" aria-label="Toggle navigation">
343 <span class="navbar-toggler-icon"></span>
344 </button>
345 <div class="collapse navbar-collapse" id="mainMenu" data-bind="template: {name: 'menu-template', data: application_data}"></div>
346 <form name="frm_search_globals" class="form-inline">
347 <div class="input-group">
348 <input type="text" id="anySearchBox" class="form-control-sm <?php echo $any_search_class ?> form-control" name="anySearchBox" placeholder="<?php echo xla("Search by any demographics") ?>" autocomplete="off">
349 <div class="input-group-append">
350 <button type="button" id="search_globals" class="btn btn-sm btn-secondary <?php echo $search_globals_class ?>" title='<?php echo xla("Search for patient by entering whole or part of any demographics field information"); ?>' data-bind="event: {mousedown: viewPtFinder.bind( $data, '<?php echo xla("The search field cannot be empty. Please enter a search term") ?>', '<?php echo attr($search_any_type); ?>')}"><i class="fa fa-search">&nbsp;</i></button>
351 </div>
352 </div>
353 </form>
354 <span id="userData" data-bind="template: {name: 'user-data-template', data: application_data}"></span>
355 </nav>
356 <div id="attendantData" class="body_title acck" data-bind="template: {name: app_view_model.attendant_template_type, data: application_data}"></div>
357 <div class="body_title" id="tabs_div" data-bind="template: {name: 'tabs-controls', data: application_data}"></div>
358 <div class="mainFrames d-flex flex-row" id="mainFrames_div">
359 <div id="framesDisplay" data-bind="template: {name: 'tabs-frames', data: application_data}"></div>
360 </div>
361 </div>
362 <script>
363 ko.applyBindings(app_view_model);
365 $(function() {
366 $('.dropdown-toggle').dropdown();
367 $('#patient_caret').click(function() {
368 $('#attendantData').slideToggle();
369 $('#patient_caret').toggleClass('fa-caret-down').toggleClass('fa-caret-up');
371 if ($('body').css('direction') == "rtl") {
372 $('.dropdown-menu-right').each(function() {
373 $(this).removeClass('dropdown-menu-right');
377 $(function() {
378 $('#logo_menu').focus();
380 $('#anySearchBox').keypress(function(event) {
381 if (event.which === 13 || event.keyCode === 13) {
382 event.preventDefault();
383 $('#search_globals').mousedown();
386 document.addEventListener('touchstart', {}); //specifically added for iOS devices, especially in iframes
387 $(function() {
388 goRepeaterServices();
390 </script>
391 <?php
392 // fire off an event here
393 if (!empty($GLOBALS['kernel']->getEventDispatcher())) {
395 * @var \Symfony\Component\EventDispatcher\EventDispatcher
397 $dispatcher = $GLOBALS['kernel']->getEventDispatcher();
398 $dispatcher->dispatch(new RenderEvent(), RenderEvent::EVENT_BODY_RENDER_POST);
401 </body>
403 </html>