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']); ?
>;
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
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", {
102 credentials
: 'same-origin',
104 }).then((response
) => {
105 if (response
.status
!== 200) {
106 console
.log('Reminders start failed. Status Code: ' + response
.status
);
109 return response
.json();
111 if (data
.timeoutMessage
&& (data
.timeoutMessage
== 'timeout')) {
112 // timeout has happened, so logout
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
);
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 () {
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", {
150 credentials
: 'same-origin',
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
);
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
172 let url
= webroot_url +
"/interface/esign/index.php?module=encounter&method=esign_is_encounter_locked";
176 data
: {encounterId
: encounterId
},
177 success
: function (data
) {
178 encounter_locked
= data
;
183 return encounter_locked
;
185 // If encounter locking isn't enabled then always return false
191 <?php Header
::setupHeader(['knockout', 'tabs-theme', 'i18next']); ?
>
193 // set up global translations for js
194 function setupI18n(lang_id
) {
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',
199 }).then(response
=> response
.json())
201 setupI18n(<?php
echo js_escape($_SESSION['language_choice']); ?
>).then(translationsJson
=> {
209 translation
: translationsJson
214 console
.log(error
.message
);
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
>
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'])); ?
>
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));
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));
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']); ?
>));
275 min
-height
: 100%
!important
;
276 height
: 100%
!important
;
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
285 if (isset($_SESSION['app1'])) {
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"); ?
>
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
>
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
>
308 <div id
="attendantData" class="body_title acck" data
-bind
="template: {name: app_view_model.attendant_template_type, data: application_data}">
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
>
318 ko
.applyBindings(app_view_model
);
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');
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
343 goRepeaterServices();