6 * @link http://www.open-emr.org
7 * @author Ranganath Pathak <pathak@scrs1.org>
8 * @copyright Copyright (c) 2018 Ranganath Pathak <pathak@scrs1.org>
9 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
11 namespace OpenEMR\OeUI
;
13 use OpenEMR\Common\Csrf\CsrfUtils
;
14 use OpenEMR\Core\Header
;
16 Header
::setupHeader(['jquery-ui', 'jquery-ui-base', 'no_jquery', 'no_bootstrap', 'no_fontawesome', 'no_main-theme', 'no_textformat', 'no_dialog' ]);
21 private $action_bot_js;
24 private $action_title;
25 private $action_top_js;
27 private $arrexpandIcon;
29 private $arrOeUiSettings;
30 private $arrow_direction;
32 private $collectToken;
34 private $contractTitle;
35 private $current_state;
36 private $display_help_icon;
37 private $expand_icon_class;
38 private $expand_title;
40 private $expandable_icon;
42 private $header_expand_js;
47 private $jquery_draggable;
54 * Create the html string that will display the formatted heading with selected icons - expandable,
55 * action and help and generate the html code for the help modal and output all the jQuery needed to make it work.
57 * @param array $arrOeUiSettings is an associative array that contains 9 elements, string 'heading_title',
58 * int|bool 'include_patient_name', int|bool 'expandable', array 'expandable_files', string 'action', string 'action_title',
59 * string 'action_href', int|bool 'show_help_icon' and string 'help_file_name'.
60 * The int|bool 'current_state' (expanded = 1, centered = 0) value is obtained from function collectAndOrganizeExpandSetting(array("")),
61 * this function needs an indexed array as an argument (array ('expandable_files')) that contains the file name
62 * of the current file as the first element, the name of any other file that needs to open in a similar state
63 * needs to be included in this array,all names must be unique and have a '_xpd' suffix.
64 * It will be used to generate up to 4 values - string $heading, string $expandable_icon, string $action_icon and string $help_icon
65 * that will form the html string used to output the formatted heading of the page.
66 * If a feature is not required set the corresponding element in the array to an empty string
68 public function __construct($arrOeUiSettings = array())
70 global $v_js_includes;
72 $this->heading
= ($arrOeUiSettings['include_patient_name'] && !empty($arrOeUiSettings['heading_title']))?
$arrOeUiSettings['heading_title'] . " - " . getPatientNameFirstLast($_SESSION['pid']):$arrOeUiSettings['heading_title'];
73 $this->expandable
= $arrOeUiSettings['expandable'];
74 $this->arrFiles
= $arrOeUiSettings['expandable_files'];
75 $this->arrAction
= array($arrOeUiSettings['action'], $arrOeUiSettings['action_title'], $arrOeUiSettings['action_href']);
76 $this->display_help_icon
= $arrOeUiSettings['show_help_icon'];
77 $this->help_file
= $arrOeUiSettings['help_file_name'];
78 if ($arrOeUiSettings['expandable'] && $arrOeUiSettings['expandable_files']) {
79 $this->current_state
= collectAndOrganizeExpandSetting($arrOeUiSettings['expandable_files']);
81 echo "\r\n<script src='" . $GLOBALS['webroot'] . "/library/js/oeUI/universalTooltip.js?v=" . $v_js_includes. "'></script>\r\n";
85 * Creates the html string that will display the formatted heading with selected icons - expandable, action and help.
87 * @return array containing string $heading - the formatted html string of the actual heading and string $container
88 * - the value of the container class 'container' or 'container-fluid'
91 public function pageHeading()
93 $heading = text($this->heading
);
94 if (!empty($heading)) {
95 $arrexpandIcon = $this->expandIcon();// returns and array containing expandable icon string and container class string
96 $action_icon = $this->actionIcon();
97 $help_icon = $this->helpIcon();
98 $expandable_icon = $arrexpandIcon[0];
99 $heading = "<h2>$heading $expandable_icon $action_icon $help_icon</h2>";
101 $heading = "<h2>" . xlt("Please supply a heading") . " <i class='fa fa-smile-o' aria-hidden='true'></i></h2>";
107 * Creates the html string that will display the formatted expandable icon - fa-expand or fa-compress.
109 * @param $expandable - int|bool - whether form is expandable or not and $current_state int|bool - the current state of the form
111 * @return array containing string $expandable_icon - the formatted html string of the expand icon and string
112 * $container - the value of the container class 'container' or 'container-fluid'
115 private function expandIcon($expandable = '', $current_state = '')
117 $current_state = $this->current_state
;
118 $expandable = $this->expandable
;
120 if ($current_state) {
121 $container = 'container-fluid';
122 $expand_title = xl('Click to Contract and set to henceforth open in Centered mode');
123 $expand_icon_class = 'fa-compress oe-center';
125 $container = 'container';
126 $expand_title = xl('Click to Expand and set to henceforth open in Expanded mode');
127 $expand_icon_class = 'fa-expand oe-expand';
129 $expandable_icon = '';
131 $expandable_icon = "<i id='exp_cont_icon' class='oe-superscript-small expand_contract fa " . attr($expand_icon_class) . "'" . " title='" . attr($expand_title) . "'
132 aria-hidden='true'></i>";
134 return array($expandable_icon, $container);
138 * Will return the container class value either 'container' or 'container-fluid'
140 * @return string $container that will reflect the current state of the page i.e. expanded = 'container-fluid' or centered = 'container'
142 public function oeContainer()
144 $arrexpandIcon = $this->expandIcon();
145 $container = $arrexpandIcon[1] ?
$arrexpandIcon[1]:'container';
150 * Creates the html string that will display the formatted action/re-direction icon - for conceal, reveal, search, reset, link and back.
152 * @param array $arrAction has 3 elements - string - type of action, string - optional title to be used in tooltip
153 * and string - the file name or url to be redirected to, only the 3 re-directions reset, link or back need a href value
154 * the 3 actions conceal, reveal, search will only use the default title strings
156 * @return string $action_icon that will output the action icon html string
159 private function actionIcon($arrAction = array())
161 $arrAction = $this->arrAction
;
163 $action = $arrAction[0];
164 $action_title = $arrAction[1];
165 $action_href = $arrAction[2];
167 $action_href = ($action_href) ?
$action_href : "#";
170 $action_title = ($action_title) ?
$action_title : xl("Reset");
171 $action_icon = "<a href='" . attr($action_href) ."' onclick='top.restoreSession()'><i id='advanced-action' class='fa fa-undo fa-2x small' title='" . attr($action_title) ."' aria-hidden='true'></i></a>";
174 $action_title = xl("Click to Hide"); // default needed for jQuery to function
175 $action_icon = "<i id='show_hide' class='fa fa-2x small fa-eye-slash' title='" . attr($action_title) . "'></i>";
178 $action_title = xl("Click to Show"); // default needed for jQuery to function
179 $action_icon = "<i id='show_hide' class='fa fa-2x small fa-eye' title='" . attr($action_title) . "'></i>";
182 $action_title = xl("Click to show search"); // default needed for jQuery to function
183 $action_icon = "<i id='show_hide' class='fa fa-search-plus fa-2x small' title='" . attr($action_title) . "'></i>";
186 if (strpos($action_href, 'http') !== false) {
191 $action_title = ($action_title) ?
$action_title : xl("Click to go to page");
192 $action_icon = "<a href='" . attr($action_href) . "' target = '" .attr($target)."' onclick='top.restoreSession()'><i id='advanced-action' class='fa fa-external-link fa-2x small' title='" . attr($action_title) ."' aria-hidden='true'></i></a>";
195 $action_title = ($action_title) ?
$action_title : xl("Go Back");
196 if ($_SESSION ['language_direction'] == 'ltr') {
197 $arrow_direction = 'fa-arrow-circle-left';
198 } elseif ($_SESSION ['language_direction'] == 'rtl') {
199 $arrow_direction = 'fa-arrow-circle-right';
201 $action_icon = "<a href='" . attr($action_href) ."' onclick='top.restoreSession()'><i id='advanced-action' class='fa " . attr($arrow_direction) . " fa-2x small' title='" . attr($action_title) ."' aria-hidden='true'></i></a>";
210 * Creates the html string that will display the formatted help icon - fa-question-circle.
212 * @param int|bool $display_help_icon
214 * @return string $help_icon that will output the help icon html string
217 private function helpIcon($display_help_icon = '')
220 $display_help_icon = $this->display_help_icon
;
221 if ($display_help_icon) {
222 if ($_SESSION ['language_direction'] == 'ltr') {
223 $help_icon_title = xl("To enable help - Go to the User Name on top right > Settings > Features > Enable Help Modal");
224 } elseif ($_SESSION ['language_direction'] == 'rtl') {
225 $help_icon_title = xl("To enable help - Go to the User Name on top left > Settings > Features > Enable Help Modal");
227 if ($GLOBALS['enable_help'] == 1) {
228 $help_icon = '<a class="oe-pull-away oe-help-redirect" data-target="#myModal" data-toggle="modal" href="#" id="help-href" name="help-href" style="color:#676666" title="' . xla("Click to view Help") . '"><i class="fa fa-question-circle" aria-hidden="true"></i></a>';
229 } elseif ($GLOBALS['enable_help'] == 2) {
230 $help_icon = '<a class="oe-pull-away oe-help-redirect" data-target="#myModal" data-toggle="modal" href="#" id="help-href" name="help-href" style="color:#DCD6D0 !Important" title="' . attr($help_icon_title) . '"><i class="fa fa-question-circle" aria-hidden="true"></i></a>';
231 } elseif ($GLOBALS['enable_help'] == 0) {
239 * Output the help modal html along with the jQuery to make it work.
241 * $param string $help_file - name of the help file to be displayed, must exists in Documentation/help_files
242 * will echo the entire html string of the help modal and the jQuery, needs to be used as the first line after the container div
247 private function helpFileModal($help_file = '')
249 $help_file = $this->help_file
;
250 $close = xla("Close");
251 $print = xla("Print");
253 $help_file = attr($help_file);
254 $help_file = $GLOBALS['webroot']."/Documentation/help_files/$help_file";
255 $modal_body = "<iframe src=\"$help_file\" id='targetiframe' style='height:100%; width:100%; overflow-x: hidden; border:none'
256 allowtransparency='true'></iframe>";
258 $modal_body = "<h3> <i class='fa fa-exclamation-triangle oe-text-red' aria-hidden='true'></i> " . xlt("Check if a help file exists for this page in") . " " . text("Documentation/help_files") . ".<br><br>" . xlt("Then pass it's name as a value to the element" ." " . text("'help_file_name'") . " " . "in the associative array") . " " . text("\$arrOeUiSettings"). ".<br><br>" . xlt("If the help file does not exist create one and place it in") . " " . text("Documentation/help_files") . ".<br>" . "</h3>";
260 $help_modal = <<<HELP
262 <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
263 <div class="modal-dialog modal-lg">
264 <div class="modal-content oe-modal-content" style="height:700px">
265 <div class="modal-header clearfix">
266 <button type="button" class="close" data-dismiss="modal" aria-label="$close">
267 <span aria-hidden="true" style="color:#000000; font-size:1.5em;">×</span></button>
269 <div class="modal-body" style="height:80%;">
272 <div class="modal-footer" style="margin-top:0px;">
273 <button class="btn btn-link btn-cancel oe-pull-away" data-dismiss="modal" type="button">$close</button>
274 <!--<button class="btn btn-default btn-print oe-pull-away" data-dismiss="modal" id="print-help-href" type="button">$print</button>-->
281 echo $help_modal. "\r\n";
283 $jquery_draggable = <<<JQD
286 $('.modal-dialog').draggable({
287 handle: ".modal-header, .modal-footer"
289 $( ".modal-content" ).resizable({
294 var helpTitle = $('#help-href').prop('title');
295 $('#myModal').on('hidden.bs.modal', function (e) {
296 $('#help-href').prop('title', '');
298 $('#help-href').focus( function() {
299 $('#help-href').prop('title', helpTitle);
303 echo $jquery_draggable. "\r\n";
308 * Generates the jQuery for the form to toggle between 'expanded' and 'centered' states.
310 * @param array $arrFiles - that contains the files names that need to be toggled between 'expanded' and 'centered' states
311 * will generate the jQuery that will be outputted on the page by function oeBelowContainerDiv()
316 private function headerExpandJs($arrFiles = array())
318 $expandTitle = xlj("Click to Contract and set to henceforth open in Centered mode");
319 $contractTitle = xlj("Click to Expand and set to henceforth open in Expanded mode");
320 $arrFiles = json_encode($this->arrFiles
);
321 $web_root = $GLOBALS['webroot'];
322 $collectToken = js_escape(CsrfUtils
::collectCsrfToken());
323 $header_expand_js = <<<EXP
325 $(window).on('resize', function() {//hide icon on smaller devices as width is almost 100%
326 var winWidth = $(this).width();
327 if (winWidth < 900) {
328 $("#exp_cont_icon").addClass ("hidden");
330 $("#exp_cont_icon").removeClass ("hidden");
334 $(window).trigger('resize');// to avoid repeating code triggers above on page open
338 $('.expand_contract').click(function () {
340 var expandTitle = {$expandTitle};
341 var contractTitle = {$contractTitle};
342 var arrFiles = {$arrFiles};
343 if ($(this).is('.oe-expand')) {
344 elementTitle = expandTitle;
345 $(this).toggleClass('fa-expand fa-compress');
346 $(this).toggleClass('oe-expand oe-center');
347 $('#container_div').toggleClass('container container-fluid');
348 if ($(arrFiles).length) {
349 $.each(arrFiles, function (index, value) {
352 "{$web_root}/library/ajax/user_settings.php",
354 target: arrFiles[index].trim(),
356 csrf_token_form: {$collectToken}
361 } else if ($(this).is('.oe-center')) {
362 elementTitle = contractTitle;
363 $(this).toggleClass('fa-compress fa-expand');
364 $(this).toggleClass('oe-center oe-expand');
365 $('#container_div').toggleClass('container-fluid container');
366 if ($(arrFiles).length) {
367 $.each(arrFiles, function (index, value) {
369 "{$web_root}/library/ajax/user_settings.php",
371 target: arrFiles[index].trim(),
373 csrf_token_form: {$collectToken}
379 $(this).prop('title', elementTitle);
384 echo $header_expand_js ."\r\n";
389 * Generates the jQuery to enable an element to toggle between hidden and revealed states.
391 * @param array $arrAction - first element contains the string for type of action - needed only for actions search, reveal and conceal
392 * will generate the jQuery that will be outputted on the page by function oeBelowContainerDiv()
397 private function headerActionJs($arrAction = array())
399 $arrAction = $this->arrAction
;
400 $action_top_js = <<<SHWTOP
403 $('#show_hide').click(function () {
404 var elementTitle = '';
406 echo $action_top_js ."\r\n";
408 if ($arrAction[0] == 'search') {
409 echo "var showTitle = " . xlj('Click to show search') . "\r\n;";
410 echo "var hideTitle = " . xlj('Click to hide search') . "\r\n;";
411 } elseif ($arrAction[0] == 'reveal' ||
$arrAction[0] == 'conceal') {
412 echo "var hideTitle = " . xlj('Click to Hide') . "\r\n;";
413 echo "var showTitle = " . xlj('Click to Show') . "\r\n;";
416 if ($arrAction[0] == 'search') {
417 echo "$(this).toggleClass('fa-search-plus fa-search-minus'); \r\n";
418 } elseif ($arrAction[0] == 'reveal') {
419 echo "$(this).toggleClass('fa-eye fa-eye-slash'); \r\n";
420 } elseif ($arrAction[0] == 'conceal') {
421 echo "$(this).toggleClass('fa-eye-slash fa-eye'); \r\n";
424 $action_bot_js = <<<SHWBOT
425 $('.hideaway').toggle(500);
426 if ($(this).is('.fa-eye') || $(this).is('.fa-search-plus')) {
427 elementTitle = showTitle;
428 } else if ($(this).is('.fa-eye-slash') || $(this).is('.fa-search-minus')) {
429 elementTitle = hideTitle;
431 $(this).prop('title', elementTitle);
436 echo $action_bot_js . "\r\n";
441 * Output the help modal html with needed jQuery, jQuery to enable an element to toggle between 'hidden' and 'revealed states'
442 * and/or 'expand' and 'centered' states.
444 * based on the values in the associative array $arrOeUiSettings the relevant code will be outputted to the page
445 * for consistency always call this function just below the container div on the page
450 public function oeBelowContainerDiv()
452 $this->display_help_icon ?
$this->helpFileModal() : '';
453 $this->expandable ?
$this->headerExpandJs() : '';
454 $this->arrAction
[0] ?
$this->headerActionJs() : '';