UX - Expandable Search Patient By Any Demographics - Take 3 (#2523)
[openemr.git] / src / OeUI / OemrUI.php
blobb3051a268666a563b2d3782b72e24751ee740b28
1 <?php
2 /**
3 * OemrUI class.
5 * @package OpenEMR
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' ]);
18 class OemrUI
20 private $action;
21 private $action_bot_js;
22 private $action_href;
23 private $action_icon;
24 private $action_title;
25 private $action_top_js;
26 private $arrAction;
27 private $arrexpandIcon;
28 private $arrFiles;
29 private $arrOeUiSettings;
30 private $arrow_direction;
31 private $close;
32 private $collectToken;
33 private $container;
34 private $contractTitle;
35 private $current_state;
36 private $display_help_icon;
37 private $expand_icon_class;
38 private $expand_title;
39 private $expandable;
40 private $expandable_icon;
41 private $expandTitle;
42 private $header_expand_js;
43 private $heading;
44 private $help_file;
45 private $help_icon;
46 private $help_modal;
47 private $jquery_draggable;
48 private $modal_body;
49 private $print;
50 private $target;
51 private $web_root;
53 /**
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";
84 /**
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>";
100 } else {
101 $heading = "<h2>" . xlt("Please supply a heading") . " <i class='fa fa-smile-o' aria-hidden='true'></i></h2>";
103 return $heading;
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';
124 } else {
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 = '';
130 if ($expandable) {
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';
146 return $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;
162 if ($arrAction) {
163 $action = $arrAction[0];
164 $action_title = $arrAction[1];
165 $action_href = $arrAction[2];
167 $action_href = ($action_href) ? $action_href : "#";
168 switch ($action) {
169 case "reset":
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>";
172 break;
173 case "conceal":
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>";
176 break;
177 case "reveal":
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>";
180 break;
181 case "search":
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>";
184 break;
185 case "link":
186 if (strpos($action_href, 'http') !== false) {
187 $target = '_blank';
188 } else {
189 $target = '_self';
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>";
193 break;
194 case "back":
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>";
202 break;
203 default:
204 $action_icon = '';
206 return $action_icon;
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 = '')
219 $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) {
232 $help_icon = '';
235 return $help_icon;
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
244 * @return void
247 private function helpFileModal($help_file = '')
249 $help_file = $this->help_file;
250 $close = xla("Close");
251 $print = xla("Print");
252 if ($help_file) {
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>";
257 } else {
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
261 <div class="row">
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>
268 </div>
269 <div class="modal-body" style="height:80%;">
270 $modal_body
271 </div>
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>-->
275 </div>
276 </div>
277 </div>
278 </div>
279 </div>
280 HELP;
281 echo $help_modal. "\r\n";
283 $jquery_draggable = <<<JQD
284 <script>
285 // Jquery draggable
286 $('.modal-dialog').draggable({
287 handle: ".modal-header, .modal-footer"
289 $( ".modal-content" ).resizable({
290 aspectRatio: true,
291 minHeight: 300,
292 minWidth: 300
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);
301 </script>
302 JQD;
303 echo $jquery_draggable. "\r\n";
304 return;
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()
313 * @return void
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
324 <script>
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");
329 } else {
330 $("#exp_cont_icon").removeClass ("hidden");
333 $(function() {
334 $(window).trigger('resize');// to avoid repeating code triggers above on page open
337 $(function () {
338 $('.expand_contract').click(function () {
339 var elementTitle;
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) {
351 $.post(
352 "{$web_root}/library/ajax/user_settings.php",
354 target: arrFiles[index].trim(),
355 setting: 1,
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) {
368 $.post(
369 "{$web_root}/library/ajax/user_settings.php",
371 target: arrFiles[index].trim(),
372 setting: 0,
373 csrf_token_form: {$collectToken}
379 $(this).prop('title', elementTitle);
382 </script>
383 EXP;
384 echo $header_expand_js ."\r\n";
385 return;
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()
394 * @return void
397 private function headerActionJs($arrAction = array())
399 $arrAction = $this->arrAction;
400 $action_top_js = <<<SHWTOP
401 <script>
402 $(function () {
403 $('#show_hide').click(function () {
404 var elementTitle = '';
405 SHWTOP;
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);
434 </script>
435 SHWBOT;
436 echo $action_bot_js . "\r\n";
437 return;
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
447 * @return void
450 public function oeBelowContainerDiv()
452 $this->display_help_icon ? $this->helpFileModal() : '';
453 $this->expandable ? $this->headerExpandJs() : '';
454 $this->arrAction[0] ? $this->headerActionJs() : '';
455 return;