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';
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
30 (empty($_SESSION['token_main_php'])) ||
31 (empty($_GET['token_main'])) ||
32 ($_GET['token_main'] != $_SESSION['token_main_php'])
34 // Below functions are from auth.inc, which is included in globals.php
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();
49 <title
><?php
echo text($openemr_name); ?
></title
>
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
) => {
57 event
.returnValue
= <?php
echo xlj('Recommend not leaving or refreshing or you may lose data.'); ?
>;
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.
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.
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']); ?
>;
85 function goRepeaterServices() {
86 // Ensure send the skip_timeout_reset parameter to not count this as a manual entry in the
87 // timing out mechanism in OpenEMR.
89 // Send the skip_timeout_reset parameter to not count this as a manual entry in the
90 // timing out mechanism in OpenEMR. Notify App for various portal and reminder alerts.
91 // Combined portal and reminders ajax to fetch sjp 06-07-2020.
93 let request
= new FormData
;
94 request
.append("skip_timeout_reset", "1");
95 request
.append("isPortal", isPortalEnabled
);
96 request
.append("csrf_token_form", csrf_token_js
);
97 fetch(webroot_url +
"/library/ajax/dated_reminders_counter.php", {
99 credentials
: 'same-origin',
101 }).then((response
) => {
102 if (response
.status
!== 200) {
103 console
.log('Reminders start failed. Status Code: ' + response
.status
);
106 return response
.json();
108 if (isPortalEnabled
) {
109 let mail
= data
.mailCnt
;
110 let chats
= data
.chatCnt
;
111 let audits
= data
.auditCnt
;
112 let payments
= data
.paymentCnt
;
113 let total
= data
.total
;
114 let enable
= ((1 * mail
) +
(1 * audits
)); // payments are among audits.
115 // Send portal counts to notification button model
116 // Will turn off button display if no notification!
117 app_view_model
.application_data
.user().portal(enable
);
119 app_view_model
.application_data
.user().portalAlerts(total
);
120 app_view_model
.application_data
.user().portalAudits(audits
);
121 app_view_model
.application_data
.user().portalMail(mail
);
122 app_view_model
.application_data
.user().portalChats(chats
);
123 app_view_model
.application_data
.user().portalPayments(payments
);
126 // Always send reminder count text to model
127 app_view_model
.application_data
.user().messages(data
.reminderText
);
128 }).catch(function(error
) {
129 console
.log('Request failed', error
);
132 // run background-services
134 request
= new FormData
;
135 request
.append("skip_timeout_reset", "1");
136 request
.append("ajax", "1");
137 request
.append("csrf_token_form", csrf_token_js
);
138 fetch(webroot_url +
"/library/ajax/execute_background_services.php", {
140 credentials
: 'same-origin',
142 }).then((response
) => {
143 if (response
.status
!== 200) {
144 console
.log('Background Service start failed. Status Code: ' + response
.status
);
146 }).catch(function(error
) {
147 console
.log('HTML Background Service start Request failed: ', error
);
150 // auto run this function every 60 seconds
151 var repeater
= setTimeout("goRepeaterServices()", 60000);
154 function isEncounterLocked(encounterId
) {
155 <?php
if ($esignApi->lockEncounters()) { ?
>
156 // If encounter locking is enabled, make a syncronous call (async=false) to check the
157 // DB to see if the encounter is locked.
158 // Call restore session, just in case
159 // @TODO next clean up pass, turn into await promise then modify tabs_view_model.js L-309
161 let url
= webroot_url +
"/interface/esign/index.php?module=encounter&method=esign_is_encounter_locked";
165 data
: {encounterId
: encounterId
},
166 success
: function (data
) {
167 encounter_locked
= data
;
172 return encounter_locked
;
174 // If encounter locking isn't enabled then always return false
180 <?php Header
::setupHeader(['knockout', 'tabs-theme', 'i18next']); ?
>
182 // set up global translations for js
183 function setupI18n(lang_id
) {
185 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
), {
186 credentials
: 'same-origin',
188 }).then(response
=> response
.json())
190 setupI18n(<?php
echo js_escape($_SESSION['language_choice']); ?
>).then(translationsJson
=> {
198 translation
: translationsJson
203 console
.log(error
.message
);
207 <script src
="js/custom_bindings.js?v=<?php echo $v_js_includes; ?>"></script
>
208 <script src
="js/user_data_view_model.js?v=<?php echo $v_js_includes; ?>"></script
>
209 <script src
="js/patient_data_view_model.js?v=<?php echo $v_js_includes; ?>"></script
>
210 <script src
="js/therapy_group_data_view_model.js?v=<?php echo $v_js_includes; ?>"></script
>
211 <script src
="js/tabs_view_model.js?v=<?php echo $v_js_includes; ?>"></script
>
212 <script src
="js/application_view_model.js?v=<?php echo $v_js_includes; ?>"></script
>
213 <script src
="js/frame_proxies.js?v=<?php echo $v_js_includes; ?>"></script
>
214 <script src
="js/dialog_utils.js?v=<?php echo $v_js_includes; ?>"></script
>
217 // Below code block is to prepare certain elements for deciding what links to show on the menu
219 // prepare newcrop globals that are used in creating the menu
220 if ($GLOBALS['erx_enable']) {
221 $newcrop_user_role_sql = sqlQuery("SELECT `newcrop_user_role` FROM `users` WHERE `username` = ?", array($_SESSION['authUser']));
222 $GLOBALS['newcrop_user_role'] = $newcrop_user_role_sql['newcrop_user_role'];
223 if ($GLOBALS['newcrop_user_role'] === 'erxadmin') {
224 $GLOBALS['newcrop_user_role_erxadmin'] = 1;
228 // prepare track anything to be used in creating the menu
229 $track_anything_sql = sqlQuery("SELECT `state` FROM `registry` WHERE `directory` = 'track_anything'");
230 $GLOBALS['track_anything_state'] = ($track_anything_sql['state'] ??
0);
231 // prepare Issues popup link global that is used in creating the menu
232 $GLOBALS['allow_issue_menu_link'] = ((AclMain
::aclCheckCore('encounters', 'notes', '', 'write') || AclMain
::aclCheckCore('encounters', 'notes_a', '', 'write')) &&
233 AclMain
::aclCheckCore('patients', 'med', '', 'write'));
236 <?php
require_once("templates/tabs_template.php"); ?
>
237 <?php
require_once("templates/menu_template.php"); ?
>
238 <?php
require_once("templates/patient_data_template.php"); ?
>
239 <?php
require_once("templates/therapy_group_template.php"); ?
>
240 <?php
require_once("templates/user_data_template.php"); ?
>
241 <?php
require_once("menu/menu_json.php"); ?
>
242 <?php
$userQuery = sqlQuery("select * from users where username = ?", array($_SESSION['authUser'])); ?
>
245 <?php
if (!empty($_SESSION['frame1url']) && !empty($_SESSION['frame1target'])) { ?
>
246 // Use session variables and tabStatus object to set up initial/default first tab
247 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));
250 <?php
if (!empty($_SESSION['frame2url']) && !empty($_SESSION['frame2target'])) { ?
>
251 // 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
252 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));
255 app_view_model
.application_data
.user(new user_data_view_model(<?php
echo json_encode($_SESSION["authUser"])
256 . ',' . json_encode($userQuery['fname'])
257 . ',' . json_encode($userQuery['lname'])
258 . ',' . json_encode($_SESSION['authProvider']); ?
>));
264 min
-height
: 100%
!important
;
265 height
: 100%
!important
;
269 <body
class="min-vw-100">
270 <!-- Below iframe is to support auto logout when timeout is reached
-->
271 <iframe name
="timeout" style
="visibility:hidden; position:absolute; left:0; top:0; height:0; width:0; border:none;" src
="timeout_iframe.php"></iframe
>
272 <!-- Below iframe is to support logout
, which needs to be run in an inner iframe to work
as intended
-->
273 <iframe name
="logoutinnerframe" id
="logoutinnerframe" style
="visibility:hidden; position:absolute; left:0; top:0; height:0; width:0; border:none;" src
="about:blank"></iframe
>
274 <?php
// mdsupport - app settings
276 if (isset($_SESSION['app1'])) {
278 "SELECT title app_url FROM list_options WHERE activity=1 AND list_id=? AND option_id=?",
279 array('apps', $_SESSION['app1'])
281 if ($rs['app_url'] != "main/main_screen.php") {
282 echo '<iframe name="app1" src="../../' . attr($rs['app_url']) . '"
283 style="position: absolute; left: 0; top: 0; height: 100%; width: 100%; border: none;" />';
284 $disp_mainBox = 'style="display: none;"';
288 <div id
="mainBox" <?php
echo $disp_mainBox ?
> >
289 <nav
class="navbar navbar-expand-xl navbar-light bg-light py-0">
290 <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">
291 <?php
echo file_get_contents($GLOBALS['images_static_absolute'] . "/menu-logo.svg"); ?
>
293 <button
class="navbar-toggler mr-auto" type
="button" data
-toggle
="collapse" data
-target
="#mainMenu" aria
-controls
="mainMenu" aria
-expanded
="false" aria
-label
="Toggle navigation">
294 <span
class="navbar-toggler-icon"></span
>
296 <div
class="collapse navbar-collapse" id
="mainMenu" data
-bind
="template: {name: 'menu-template', data: application_data}"></div
>
297 <span id
="userData" data
-bind
="template: {name: 'user-data-template', data: application_data}"></span
>
299 <div id
="attendantData" class="body_title acck" data
-bind
="template: {name: app_view_model.attendant_template_type, data: application_data}">
302 <div
class="body_title" id
="tabs_div" data
-bind
="template: {name: 'tabs-controls', data: application_data}"></div
>
304 <div
class="mainFrames d-flex flex-row" id
="mainFrames_div">
305 <div id
="framesDisplay" data
-bind
="template: {name: 'tabs-frames', data: application_data}"></div
>
309 ko
.applyBindings(app_view_model
);
312 $
('.dropdown-toggle').dropdown();
313 goRepeaterServices();
314 $
('#patient_caret').click(function () {
315 $
('#attendantData').slideToggle();
316 $
('#patient_caret').toggleClass('fa-caret-down').toggleClass('fa-caret-up');
318 if($
('body').css('direction') == "rtl") {
319 $
('.dropdown-menu-right').each(function() {
320 $
(this
).removeClass('dropdown-menu-right');
326 $
('#logo_menu').focus();
328 $
('#anySearchBox').keypress(function (event
) {
329 if (event
.which
=== 13 || event
.keyCode
=== 13) {
330 event
.preventDefault();
331 $
('#search_globals').mousedown();
334 document
.addEventListener('touchstart', {}); //specifically added for iOS devices, especially in iframes