Responsive Vertical Menu For Tab Based Layout Take 2 (#2431)
[openemr.git] / interface / main / tabs / main.php
blobe8faf99d57d66190bfa6e1202bf62215fa9808af
1 <?php
2 /**
3 * main.php
5 * @package OpenEMR
6 * @link http://www.open-emr.org
7 * @author Kevin Yeh <kevin.y@integralemr.com>
8 * @author Brady Miller <brady.g.miller@gmail.com>
9 * @author Ranganath Pathak <pathak@scrs1.org>
10 * @copyright Copyright (c) 2016 Kevin Yeh <kevin.y@integralemr.com>
11 * @copyright Copyright (c) 2016 Brady Miller <brady.g.miller@gmail.com>
12 * @copyright Copyright (c) 2019 Ranganath Pathak <pathak@scrs1.org>
13 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
17 require_once('../../globals.php');
18 require_once $GLOBALS['srcdir'].'/ESign/Api.php';
20 use Esign\Api;
21 use OpenEMR\Core\Header;
23 // ensure token_main matches so this script can not be run by itself
24 if ((empty($_SESSION['token_main_php'])) ||
25 (empty($_GET['token_main'])) ||
26 ($_GET['token_main'] != $_SESSION['token_main_php'])) {
27 die(xlt('Authentication Error'));
29 // this will not allow copy/paste of the link to this main.php page or a refresh of this main.php page
30 unset($_SESSION['token_main_php']);
32 $esignApi = new Api();
34 ?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
35 <html>
36 <head>
37 <title><?php echo text($openemr_name); ?></title>
39 <meta name="viewport" content="width=device-width, initial-scale=1.0">
41 <script type="text/javascript">
42 <?php require($GLOBALS['srcdir'] . "/restoreSession.php"); ?>
44 var isPortalEnabled = "<?php echo $GLOBALS['portal_onsite_two_enable'] == 1; ?>";
46 // Since this should be the parent window, this is to prevent calls to the
47 // window that opened this window. For example when a new window is opened
48 // from the Patient Flow Board or the Patient Finder.
49 window.opener = null;
51 // This flag indicates if another window or frame is trying to reload the login
52 // page to this top-level window. It is set by javascript returned by auth.inc
53 // and is checked by handlers of beforeunload events.
54 var timed_out = false;
56 // Include this variable for backward compatibility
57 var loadedFrameCount = 0;
58 var tab_mode=true;
59 function allFramesLoaded() {
60 // Stub function for backward compatibility with frame race condition mechanism
61 return true;
64 function goRepeaterServices(){
65 // Ensure send the skip_timeout_reset parameter to not count this as a manual entry in the
66 // timing out mechanism in OpenEMR.
68 // Send the skip_timeout_reset parameter to not count this as a manual entry in the
69 // timing out mechanism in OpenEMR.
70 top.restoreSession();
71 $.post("<?php echo $GLOBALS['webroot']; ?>/library/ajax/dated_reminders_counter.php",
73 skip_timeout_reset: "1",
74 csrf_token_form: "<?php echo attr(collectCsrfToken()); ?>"
76 function(data) {
77 // Go knockout.js
78 app_view_model.application_data.user().messages(data);
81 // Notify App for various portal alerts
82 if (isPortalEnabled) {
83 top.restoreSession();
84 $.post("<?php echo $GLOBALS['webroot']; ?>/library/ajax/dated_reminders_counter.php",
86 skip_timeout_reset: "1",
87 isPortal: "1",
88 csrf_token_form: "<?php echo attr(collectCsrfToken()); ?>"
90 function (counts) {
91 data = JSON.parse(counts);
92 let mail = data.mailCnt;
93 let chats = data.chatCnt;
94 let audits = data.auditCnt;
95 let payments = data.paymentCnt;
96 let total = data.total;
97 let enable = (1 * mail) + (1 * audits); // payments are among audits.
99 app_view_model.application_data.user().portal(enable);
100 if (enable) {
101 app_view_model.application_data.user().portalAlerts(total);
102 app_view_model.application_data.user().portalAudits(audits);
103 app_view_model.application_data.user().portalMail(mail);
104 app_view_model.application_data.user().portalChats(chats);
105 app_view_model.application_data.user().portalPayments(payments);
111 top.restoreSession();
112 // run background-services
113 $.post("<?php echo $GLOBALS['webroot']; ?>/library/ajax/execute_background_services.php",
115 skip_timeout_reset: "1",
116 ajax: "1",
117 csrf_token_form: "<?php echo attr(collectCsrfToken()); ?>"
121 // auto run this function every 60 seconds
122 var repeater = setTimeout("goRepeaterServices()", 60000);
125 function isEncounterLocked( encounterId ) {
126 <?php if ($esignApi->lockEncounters()) { ?>
127 // If encounter locking is enabled, make a syncronous call (async=false) to check the
128 // DB to see if the encounter is locked.
129 // Call restore session, just in case
130 top.restoreSession();
131 $.ajax({
132 type: 'POST',
133 url: '<?php echo $GLOBALS['webroot']?>/interface/esign/index.php?module=encounter&method=esign_is_encounter_locked',
134 data: { encounterId : encounterId },
135 success: function( data ) {
136 encounter_locked = data;
138 dataType: 'json',
139 async:false
141 return encounter_locked;
142 <?php } else { ?>
143 // If encounter locking isn't enabled then always return false
144 return false;
145 <?php } ?>
147 // some globals to access using top.variable
148 var userDebug = <?php echo js_escape($GLOBALS['user_debug']); ?>;
149 var webroot_url = <?php echo js_escape($web_root); ?>;
150 var jsLanguageDirection = <?php echo js_escape($_SESSION['language_direction']); ?>;
151 </script>
153 <?php Header::setupHeader(["knockout","tabs-theme",'jquery-ui']); ?>
156 <link rel="shortcut icon" href="<?php echo $GLOBALS['images_static_relative']; ?>/favicon.ico" />
158 <script type="text/javascript" src="js/custom_bindings.js?v=<?php echo $v_js_includes; ?>"></script>
159 <script type="text/javascript" src="js/user_data_view_model.js?v=<?php echo $v_js_includes; ?>"></script>
160 <script type="text/javascript" src="js/patient_data_view_model.js?v=<?php echo $v_js_includes; ?>"></script>
161 <script type="text/javascript" src="js/therapy_group_data_view_model.js?v=<?php echo $v_js_includes; ?>"></script>
163 <script type="text/javascript">
164 // Create translations to be used in the menuActionClick() function in below js/tabs_view_model.js script
165 var xl_strings_tabs_view_model = <?php echo json_encode(array(
166 'encounter_locked' => xla('This encounter is locked. No new forms can be added.'),
167 'must_select_patient' => $GLOBALS['enable_group_therapy'] ? xla('You must first select or add a patient or therapy group.') : xla('You must first select or add a patient.'),
168 'must_select_encounter' => xla('You must first select or create an encounter.'),
169 'new' => xla('New')
172 // Set the csrf_token_js token that is used in the below js/tabs_view_model.js script
173 var csrf_token_js = <?php echo js_escape(collectCsrfToken()); ?>;
174 </script>
175 <script type="text/javascript" src="js/tabs_view_model.js?v=<?php echo $v_js_includes; ?>"></script>
177 <script type="text/javascript" src="js/application_view_model.js?v=<?php echo $v_js_includes; ?>"></script>
178 <script type="text/javascript" src="js/frame_proxies.js?v=<?php echo $v_js_includes; ?>"></script>
179 <script type="text/javascript" src="js/dialog_utils.js?v=<?php echo $v_js_includes; ?>"></script>
181 <?php
182 // Below code block is to prepare certain elements for deciding what links to show on the menu
184 // prepare newcrop globals that are used in creating the menu
185 if ($GLOBALS['erx_enable']) {
186 $newcrop_user_role_sql = sqlQuery("SELECT `newcrop_user_role` FROM `users` WHERE `username` = ?", array($_SESSION['authUser']));
187 $GLOBALS['newcrop_user_role'] = $newcrop_user_role_sql['newcrop_user_role'];
188 if ($GLOBALS['newcrop_user_role'] === 'erxadmin') {
189 $GLOBALS['newcrop_user_role_erxadmin'] = 1;
193 // prepare track anything to be used in creating the menu
194 $track_anything_sql = sqlQuery("SELECT `state` FROM `registry` WHERE `directory` = 'track_anything'");
195 $GLOBALS['track_anything_state'] = $track_anything_sql['state'];
196 // prepare Issues popup link global that is used in creating the menu
197 $GLOBALS['allow_issue_menu_link'] = ((acl_check('encounters', 'notes', '', 'write') || acl_check('encounters', 'notes_a', '', 'write')) &&
198 acl_check('patients', 'med', '', 'write'));
201 <?php require_once("templates/tabs_template.php"); ?>
202 <?php require_once("templates/menu_template.php"); ?>
203 <?php require_once("templates/patient_data_template.php"); ?>
204 <?php require_once("templates/therapy_group_template.php"); ?>
205 <?php require_once("templates/user_data_template.php"); ?>
206 <?php require_once("menu/menu_json.php"); ?>
207 <?php $userQuery = sqlQuery("select * from users where username = ?", array($_SESSION['authUser']));?>
208 <?php $width = $GLOBALS['vertical_responsive_menu']; //will be vertical menu at and below this width
212 <script type="text/javascript">
213 <?php if (!empty($_SESSION['frame1url']) && !empty($_SESSION['frame1target'])) { ?>
214 app_view_model.application_data.tabs.tabsList()[0].url(<?php echo json_encode("../".$_SESSION['frame1url']); ?>);
215 app_view_model.application_data.tabs.tabsList()[0].name(<?php echo json_encode($_SESSION['frame1target']); ?>);
216 <?php } ?>
218 <?php if (!empty($_SESSION['frame2url']) && !empty($_SESSION['frame2target'])) { ?>
219 app_view_model.application_data.tabs.tabsList()[1].url(<?php echo json_encode("../".$_SESSION['frame2url']); ?>);
220 app_view_model.application_data.tabs.tabsList()[1].name(<?php echo json_encode($_SESSION['frame2target']); ?>);
221 <?php } ?>
223 app_view_model.application_data.user(new user_data_view_model(<?php echo json_encode($_SESSION{"authUser"})
224 .',' . json_encode($userQuery['fname'])
225 .',' . json_encode($userQuery['lname'])
226 .',' . json_encode($_SESSION['authGroup']); ?>));
228 </script>
229 <script>
230 $(window).on('resize', function() {
232 var win = $(this);
233 var winWidth = $(this).width();
234 if (winWidth > <?php echo js_escape($width); ?>) {
235 $("#tabs_div").removeClass('col-sm-10');
236 $("#mainFrames_div").removeClass('col-sm-10');
237 $("#menu_icon").addClass('fa-bars');
239 $("#username div:first-child" ).addClass("userSection");
240 $(".appMenu_small").addClass('appMenu');
241 $(".appMenu_small").removeClass('appMenu_small');
243 } else if (winWidth <= <?php echo js_escape($width); ?> ){
244 $("#username div:first-child" ).removeClass("userSection");
245 $(".appMenu").addClass('appMenu_small');
246 $(".appMenu").removeClass('appMenu');
249 $(function() {
250 $(window).trigger('resize');// to avoid repeating code triggers above on page open
252 </script>
254 <style>
255 @media only screen and (max-width: <?php echo attr($width); ?>px) {
256 .patientDataColumn
258 width: 100% !important;
259 float: left;
260 display: block;
264 html, body{
266 min-height:100% !important;
267 height:100% !important;
270 </style>
272 </head>
273 <body data-bind="css: responsiveDisplay.objWidth().bodyMain">
274 <!-- Below iframe is to support auto logout when timeout is reached -->
275 <iframe name="timeout" style="visibility:hidden; position:absolute; left:0; top:0; height:0; width:0; border:none;" src="timeout_iframe.php"></iframe>
276 <?php // mdsupport - app settings
277 $disp_mainBox = '';
278 if (isset($_SESSION['app1'])) {
279 $rs = sqlquery(
280 "SELECT title app_url FROM list_options WHERE activity=1 AND list_id=? AND option_id=?",
281 array('apps', $_SESSION['app1'])
283 if ($rs['app_url'] != "main/main_screen.php") {
284 echo '<iframe name="app1" src="../../'.attr($rs['app_url']).'"
285 style="position:absolute; left:0; top:0; height:100%; width:100%; border:none;" />';
286 $disp_mainBox = 'style="display: none;"';
290 <div id="mainBox" <?php echo $disp_mainBox ?> data-bind='attr: {id: responsiveDisplay.objWidth().mainBoxId} '>
292 <div id="dialogDiv"></div>
294 <div class="body_top" id="body_top_div" data-bind='css: responsiveDisplay.objWidth().bodyTopDivWidth'>
295 <div id="logo_menu" >
296 <a href="https://www.open-emr.org" title="OpenEMR <?php echo xla("Website"); ?>" rel="noopener" target="_blank"><img class="logo" id='oemr_logo' alt="openEMR small logo" style="width:20px" border="0" src="<?php echo $GLOBALS['images_static_relative']; ?>/menu-logo.png"></a>
297 <div>
298 <i class="fa fa-2x fa-bars oe-hidden col-sm-2" aria-hidden="true" id='menu_icon' data-bind='css: responsiveDisplay.objWidth().menuIconHide, click: function(){ responsiveDisplay.verticalMenuObservable(); responsiveDisplay.menuIconObservable()}, css2: {"fa-bars" : !responsiveDisplay.oeMenuIcon(), "fa-eye-slash" : responsiveDisplay.oeMenuIcon}'></i>
299 </div>
300 <div class="clearfix" data-bind="css: {'clearfix' : responsiveDisplay.winWidth() <= <?php echo attr($width); ?>}"></div>
301 </div>
302 <div id="menu_items" class="oe-hidden" data-bind=" css2: {'oe-hidden' : !responsiveDisplay.oeVerticalMenu() && responsiveDisplay.winWidth() <= <?php echo attr($width); ?>}">
303 <span id="menu_logo" data-bind="template: {name: 'menu-template', data: application_data} "></span>
304 <div>
305 <span id="userData" data-bind="template: {name: 'user-data-template', data:application_data} "></span>
306 <a href="../../logout.php" rel="noopener" id="logout_link" onclick="top.restoreSession()" data-bind="css: {'oe-hidden' :responsiveDisplay.oeLogoutIcon}" title="<?php echo xla("Logout");?>"><i class="fa fa-2x fa-sign-out" aria-hidden="true" id="logout_icon"></i></a>
307 </div>
308 </div>
309 <div class="clearfix" data-bind="css: {'clearfix' : responsiveDisplay.winWidth() <= <?php echo attr($width); ?>}"></div>
310 </div>
311 <div id="attendantData" class="body_title acck" data-bind="template: {name: app_view_model.attendant_template_type, data: application_data}, css: responsiveDisplay.objWidth().attendantDataWidth + ' ' + responsiveDisplay.objWidth().attendantDataClear ">
312 </div>
314 <div class="body_title" id="tabs_div" data-bind="template: {name: 'tabs-controls', data: application_data}, css: responsiveDisplay.objWidth().tabsDivWidth"> </div>
316 <div class="mainFrames" id="mainFrames_div" style="display: flex;" data-bind="css: responsiveDisplay.objWidth().mainFramesDivWidth + ' ' + responsiveDisplay.objWidth().mainFramesDivFill">
317 <div id="framesDisplay" data-bind="template: {name: 'tabs-frames', data: application_data}, css: responsiveDisplay.objWidth().framesDisplayFill"> </div>
318 </div>
319 </div>
320 <script>
322 var displayViewModel = {
323 winWidth: ko.observable(),
324 winHeight: ko.observable(),
325 winDevice: ko.observable(),
326 objWidth: {}
330 displayViewModel.objWidth = ko.computed(function() {
331 if(this.winWidth() <= <?php echo js_escape($width); ?>){
332 currWidth = {
333 mainBoxId: "mainBox_vertical",
334 mainFramesDivFill: "oe-fill",
335 framesDisplayFill: "oe-fill",
336 menuItemsHide: "oe-hidden",
337 menuIconHide: "",
338 menuHideHide: "oe-hidden"
340 if(this.winWidth() > 1440){
341 currWidth.bodyTopDivWidth = "col-sm-1";
342 currWidth.bodyMain = "body_main_widescreen";
343 } else {
344 currWidth.bodyTopDivWidth = "col-sm-2";
345 currWidth.bodyMain = "body_main";
347 if(this.oeVerticalMenu()){
348 if(this.winWidth() > 1440){
349 currWidth.tabsDivWidth = "col-sm-11";
350 currWidth.mainFramesDivWidth = "col-sm-11";
351 currWidth.bodyTopDivWidth = "col-sm-1";
352 } else {
353 currWidth.tabsDivWidth = "col-sm-10";
354 currWidth.mainFramesDivWidth = "col-sm-10";
355 currWidth.bodyTopDivWidth = "col-sm-2";
357 } else {
358 currWidth.tabsDivWidth = "col-sm-12";
359 currWidth.mainFramesDivWidth = "col-sm-12";
361 if (this.winWidth() <= 767){
362 currWidth.attendantDataClear = "clearfix";
363 currWidth.attendantDataWidth = "";
364 } else if (this.winWidth() > 767){
365 currWidth.attendantDataClear = "";
366 if(this.winWidth() > 1440){
367 currWidth.attendantDataWidth = "col-sm-11";
368 } else{
369 currWidth.attendantDataWidth = "col-sm-10";
372 } else {
373 currWidth = {
374 mainBoxId: "mainBox",
375 bodyTopDivWidth : "",
376 tabsDivWidth: "",
377 mainFramesDivWidth: "",
378 mainFramesDivFill: "",
379 framesDisplayFill: "",
380 menuItemsHide: "",
381 menuIconHide: "oe-hidden",
382 menuHideHide: "oe-hidden",
383 attendantDataClear: "",
384 attendantDataWidth: ""
387 return currWidth;
388 }, displayViewModel);
390 displayViewModel.oeVerticalMenu = ko.observable(false);
391 displayViewModel.oeVerticalDisplay = ko.computed(function(){
392 var vertDispl = displayViewModel.winWidth() > <?php echo js_escape($width); ?> ? false : true;
393 return vertDispl;
394 }, displayViewModel);
396 displayViewModel.verticalMenuObservable = function() {
397 displayViewModel.oeVerticalMenu(!displayViewModel.oeVerticalMenu());
399 displayViewModel.oeMenuIcon = ko.observable(false);
400 displayViewModel.menuIconObservable = function() {
401 displayViewModel.oeMenuIcon(!displayViewModel.oeMenuIcon());
404 displayViewModel.oeLogoutIcon = ko.computed(function(){
405 var logoutIcon = this.winWidth() > <?php echo js_escape($width); ?> ? true : false;
406 return logoutIcon;
407 }, displayViewModel);
408 var $window = $(window);
409 $window.resize(function () {
410 displayViewModel.winWidth($window.width());
411 displayViewModel.winHeight($window.height());
412 if($window.width() > <?php echo js_escape($width); ?>){
413 displayViewModel.winDevice('ipad');
414 } else {
415 displayViewModel.winDevice('bipad');
419 $(function() {
420 $(window).trigger('resize');// to avoid repeating code triggers above on page open
422 ko.bindingHandlers['css2'] = ko.bindingHandlers.css;
423 app_view_model.responsiveDisplay = displayViewModel;
424 </script>
425 <script>
426 $("#dialogDiv").hide();
427 ko.applyBindings(app_view_model);
429 $(function () {
430 $('.dropdown-toggle').dropdown();
431 goRepeaterServices();
432 $('#patient_caret').click(function() {
433 $('#attendantData').slideToggle();
434 $('#patient_caret').toggleClass('fa-caret-down').toggleClass('fa-caret-up');
437 </script>
438 </body>
439 </html>