6 * @link http://www.open-emr.org
7 * @author Rod Roark <rod@sunsetsystems.com>
8 * @author Jerry Padgett <sjpadgett@gmail.com>
9 * @author Brady Miller <brady.g.miller@gmail.com>
10 * @copyright Copyright (c) 2014-2019 Rod Roark <rod@sunsetsystems.com>
11 * @copyright Copyright (c) 2017 Jerry Padgett <sjpadgett@gmail.com>
12 * @copyright Copyright (c) 2017-2018 Brady Miller <brady.g.miller@gmail.com>
13 * @license https://github.com/openemr/openemr/blob/master/LICENSE GNU General Public License 3
16 require_once("../globals.php");
17 require_once("$srcdir/acl.inc");
19 use OpenEMR\Common\Logging\EventAuditLogger
;
20 use OpenEMR\Core\Header
;
22 function collectLayoutNames($condition, $mapping = '')
25 $gres = sqlStatement("SELECT grp_form_id, grp_title, grp_mapping " .
26 "FROM layout_group_properties WHERE " .
27 "grp_group_id = '' AND grp_activity = 1 AND $condition " .
28 "ORDER BY grp_mapping, grp_seq, grp_title");
29 while ($grow = sqlFetchArray($gres)) {
30 $tmp = $mapping ?
$mapping : $grow['grp_mapping'];
32 $tmp = '(' . xl('No Name') . ')';
34 $layouts[$grow['grp_form_id']] = array($tmp, $grow['grp_title']);
38 collectLayoutNames("grp_form_id NOT LIKE 'LBF%' AND grp_form_id NOT LIKE 'LBT%'", xl('Core'));
39 collectLayoutNames("grp_form_id LIKE 'LBT%'", xl('Transactions'));
40 collectLayoutNames("grp_form_id LIKE 'LBF%'", '');
42 // Include predefined Validation Rules from list
43 $validations = array();
44 $lres = sqlStatement("SELECT * FROM list_options " .
45 "WHERE list_id = 'LBF_Validations' AND activity = 1 ORDER BY seq, title");
46 while ($lrow = sqlFetchArray($lres)) {
47 $validations[$lrow['option_id']] = xl_list_label($lrow['title']);
50 // Field modifier objects in script
51 // array of the data_types of the fields
53 "1" => xl("List box"),
55 "3" => xl("Textarea"),
56 "4" => xl("Text-date"),
57 "10" => xl("Providers"),
58 "11" => xl("Providers NPI"),
59 "12" => xl("Pharmacies"),
61 "14" => xl("Organizations"),
62 "15" => xl("Billing codes"),
63 "16" => xl("Insurances"),
64 "18" => xl("Visit Categories"),
65 "21" => xl("Checkbox(es)"),
66 "22" => xl("Textbox list"),
67 "23" => xl("Exam results"),
68 "24" => xl("Patient allergies"),
69 "25" => xl("Checkboxes w/text"),
70 "26" => xl("List box w/add"),
71 "27" => xl("Radio buttons"),
72 "28" => xl("Lifestyle status"),
73 "31" => xl("Static Text"),
74 "32" => xl("Smoking Status"),
75 "33" => xl("Race/Ethnicity"),
76 "34" => xl("NationNotes"),
77 "35" => xl("Facilities"),
78 "36" => xl("Multiple Select List"),
79 "40" => xl("Image canvas"),
90 function nextGroupOrder($order)
94 } else if ($order == 'Z') {
97 $order = chr(ord($order) +
1);
103 // This returns HTML for a <select> that allows choice of a layout group.
104 // Included also are parent groups containing only sub-groups. Groups are listed
105 // in the same order as they appear in the layout.
107 function genGroupSelector($name, $layout_id, $default = '')
110 "SELECT grp_group_id, grp_title " .
111 "FROM layout_group_properties WHERE " .
112 "grp_form_id = ? AND grp_group_id != '' ORDER BY grp_group_id",
115 $s = "<select class='form-control' name='" . xla($name) . "'>";
116 $s .= "<option value=''>" . xlt('None') . "</option>";
119 while ($row = sqlFetchArray($res)) {
120 $thisid = $row['grp_group_id'];
122 // Compute number of initial matching groups.
123 while ($i < strlen($thisid) && $i < strlen($arrid) && $thisid[$i] == $arrid[$i]) {
126 $arr = array_slice($arr, 0, $i); // discard the rest
127 while ($i < (strlen($arrid) - 1)) {
128 $arr[$i++
] = '???'; // should not happen
130 $arr[$i] = $row['grp_title'];
132 foreach ($arr as $part) {
138 $s .= "<option value='" . attr($thisid) . "'";
139 if ($thisid == $default) {
142 $s .= ">" . text($gval) . "</option>";
148 // Compute a new group ID that will become layout_options.group_id and
149 // layout_group_properties.grp_group_id.
150 // $parent is a string of zero or more sequence prefix characters.
151 // If there is a nonempty $parent then its ID will be the prefix for the
152 // new ID and the sequence prefix will be computed within the parent.
154 function genGroupId($parent)
157 $results = sqlStatement(
158 "SELECT grp_group_id " .
159 "FROM layout_group_properties WHERE " .
160 "grp_form_id = ? AND grp_group_id LIKE ?",
161 array($layout_id, "$parent_%")
164 while ($result = sqlFetchArray($results)) {
165 $tmp = substr($result['grp_group_id'], strlen($parent), 1);
166 if ($tmp >= $maxnum) {
167 $maxnum = nextGroupOrder($tmp);
170 return $parent . $maxnum;
173 // Changes a group's ID from and to the specified IDs. This also works for groups
174 // that have sub-groups, in which case only the appropriate parent portion of
175 // the ID is changed.
177 function fuzzyRename($from, $to)
181 $query = "UPDATE layout_options SET group_id = concat(?, substr(group_id, ?)) " .
182 "WHERE form_id = ? AND group_id LIKE ?";
183 sqlStatement($query, array($to, strlen($from) +
1, $layout_id, "$from%"));
185 $query = "UPDATE layout_group_properties SET grp_group_id = concat(?, substr(grp_group_id, ?)) " .
186 "WHERE grp_form_id = ? AND grp_group_id LIKE ?";
187 sqlStatement($query, array($to, strlen($from) +
1, $layout_id, "$from%"));
190 // Swaps the positions of two groups. To the degree they have matching parents,
191 // only the first differing child positions are swapped.
193 function swapGroups($id1, $id2)
196 while ($i < strlen($id1) && $i < strlen($id2) && $id1[$i] == $id2[$i]) {
199 // $i is now the number of matching characters/levels.
200 if ($i < strlen($id1) && $i < strlen($id2)) {
201 $common = substr($id1, 0, $i);
202 $pfx1 = substr($id1, $i, 1);
203 $pfx2 = substr($id2, $i, 1);
204 $tmpname = $common . '#';
205 // To avoid collision use 3 renames.
206 fuzzyRename($common . $pfx1, $common . '#');
207 fuzzyRename($common . $pfx2, $common . $pfx1);
208 fuzzyRename($common . '#', $common . $pfx2);
212 function tableNameFromLayout($layout_id)
214 // Skip layouts that store data in vertical tables.
215 if (substr($layout_id, 0, 3) == 'LBF' ||
substr($layout_id, 0, 3) == 'LBT' ||
$layout_id == "FACUSR") {
218 if ($layout_id == "DEM") {
219 $tablename = "patient_data";
220 } elseif ($layout_id == "HIS") {
221 $tablename = "history_data";
222 } elseif ($layout_id == "SRH") {
223 $tablename = "lists_ippf_srh";
224 } elseif ($layout_id == "CON") {
225 $tablename = "lists_ippf_con";
226 } elseif ($layout_id == "GCA") {
227 $tablename = "lists_ippf_gcac";
229 die(xlt('Internal error in tableNameFromLayout') . '(' . text($layout_id) . ')');
234 // Call this when adding or removing a layout field. This will create or drop
235 // the corresponding table column when appropriate. Table columns are not
236 // dropped if they contain any non-empty values.
237 function addOrDeleteColumn($layout_id, $field_id, $add = true)
239 $tablename = tableNameFromLayout($layout_id);
243 // Check if the column currently exists.
244 $tmp = sqlQuery("SHOW COLUMNS FROM `$tablename` LIKE ?", array($field_id));
245 $column_exists = !empty($tmp);
247 if ($add && !$column_exists) {
248 sqlStatement("ALTER TABLE `$tablename` ADD `" . add_escape_custom($field_id) . "` TEXT");
249 EventAuditLogger
::instance()->newEvent(
251 $_SESSION['authUser'],
252 $_SESSION['authProvider'],
254 "$tablename ADD $field_id"
256 } elseif (!$add && $column_exists) {
257 // Do not drop a column that has any data.
258 $tmp = sqlQuery("SELECT `" . add_escape_custom($field_id) . "` FROM `$tablename` WHERE " .
259 "`" . add_escape_custom($field_id) . "` IS NOT NULL AND `" . add_escape_custom($field_id) . "` != '' LIMIT 1");
260 if (!isset($tmp['field_id'])) {
261 sqlStatement("ALTER TABLE `$tablename` DROP `" . add_escape_custom($field_id) . "`");
262 EventAuditLogger
::instance()->newEvent(
264 $_SESSION['authUser'],
265 $_SESSION['authProvider'],
267 "$tablename DROP $field_id "
273 // Call this before renaming a layout field.
274 // Renames the table column (if applicable) and returns a result status:
275 // -1 = There is no table for this layout (not an error).
276 // 0 = Rename successful.
277 // 2 = There is no column having the old name.
278 // 3 = There is already a column having the new name.
280 function renameColumn($layout_id, $old_field_id, $new_field_id)
282 $tablename = tableNameFromLayout($layout_id);
284 return -1; // Indicate rename is not relevant.
286 // Make sure old column exists.
287 $colarr = sqlQuery("SHOW COLUMNS FROM `$tablename` LIKE ?", array($old_field_id));
288 if (empty($colarr)) {
289 // Error, old name does not exist.
292 // Make sure new column does not exist.
293 $tmp = sqlQuery("SHOW COLUMNS FROM `$tablename` LIKE ?", array($new_field_id));
295 // Error, new name already in use.
298 // With MySQL you can't change just the name, you have to specify the column definition too.
299 $colstr = $colarr['Type'];
300 if ($colarr['Null'] == 'NO') {
301 $colstr .= " NOT NULL";
303 if ($colarr['Default'] !== null) {
304 $colstr .= " DEFAULT '" . add_escape_custom($colarr['Default']) . "'";
306 if ($colarr['Extra']) {
307 $colstr .= " " . add_escape_custom($colarr['Extra']);
309 $query = "ALTER TABLE `$tablename` CHANGE `" . add_escape_custom($old_field_id) . "` `" . add_escape_custom($new_field_id) . "` $colstr";
310 sqlStatement($query);
311 EventAuditLogger
::instance()->newEvent(
313 $_SESSION['authUser'],
314 $_SESSION['authProvider'],
316 "$tablename RENAME $old_field_id TO $new_field_id $colstr"
318 return 0; // Indicate rename done and successful.
321 // Test options array for save
322 function encodeModifier($jsonArray)
324 return $jsonArray !== null ?
json_encode($jsonArray) : "";
327 // Check authorization.
328 $thisauth = acl_check('admin', 'super');
330 die(xlt('Not authorized'));
333 // The layout ID identifies the layout to be edited.
334 $layout_id = empty($_REQUEST['layout_id']) ?
'' : $_REQUEST['layout_id'];
336 // Tag style for stuff to hide if not an LBF layout. Currently just for the Source column.
337 $lbfonly = substr($layout_id, 0, 3) == 'LBF' ?
"" : "style='display:none;'";
339 // Handle the Form actions
341 if ($_POST['formaction'] == "save" && $layout_id) {
342 if (!verifyCsrfToken($_POST["csrf_token_form"])) {
346 // If we are saving, then save.
347 $fld = $_POST['fld'];
348 for ($lino = 1; isset($fld[$lino]['id']); ++
$lino) {
350 $field_id = trim($iter['id']);
351 $field_id_original = trim($iter['originalid']);
352 $data_type = trim($iter['datatype']);
353 $listval = $data_type == 34 ?
trim($iter['contextName']) : trim($iter['list_id']);
354 $action = $iter['action'];
355 if ($action == 'value') {
356 $action = 'value=' . $iter['value'];
359 // Skip conditions for the line are stored as a serialized array.
360 $condarr = array('action' => $action);
362 for (; !empty($iter['condition_id'][$cix]); ++
$cix) {
363 $andor = empty($iter['condition_andor'][$cix]) ?
'' : $iter['condition_andor'][$cix];
364 $condarr[$cix] = array(
365 'id' => $iter['condition_id' ][$cix],
366 'itemid' => $iter['condition_itemid' ][$cix],
367 'operator' => $iter['condition_operator'][$cix],
368 'value' => $iter['condition_value' ][$cix],
372 $conditions = $cix ?
serialize($condarr) : '';
375 if ($field_id != $field_id_original) {
376 if (renameColumn($layout_id, $field_id_original, $field_id) > 0) {
377 // If column rename had an error then don't rename it here.
378 $field_id = $field_id_original;
381 sqlStatement("UPDATE layout_options SET " .
382 "field_id = '" . add_escape_custom($field_id) . "', " .
383 "source = '" . add_escape_custom(trim($iter['source'])) . "', " .
384 "title = '" . add_escape_custom($iter['title']) . "', " .
385 "group_id = '" . add_escape_custom(trim($iter['group'])) . "', " .
386 "seq = '" . add_escape_custom(trim($iter['seq'])) . "', " .
387 "uor = '" . add_escape_custom(trim($iter['uor'])) . "', " .
388 "fld_length = '" . add_escape_custom(trim($iter['lengthWidth'])) . "', " .
389 "fld_rows = '" . add_escape_custom(trim($iter['lengthHeight'])) . "', " .
390 "max_length = '" . add_escape_custom(trim($iter['maxSize'])) . "', " .
391 "titlecols = '" . add_escape_custom(trim($iter['titlecols'])) . "', " .
392 "datacols = '" . add_escape_custom(trim($iter['datacols'])) . "', " .
393 "data_type= '" . add_escape_custom($data_type) . "', " .
394 "list_id= '" . add_escape_custom($listval) . "', " .
395 "list_backup_id= '" . add_escape_custom(trim($iter['list_backup_id'])) . "', " .
396 "edit_options = '" . add_escape_custom(encodeModifier($iter['edit_options'])) . "', " .
397 "default_value = '" . add_escape_custom(trim($iter['default'])) . "', " .
398 "description = '" . add_escape_custom(trim($iter['desc'])) . "', " .
399 "conditions = '" . add_escape_custom($conditions) . "', " .
400 "validation = '" . add_escape_custom(trim($iter['validation'])) . "' " .
401 "WHERE form_id = '" . add_escape_custom($layout_id) . "' AND field_id = '" . add_escape_custom($field_id_original) . "'");
404 } else if ($_POST['formaction'] == "addfield" && $layout_id) {
405 if (!verifyCsrfToken($_POST["csrf_token_form"])) {
409 // Add a new field to a specific group
410 $data_type = trim($_POST['newdatatype']);
411 $max_length = $data_type == 3 ?
3 : 255;
412 $listval = $data_type == 34 ?
trim($_POST['contextName']) : trim($_POST['newlistid']);
413 sqlStatement("INSERT INTO layout_options (" .
414 " form_id, source, field_id, title, group_id, seq, uor, fld_length, fld_rows" .
415 ", titlecols, datacols, data_type, edit_options, default_value, description" .
416 ", max_length, list_id, list_backup_id " .
418 "'" . add_escape_custom(trim($_POST['layout_id'])) . "'" .
419 ",'" . add_escape_custom(trim($_POST['newsource'])) . "'" .
420 ",'" . add_escape_custom(trim($_POST['newid'])) . "'" .
421 ",'" . add_escape_custom($_POST['newtitle']) . "'" .
422 ",'" . add_escape_custom(trim($_POST['newfieldgroupid'])) . "'" .
423 ",'" . add_escape_custom(trim($_POST['newseq'])) . "'" .
424 ",'" . add_escape_custom(trim($_POST['newuor'])) . "'" .
425 ",'" . add_escape_custom(trim($_POST['newlengthWidth'])) . "'" .
426 ",'" . add_escape_custom(trim($_POST['newlengthHeight'])) . "'" .
427 ",'" . add_escape_custom(trim($_POST['newtitlecols'])) . "'" .
428 ",'" . add_escape_custom(trim($_POST['newdatacols'])) . "'" .
429 ",'" . add_escape_custom($data_type) . "'" .
430 ",'" . add_escape_custom(encodeModifier($_POST['newedit_options'])) . "'" .
431 ",'" . add_escape_custom(trim($_POST['newdefault'])) . "'" .
432 ",'" . add_escape_custom(trim($_POST['newdesc'])) . "'" .
433 ",'" . add_escape_custom(trim($_POST['newmaxSize'])) . "'" .
434 ",'" . add_escape_custom($listval) . "'" .
435 ",'" . add_escape_custom(trim($_POST['newbackuplistid'])) . "'" .
437 addOrDeleteColumn($layout_id, trim($_POST['newid']), true);
438 } else if ($_POST['formaction'] == "movefields" && $layout_id) {
439 if (!verifyCsrfToken($_POST["csrf_token_form"])) {
443 // Move field(s) to a new group in the layout
444 $sqlstmt = "UPDATE layout_options SET ".
445 " group_id = '" . add_escape_custom($_POST['targetgroup']) . "' " .
447 " form_id = '" . add_escape_custom($_POST['layout_id']) . "' ".
448 " AND field_id IN (";
450 foreach (explode(" ", $_POST['selectedfields']) as $onefield) {
451 $sqlstmt .= $comma."'" . add_escape_custom($onefield) . "'";
457 sqlStatement($sqlstmt);
458 } else if ($_POST['formaction'] == "deletefields" && $layout_id) {
459 if (!verifyCsrfToken($_POST["csrf_token_form"])) {
463 // Delete a field from a specific group
464 $sqlstmt = "DELETE FROM layout_options WHERE ".
465 " form_id = '" . add_escape_custom($_POST['layout_id']) . "' ".
466 " AND field_id IN (";
468 foreach (explode(" ", $_POST['selectedfields']) as $onefield) {
469 $sqlstmt .= $comma."'" . add_escape_custom($onefield) . "'";
474 sqlStatement($sqlstmt);
475 foreach (explode(" ", $_POST['selectedfields']) as $onefield) {
476 addOrDeleteColumn($layout_id, $onefield, false);
478 } else if ($_POST['formaction'] == "addgroup" && $layout_id) {
479 if (!verifyCsrfToken($_POST["csrf_token_form"])) {
483 // Generate new value for layout_items.group_id.
484 $newgroupid = genGroupId($_POST['newgroupparent']);
487 "INSERT INTO layout_group_properties SET " .
488 "grp_form_id = ?, " .
489 "grp_group_id = ?, " .
491 array($layout_id, $newgroupid, $_POST['newgroupname'])
494 $data_type = trim($_POST['gnewdatatype']);
495 $max_length = $data_type == 3 ?
3 : 255;
496 $listval = $data_type == 34 ?
trim($_POST['gcontextName']) : trim($_POST['gnewlistid']);
497 // add a new group to the layout, with the defined field
498 sqlStatement("INSERT INTO layout_options (" .
499 " form_id, source, field_id, title, group_id, seq, uor, fld_length, fld_rows" .
500 ", titlecols, datacols, data_type, edit_options, default_value, description" .
501 ", max_length, list_id, list_backup_id " .
503 "'" . add_escape_custom(trim($_POST['layout_id'])) . "'" .
504 ",'" . add_escape_custom(trim($_POST['gnewsource'])) . "'" .
505 ",'" . add_escape_custom(trim($_POST['gnewid'])) . "'" .
506 ",'" . add_escape_custom($_POST['gnewtitle']) . "'" .
507 ",'" . add_escape_custom(trim($newgroupid)) . "'" .
508 ",'" . add_escape_custom(trim($_POST['gnewseq'])) . "'" .
509 ",'" . add_escape_custom(trim($_POST['gnewuor'])) . "'" .
510 ",'" . add_escape_custom(trim($_POST['gnewlengthWidth'])) . "'" .
511 ",'" . add_escape_custom(trim($_POST['gnewlengthHeight'])) . "'" .
512 ",'" . add_escape_custom(trim($_POST['gnewtitlecols'])) . "'" .
513 ",'" . add_escape_custom(trim($_POST['gnewdatacols'])) . "'" .
514 ",'" . add_escape_custom($data_type) . "'" .
515 ",'" . add_escape_custom(encodeModifier($_POST['gnewedit_options'])) . "'" .
516 ",'" . add_escape_custom(trim($_POST['gnewdefault'])) . "'" .
517 ",'" . add_escape_custom(trim($_POST['gnewdesc'])) . "'" .
518 ",'" . add_escape_custom(trim($_POST['gnewmaxSize'])) . "'" .
519 ",'" . add_escape_custom($listval) . "'" .
520 ",'" . add_escape_custom(trim($_POST['gnewbackuplistid'])) . "'" .
522 addOrDeleteColumn($layout_id, trim($_POST['gnewid']), true);
523 } /**********************************************************************
524 else if ($_POST['formaction'] == "deletegroup" && $layout_id) {
525 if (!verifyCsrfToken($_POST["csrf_token_form"])) {
529 // drop the fields from the related table (this is critical)
530 $res = sqlStatement("SELECT field_id FROM layout_options WHERE " .
531 "form_id = '" . $_POST['layout_id'] . "' ".
532 "AND group_name = '" . $_POST['deletegroupname'] . "'");
533 while ($row = sqlFetchArray($res)) {
534 addOrDeleteColumn($layout_id, $row['field_id'], false);
537 // Delete an entire group from the form
538 sqlStatement("DELETE FROM layout_options WHERE ".
539 " form_id = '".$_POST['layout_id']."' ".
540 " AND group_name = '".$_POST['deletegroupname']."'"
543 **********************************************************************/
545 else if ($_POST['formaction'] == "movegroup" && $layout_id) {
546 if (!verifyCsrfToken($_POST["csrf_token_form"])) {
550 // Note that in some cases below the swapGroups() call will do nothing.
552 "SELECT DISTINCT group_id " .
553 "FROM layout_options WHERE form_id = ? ORDER BY group_id",
556 $row = sqlFetchArray($res);
557 $id1 = $row['group_id'];
558 while ($row = sqlFetchArray($res)) {
559 $id2 = $row['group_id'];
560 if ($_POST['movedirection'] == 'up') { // moving up
561 if ($id2 == $_POST['movegroupname']) {
562 swapGroups($id2, $id1);
565 } else { // moving down
566 if ($id1 == $_POST['movegroupname']) {
567 swapGroups($id1, $id2);
573 } // Renaming a group. This might include moving to a different parent group.
574 else if ($_POST['formaction'] == "renamegroup" && $layout_id) {
575 if (!verifyCsrfToken($_POST["csrf_token_form"])) {
579 $newparent = $_POST['renamegroupparent']; // this is an ID
580 $oldid = $_POST['renameoldgroupname']; // this is an ID
581 $oldparent = substr($oldid, 0, -1);
583 if ($newparent != $oldparent) {
584 // Different parent, generate a new child prefix character.
585 $newid = genGroupId($newparent);
587 "UPDATE layout_options SET group_id = ? " .
588 "WHERE form_id = ? AND group_id = ?",
589 array($newid, $layout_id, $oldid)
592 $query = "UPDATE layout_group_properties SET " .
593 "grp_group_id = ?, grp_title = ? " .
594 "WHERE grp_form_id = ? AND grp_group_id = ?";
595 sqlStatement($query, array($newid, $_POST['renamegroupname'], $layout_id, $oldid));
598 // Get the selected form's elements.
600 $res = sqlStatement("SELECT * FROM layout_options WHERE " .
601 "form_id = ? ORDER BY group_id, seq", array($layout_id));
604 // global counter for field numbers
609 // This is called to generate a select option list for fields within this form.
610 // Used for selecting a field for testing in a skip condition.
612 function genFieldOptionList($current = '')
615 $option_list = "<option value=''>-- " . xlt('Please Select') . " --</option>";
617 $query = "SELECT field_id FROM layout_options WHERE form_id = ? ORDER BY group_id, seq";
618 $res = sqlStatement($query, array($layout_id));
619 while ($row = sqlFetchArray($res)) {
620 $field_id = $row['field_id'];
621 $option_list .= "<option value='" . attr($field_id) . "'";
622 if ($field_id == $current) {
623 $option_list .= " selected";
625 $option_list .= ">" . text($field_id) . "</option>";
631 // Write one option line to the form.
633 function writeFieldLine($linedata)
635 global $fld_line_no, $sources, $lbfonly, $extra_html,$validations;
637 $checked = $linedata['default_value'] ?
" checked" : "";
639 //echo " <tr bgcolor='$bgcolor'>\n";
640 echo " <tr id='fld[" . attr($fld_line_no) . "]' class='".($fld_line_no %
2 ?
'even' : 'odd')."'>\n";
642 echo " <td class='optcell' nowrap>";
643 // tuck the group_name INPUT in here
644 echo "<input type='hidden' name='fld[" . attr($fld_line_no) . "][group]' value='" .
645 attr($linedata['group_id']) . "' class='optin' />";
646 // Original field ID.
647 echo "<input type='hidden' name='fld[" . attr($fld_line_no) . "][originalid]' value='" .
648 attr($linedata['field_id']) . "' />";
650 echo "<input type='checkbox' class='selectfield' ".
651 "name='" . attr($linedata['group_id']) . "~" . attr($linedata['field_id']) . "' " .
652 "id='" . attr($linedata['group_id']) . "~" . attr($linedata['field_id']) . "' " .
653 "title='" . xla('Select field') . "' />";
655 echo "<input type='text' name='fld[" . attr($fld_line_no) . "][seq]' id='fld[" . attr($fld_line_no) . "][seq]' value='" .
656 attr($linedata['seq']) . "' size='2' maxlength='4' " .
657 "class='optin' style='width:32pt' />";
660 echo " <td align='center' class='optcell' $lbfonly>";
661 echo "<select class='form-control' name='fld[" . attr($fld_line_no) . "][source]' class='optin' $lbfonly>";
662 foreach ($sources as $key => $value) {
663 echo "<option value='" . attr($key) . "'";
664 if ($key == $linedata['source']) {
668 echo ">" . text($value) . "</option>\n";
674 echo " <td align='left' class='optcell'>";
675 echo "<input type='text' name='fld[" . attr($fld_line_no) . "][id]' value='" .
676 attr($linedata['field_id']) . "' size='15' maxlength='63' " .
677 "class='optin' style='width:100%' onclick='FieldIDClicked(this)' />";
680 echo " <td align='center' class='optcell'>";
681 echo "<input type='text' id='fld[" . attr($fld_line_no) . "][title]' name='fld[" . attr($fld_line_no) . "][title]' value='" .
682 attr($linedata['title']) . "' size='15' maxlength='63' class='optin' style='width:100%' />";
685 // if not english and set to translate layout labels, then show the translation
686 if ($GLOBALS['translate_layout'] && $_SESSION['language_choice'] > 1) {
687 echo "<td align='center' class='translation' >" . xlt($linedata['title']) . "</td>\n";
690 echo " <td align='center' class='optcell'>";
691 echo "<select class='form-control' name='fld[" . attr($fld_line_no) . "][uor]' class='optin'>";
692 foreach (array(0 =>xl('Unused'), 1 =>xl('Optional'), 2 =>xl('Required')) as $key => $value) {
693 echo "<option value='" . attr($key) . "'";
694 if ($key == $linedata['uor']) {
698 echo ">" . text($value) . "</option>\n";
704 echo " <td align='center' class='optcell'>";
705 echo "<select class='form-control' name='fld[" . attr($fld_line_no) . "][datatype]' id='fld[" . attr($fld_line_no) . "][datatype]' onchange=NationNotesContext(" . attr_js($fld_line_no) . ",this.value)>";
706 echo "<option value=''></option>";
708 foreach ($datatypes as $key => $value) {
709 if ($linedata['data_type'] == $key) {
710 echo "<option value='" . attr($key) . "' selected>" . text($value) . "</option>";
712 echo "<option value='" . attr($key) . "'>" . text($value) . "</option>";
719 echo " <td align='center' class='optcell'>";
720 if ($linedata['data_type'] == 2 ||
$linedata['data_type'] == 3 ||
721 $linedata['data_type'] == 21 ||
$linedata['data_type'] == 22 ||
722 $linedata['data_type'] == 23 ||
$linedata['data_type'] == 25 ||
723 $linedata['data_type'] == 27 ||
$linedata['data_type'] == 28 ||
724 $linedata['data_type'] == 32 ||
$linedata['data_type'] == 15 ||
725 $linedata['data_type'] == 40
727 // Show the width field
728 echo "<input type='text' name='fld[" . attr($fld_line_no) . "][lengthWidth]' value='" .
729 attr($linedata['fld_length']) .
730 "' size='2' maxlength='10' class='optin' title='" . xla('Width') . "' />";
731 if ($linedata['data_type'] == 3 ||
$linedata['data_type'] == 40) {
732 // Show the height field
733 echo "<input type='text' name='fld[" . attr($fld_line_no) . "][lengthHeight]' value='" .
734 attr($linedata['fld_rows']) .
735 "' size='2' maxlength='10' class='optin' title='" . xla('Height') . "' />";
737 // Hide the height field
738 echo "<input type='hidden' name='fld[" . attr($fld_line_no) . "][lengthHeight]' value=''>";
741 // all other data_types (hide both the width and height fields
742 echo "<input type='hidden' name='fld[" . attr($fld_line_no) . "][lengthWidth]' value=''>";
743 echo "<input type='hidden' name='fld[" . attr($fld_line_no) . "][lengthHeight]' value=''>";
748 echo " <td align='center' class='optcell'>";
749 echo "<input type='text' name='fld[" . attr($fld_line_no) . "][maxSize]' value='" .
750 attr($linedata['max_length']) .
751 "' size='1' maxlength='10' class='optin' style='width:100%' " .
752 "title='" . xla('Maximum Size (entering 0 will allow any size)') . "' />";
755 echo " <td align='center' class='optcell'>";
756 if ($linedata['data_type'] == 1 ||
$linedata['data_type'] == 21 ||
757 $linedata['data_type'] == 22 ||
$linedata['data_type'] == 23 ||
758 $linedata['data_type'] == 25 ||
$linedata['data_type'] == 26 ||
759 $linedata['data_type'] == 27 ||
$linedata['data_type'] == 32 ||
760 $linedata['data_type'] == 33 ||
$linedata['data_type'] == 34 ||
761 $linedata['data_type'] == 36) {
763 $disp = "style='display:none'";
764 if ($linedata['data_type'] == 34) {
765 $type = "style='display:none'";
769 echo "<input type='text' name='fld[" . attr($fld_line_no) . "][list_id]' id='fld[" . attr($fld_line_no) . "][list_id]' value='" .
770 attr($linedata['list_id']) . "' " . $type .
771 " size='6' maxlength='100' class='optin listid' style='width:100%;cursor:pointer'".
772 "title='". xla('Choose list') . "' />";
774 echo "<select class='form-control' name='fld[" . attr($fld_line_no) . "][contextName]' id='fld[" . attr($fld_line_no) . "][contextName]' ".$disp.">";
775 $res = sqlStatement("SELECT * FROM customlists WHERE cl_list_type=2 AND cl_deleted=0");
776 while ($row = sqlFetchArray($res)) {
778 if ($linedata['list_id'] == $row['cl_list_item_long']) {
782 echo "<option value='" . attr($row['cl_list_item_long']) . "' ".$sel.">" . text($row['cl_list_item_long']) . "</option>";
787 // all other data_types
788 echo "<input type='hidden' name='fld[" . attr($fld_line_no) . "][list_id]' value=''>";
794 echo " <td align='center' class='optcell'>";
795 if ($linedata['data_type'] == 1 ||
$linedata['data_type'] == 26 ||
796 $linedata['data_type'] == 33 ||
$linedata['data_type'] == 36) {
797 echo "<input type='text' name='fld[" . attr($fld_line_no) . "][list_backup_id]' value='" .
798 attr($linedata['list_backup_id']) .
799 "' size='3' maxlength='100' class='optin listid' style='cursor:pointer; width:100%' />";
801 echo "<input type='hidden' name='fld[" . attr($fld_line_no) . "][list_backup_id]' value=''>";
807 echo " <td align='center' class='optcell'>";
808 echo "<input type='text' name='fld[" . attr($fld_line_no) . "][titlecols]' value='" .
809 attr($linedata['titlecols']) . "' size='3' maxlength='10' class='optin' style='width:100%' />";
812 echo " <td align='center' class='optcell'>";
813 echo "<input type='text' name='fld[" . attr($fld_line_no) . "][datacols]' value='" .
814 attr($linedata['datacols']) . "' size='3' maxlength='10' class='optin' style='width:100%' />";
816 /* Below for compatabilty with existing string modifiers. */
817 if (strpos($linedata['edit_options'], ',') === false && isset($linedata['edit_options'])) {
818 $t = json_decode($linedata['edit_options']);
819 if (json_last_error() !== JSON_ERROR_NONE ||
$t === 0) { // hopefully string of characters and 0 handled.
820 $t = str_split(trim($linedata['edit_options']));
821 $linedata['edit_options'] = json_encode($t); // convert to array select understands.
824 echo " <td align='center' class='optcell' title='" . xla("Add modifiers for this field type. You may select more than one.") . "'>";
825 echo "<select id='fld[" . attr($fld_line_no) . "][edit_options]' name='fld[" . attr($fld_line_no) . "][edit_options][]' class='typeAddons optin' size=3 multiple data-set='" .
826 attr(trim($linedata['edit_options'])) . "' ></select></td>\n";
828 if ($linedata['data_type'] == 31) {
829 echo " <td align='center' class='optcell'>";
830 echo "<textarea name='fld[" . attr($fld_line_no) . "][desc]' rows='3' cols='35' class='optin' style='width:100%'>" .
831 text($linedata['description']) . "</textarea>";
832 echo "<input type='hidden' name='fld[" . attr($fld_line_no) . "][default]' value='" .
833 attr($linedata['default_value']) . "' />";
836 echo " <td align='center' class='optcell' >";
837 echo "<input type='text' name='fld[" . attr($fld_line_no) . "][desc]' value='" .
838 attr($linedata['description']) .
839 "' size='30' class='optin' style='width:100%' />";
840 echo "<input type='hidden' name='fld[" . attr($fld_line_no) . "][default]' value='" .
841 attr($linedata['default_value']) . "' />";
843 // if not english and showing layout labels, then show the translation of Description
844 if ($GLOBALS['translate_layout'] && $_SESSION['language_choice'] > 1) {
845 echo "<td align='center' class='translation'>" .
846 xlt($linedata['description']) . "</td>\n";
850 // The "?" to click on for yet more field attributes.
851 echo " <td class='bold' id='querytd_" . attr($fld_line_no) . "' style='cursor:pointer;";
852 if (!empty($linedata['conditions']) ||
!empty($linedata['validation'])) {
853 echo "background-color:#77ff77;";
856 echo "' onclick='extShow(" . attr($fld_line_no) . ", this)' align='center' ";
857 echo "title='" . xla('Click here to view/edit more details') . "'>";
858 echo " ? ";
863 // Create a floating div for the additional attributes of this field.
864 $conditions = empty($linedata['conditions']) ?
865 array(0 => array('id' => '', 'itemid' => '', 'operator' => '', 'value' => '')) :
866 unserialize($linedata['conditions']);
867 $action = empty($conditions['action']) ?
'skip' : $conditions['action'];
868 $action_value = $action == 'skip' ?
'' : substr($action, 6);
870 $extra_html .= "<div id='ext_" . attr($fld_line_no) . "' " .
871 "style='position:absolute;width:750px;border:1px solid black;" .
872 "padding:2px;background-color:#cccccc;visibility:hidden;" .
873 "z-index:1000;left:-1000px;top:0px;font-size:8pt;'>\n" .
874 "<table width='100%'>\n" .
876 " <th colspan='3' align='left' class='bold'>" .
877 xlt('For') . " " . text($linedata['field_id']) . " " .
878 "<select name='fld[" . attr($fld_line_no) . "][action]' onchange='actionChanged(" . attr_js($fld_line_no) . ")'>" .
879 "<option value='skip' " . ($action == 'skip' ?
'selected' : '') . ">" . xlt('hide this field') . "</option>" .
880 "<option value='value' " . ($action != 'skip' ?
'selected' : '') . ">" . xlt('set value to') . "</option>" .
882 "<input type='text' name='fld[" . attr($fld_line_no) . "][value]' value='" . attr($action_value) . "' size='15' />" .
885 " <th colspan='2' align='right' class='text'><input type='button' " .
886 "value='" . xla('Close') . "' onclick='extShow(" . attr_js($fld_line_no) . ", false)' /> </th>\n" .
889 " <th align='left' class='bold'>" . xlt('Field ID') . "</th>\n" .
890 " <th align='left' class='bold'>" . xlt('List item ID') . "</th>\n" .
891 " <th align='left' class='bold'>" . xlt('Operator') . "</th>\n" .
892 " <th align='left' class='bold'>" . xlt('Value if comparing') . "</th>\n" .
893 " <th align='left' class='bold'> </th>\n" .
895 // There may be multiple condition lines for each field.
896 foreach ($conditions as $i => $condition) {
897 if (!is_numeric($i)) {
898 continue; // skip if 'action'
902 " <td align='left'>\n" .
903 " <select name='fld[" . attr($fld_line_no) . "][condition_id][" . attr($i) . "]' onchange='cidChanged(" . attr_js($fld_line_no) . ", " . attr_js($i) . ")'>" .
904 genFieldOptionList($condition['id']) . " </select>\n" .
906 " <td align='left'>\n" .
907 // List item choices are populated on the client side but will need the current value,
908 // so we insert a temporary option here to hold that value.
909 " <select name='fld[" . attr($fld_line_no) . "][condition_itemid][" . attr($i) . "]'><option value='" .
910 attr($condition['itemid']) . "'>...</option></select>\n" .
912 " <td align='left'>\n" .
913 " <select name='fld[" . attr($fld_line_no) . "][condition_operator][" . attr($i) . "]'>\n";
915 'eq' => xl('Equals'),
916 'ne' => xl('Does not equal'),
917 'se' => xl('Is selected'),
918 'ns' => xl('Is not selected'),
919 ) as $key => $value) {
920 $extra_html .= " <option value='" . attr($key) . "'";
921 if ($key == $condition['operator']) {
922 $extra_html .= " selected";
925 $extra_html .= ">" . text($value) . "</option>\n";
931 " <td align='left' title='" . xla('Only for comparisons') . "'>\n" .
932 " <input type='text' name='fld[" . attr($fld_line_no) . "][condition_value][" . attr($i) . "]' value='" .
933 attr($condition['value']) . "' size='15' maxlength='63' />\n" .
935 if (!isset($conditions[$i +
1])) {
937 " <td align='right' title='" . xla('Add a condition') . "'>\n" .
938 " <input type='button' value='+' onclick='extAddCondition(" . attr_js($fld_line_no) . ",this)' />\n" .
942 " <td align='right'>\n" .
943 " <select name='fld[" . attr($fld_line_no) . "][condition_andor][" . attr($i) . "]'>\n";
947 ) as $key => $value) {
948 $extra_html .= " <option value='" . attr($key) . "'";
949 if ($key == $condition['andor']) {
950 $extra_html .= " selected";
953 $extra_html .= ">" . text($value) . "</option>\n";
968 $extra_html .= "<table width='100%'>\n" .
970 " <td colspan='3' align='left' class='bold'>\"" . text($linedata['field_id']) . "\" " .
971 xlt('will have the following validation rules') . ":</td>\n" .
974 " <td align='left' class='bold'>" . xlt('Validation rule') . " </td>\n" .
977 " <td align='left' title='" . xla('Select a validation rule') . "'>\n" .
980 " <select name='fld[" . attr($fld_line_no) . "][validation]' onchange='valChanged(" . attr_js($fld_line_no) . ")'>\n" .
982 if (empty($linedata['validation'])) {
983 $extra_html .= " selected";
986 $extra_html .= ">-- " . xlt('Please Select') . " --</option>";
987 foreach ($validations as $key => $value) {
988 $extra_html .= " <option value='" . attr($key) . "'";
989 if ($key == $linedata['validation']) {
990 $extra_html .= " selected";
993 $extra_html .= ">" . text($value) . "</option>\n";
996 $extra_html .="</select>\n" .
1008 <?php Header
::setupHeader(['select2']); ?
>
1010 <title
><?php
echo xlt('Layout Editor'); ?
></title
>
1013 .orgTable tr
.head
{ font
-size
:8pt
; background
-color
:#cccccc; }
1014 .orgTable tr
.detail
{ font
-size
:8pt
; }
1015 .orgTable td
{ font
-size
:8pt
; }
1016 .orgTable input
{ font
-size
:8pt
; }
1017 .orgTable select
{ font
-size
:8pt
; }
1018 a
, a
:visited
, a
:hover
{ color
:#0000cc; }
1020 .optin
{ background
: transparent
; }
1022 margin
: 0pt
0pt
8pt
0pt
;
1028 border
-collapse
: collapse
;
1033 background
-color
: #ddddff;
1034 padding
: 3px
0px
3px
0px
;
1036 .orgTable
.even td
{
1037 background
-color
: #ffdddd;
1038 padding
: 3px
0px
3px
0px
;
1040 .help
{ cursor
: help
; }
1041 .layouts_title
{ font
-size
: 110%
; }
1047 border
: 2px solid blue
;
1048 background
-color
: yellow
;
1051 .select2
-container
--default .select2
-selection
--multiple
{
1054 .select2
-search__field
{
1056 width
: 0 !important
;
1058 .select2
-selection__choice
{
1061 .select2
-container
{
1063 opacity
: 0.99 !important
;
1066 opacity
: 0.99 !important
;
1075 // Helper functions for positioning the floating divs.
1076 function extGetX(elem
) {
1078 while(elem
!= null) {
1079 x +
= elem
.offsetLeft
;
1080 elem
= elem
.offsetParent
;
1084 function extGetY(elem
) {
1086 while(elem
!= null) {
1087 y +
= elem
.offsetTop
;
1088 elem
= elem
.offsetParent
;
1093 // Show or hide the "extras" div for a row.
1095 function extShow(lino
, show
) {
1096 var thisdiv
= document
.getElementById("ext_" + lino
);
1098 extdiv
.style
.visibility
= 'hidden';
1099 extdiv
.style
.left
= '-1000px';
1100 extdiv
.style
.top
= '0px';
1102 if (show
&& thisdiv
!= extdiv
) {
1104 var dw
= window
.innerWidth ? window
.innerWidth
- 20 : document
.body
.clientWidth
;
1105 x
= dw
- extdiv
.offsetWidth
;
1107 var y
= extGetY(show
) + show
.offsetHeight
;
1108 extdiv
.style
.left
= x
;
1109 extdiv
.style
.top
= y
;
1110 extdiv
.style
.visibility
= 'visible';
1117 // Show or hide the value field for a "Set value to" condition.
1118 function actionChanged(lino
) {
1119 var f
= document
.forms
[0];
1120 var eaction
= f
['fld[' + lino +
'][action]'];
1121 var evalue
= f
['fld[' + lino +
'][value]'];
1122 evalue
.style
.display
= eaction
.value
== 'skip' ?
'none' : '';
1125 // Add an extra condition line for the given row.
1126 function extAddCondition(lino
, btnelem
) {
1127 var f
= document
.forms
[0];
1130 // Get index of next condition line.
1131 while (f
['fld[' + lino +
'][condition_id][' + i +
']']) ++i
;
1132 if (i
== 0) alert('f["fld[' + lino +
'][condition_id][' + i +
']"]' +
<?php
echo xlj('not found') ?
>);
1134 // Get containing <td>, <tr> and <table> nodes of the "+" button.
1135 var tdplus
= btnelem
.parentNode
;
1136 var trelem
= tdplus
.parentNode
;
1137 var telem
= trelem
.parentNode
;
1139 // Replace contents of the tdplus cell.
1141 "<select name='fld[" + lino +
"][condition_andor][" +
(i
-1) +
"]'>" +
1142 "<option value='and'>" +
<?php
echo xlj('And') ?
> +
"</option>" +
1143 "<option value='or' >" +
<?php
echo xlj('Or') ?
> +
"</option>" +
1147 var newtrelem
= telem
.insertRow(i+
2);
1148 newtrelem
.innerHTML
=
1149 "<td align='left'>" +
1150 "<select name='fld[" + lino +
"][condition_id][" + i +
"]' onchange='cidChanged(" + lino +
"," + i +
")'>" +
1151 <?php
echo js_escape(genFieldOptionList()) ?
> +
1154 "<td align='left'>" +
1155 "<select name='fld[" + lino +
"][condition_itemid][" + i +
"]' style='display:none' />" +
1157 "<td align='left'>" +
1158 "<select name='fld[" + lino +
"][condition_operator][" + i +
"]'>" +
1159 "<option value='eq'>" +
<?php
echo xlj('Equals') ?
> +
"</option>" +
1160 "<option value='ne'>" +
<?php
echo xlj('Does not equal') ?
> +
"</option>" +
1161 "<option value='se'>" +
<?php
echo xlj('Is selected') ?
> +
"</option>" +
1162 "<option value='ns'>" +
<?php
echo xlj('Is not selected') ?
> +
"</option>" +
1165 "<td align='left'>" +
1166 "<input type='text' name='fld[" + lino +
"][condition_value][" + i +
"]' value='' size='15' maxlength='63' />" +
1168 "<td align='right'>" +
1169 "<input type='button' value='+' onclick='extAddCondition(" + lino +
",this)' />" +
1173 // This is called when a field ID is chosen for testing within a skip condition.
1174 // It checks to see if a corresponding list item must also be chosen for the test, and
1175 // if so then inserts the dropdown for selecting an item from the appropriate list.
1176 function setListItemOptions(lino
, seq
, init
) {
1177 var f
= document
.forms
[0];
1178 var target
= 'fld[' + lino +
'][condition_itemid][' + seq +
']';
1179 // field_id is the ID of the field that the condition will test.
1180 var field_id
= f
['fld[' + lino +
'][condition_id][' + seq +
']'].value
;
1182 f
[target
].options
.length
= 0;
1183 f
[target
].style
.display
= 'none';
1186 // Find the occurrence of that field in the layout.
1189 var idname
= 'fld[' + i +
'][id]';
1191 alert(<?php
echo xlj('Condition field not found') ?
> +
': ' + field_id
);
1194 if (f
[idname
].value
== field_id
) break;
1197 // If this is startup initialization then preserve the current value.
1198 var current
= init ? f
[target
].value
: '';
1199 f
[target
].options
.length
= 0;
1200 // Get the corresponding data type and list ID.
1201 var data_type
= f
['fld[' + i +
'][datatype]'].value
;
1202 var list_id
= f
['fld[' + i +
'][list_id]'].value
;
1203 // WARNING: If new data types are defined the following test may need enhancing.
1204 // We're getting out if the type does not generate multiple fields with different names.
1205 if (data_type
!= '21' && data_type
!= '22' && data_type
!= '23' && data_type
!= '25') {
1206 f
[target
].style
.display
= 'none';
1209 // OK, list item IDs do apply so go get 'em.
1210 // This happens asynchronously so the generated code needs to stand alone.
1211 f
[target
].style
.display
= '';
1212 $
.getScript('layout_listitems_ajax.php' +
1213 '?listid=' +
encodeURIComponent(list_id
) +
1214 '&target=' +
encodeURIComponent(target
) +
1215 '¤t=' +
encodeURIComponent(current
) +
1216 '&csrf_token_form=' +
<?php
echo js_url(collectCsrfToken()); ?
>);
1219 // This is called whenever a condition's field ID selection is changed.
1220 function cidChanged(lino
, seq
) {
1222 setListItemOptions(lino
, seq
, false);
1225 // This invokes the popup to edit layout properties or add a new layout.
1226 function edit_layout_props(groupid
) {
1227 var title
= <?php
echo xlj('Layout Properties');?
>;
1228 dlgopen('edit_layout_props.php?layout_id=' +
<?php
echo js_url($layout_id); ?
> +
'&group_id=' +
encodeURIComponent(groupid
),
1229 '_blank', 775, 550, "", title
);
1232 // callback from edit_layout_props.php:
1233 function refreshme(layout_id
) {
1234 location
.href
= 'edit_layout.php?layout_id=' +
encodeURIComponent(layout_id
);
1237 // This is called whenever a validation rule field ID selection is changed.
1238 function valChanged(lino
) {
1242 function changeColor(lino
){
1243 var thisid
= document
.forms
[0]['fld[' + lino +
'][condition_id][0]'].value
;
1244 var thisValId
= document
.forms
[0]['fld[' + lino +
'][validation]'].value
;
1245 var thistd
= document
.getElementById("querytd_" + lino
);
1246 if(thisid
!='' || thisValId
!='') {
1247 thistd
.style
.backgroundColor
= '#77ff77';
1249 thistd
.style
.backgroundColor
='';
1253 // Call this to disable the warning about unsaved changes and submit the form.
1254 function mySubmit() {
1255 somethingChanged
= false;
1256 top
.restoreSession();
1257 document
.forms
[0].submit();
1260 // User is about to do something that would discard any unsaved changes.
1261 // Return true if that is OK.
1262 function myChangeCheck() {
1263 if (somethingChanged
) {
1264 if (!confirm(<?php
echo xlj('You have unsaved changes. Abandon them?'); ?
>)) {
1267 // Do not set somethingChanged to false here because if they cancel the
1268 // action then the previously changed values will still be of interest.
1277 <body
class="body_top admin-layout">
1278 <div
class="container-responsive">
1279 <form method
='post' name
='theform' id
='theform' action
='edit_layout.php'>
1280 <input type
="hidden" name
="csrf_token_form" value
="<?php echo attr(collectCsrfToken()); ?>" />
1281 <input type
="hidden" name
="formaction" id
="formaction" value
="">
1282 <!-- elements used to identify a field to delete
-->
1283 <input type
="hidden" name
="deletefieldid" id
="deletefieldid" value
="">
1284 <input type
="hidden" name
="deletefieldgroup" id
="deletefieldgroup" value
="">
1285 <!-- elements used to identify a group to delete
-->
1287 <input type
="hidden" name
="deletegroupname" id
="deletegroupname" value
="">
1289 <!-- elements used to change the group order
-->
1290 <input type
="hidden" name
="movegroupname" id
="movegroupname" value
="">
1291 <input type
="hidden" name
="movedirection" id
="movedirection" value
="">
1292 <!-- elements used to select more than one field
-->
1293 <input type
="hidden" name
="selectedfields" id
="selectedfields" value
="">
1294 <input type
="hidden" id
="targetgroup" name
="targetgroup" value
="">
1296 <div
class="menubar" style
='padding:5px 0;'>
1298 <b
><?php
echo xlt('Edit layout'); ?
>:</b
> 
;
1299 <select name
='layout_id' id
='layout_id' class='form-control' style
='display:inline-block;margin-bottom:5px;width:20%;'>
1300 <option value
=''>-- <?php
echo xlt('Select') ?
> --</option
>
1303 foreach ($layouts as $key => $value) {
1304 if ($value[0] != $lastgroup) {
1306 echo " </optgroup>\n";
1308 echo " <optgroup label='" . attr($value[0]) . "'>\n";
1309 $lastgroup = $value[0];
1311 echo " <option value='" . attr($key) . "'";
1312 if ($key == $layout_id) {
1315 echo ">" . text($value[1]) . "</option>\n";
1318 echo " </optgroup>\n";
1323 <?php
if ($layout_id) { ?
>
1324 <input type
='button' value
='<?php echo xla('Layout Properties
'); ?>' onclick
='edit_layout_props("")' /> 
;
1325 <input type
='button' class='addgroup' id
='addgroup' value
='<?php echo xla('Add Group
'); ?>' />
1326 <span style
="font-size:90%">  
;
1327 <input type
='button' class="btn btn-danger" name
='save' id
='save' value
='<?php echo xla('Save Changes
'); ?>' /></span
>  
; 
;
1328 <?php
echo xlt('With selected:');?
>
1329 <input type
='button' name
='deletefields' id
='deletefields' value
='<?php echo xla('Delete
'); ?>' style
="font-size:90%" disabled
="disabled" />
1330 <input type
='button' name
='movefields' id
='movefields' value
='<?php echo xla('Move to
...'); ?>' style
="font-size:90%" disabled
="disabled" />
1331 <input type
='button' value
='<?php echo xla('Tips
'); ?>' onclick
='$("#tips").toggle();' /> 
;
1332 <input type
='button' value
='<?php echo xla('Encounter Preview
'); ?>' onclick
='layoutLook();' />
1335 <input type
='button' value
='<?php echo xla('New Layout
'); ?>' onclick
='edit_layout_props("")' /> 
;
1338 <div id
="tips" class="container tips"><section
class="panel panel-primary">
1339 <header
class="panel-heading">
1340 <h3
class="panel-title"><?php
echo xlt('Usage Tips') ?
></h3
>
1342 <div
class="panel-body">
1345 echo "<li>" . xlt("Clicking Options will present a multiselection drop menu to add behaviors to the selected data type. Typing after pull down activates allows search in options.") . "</li>";
1346 echo "<li>" . xlt("The option Span Entire Row is useful when using Static Text in allowing text to wrap and span entire row regardless of column settings. Another use could be to create an empty row as spacer or add additional option Add Bottom Border to create a line break.Only Bottom Border Row is useful here.") . "</li>";
1347 echo "<li>" . xlt("The options for Outline and Border will either wrap a row in thin border or add a border to the bottom of an item.") . "</li>";
1348 echo "<li>" . xlt("If a field's Label Col = 0 the label will immediately follow the previous data field in the Order sequence, on the same line as the Data field.") . "</li>";
1349 echo "<li>" . xlt("If a field's Data Col = 0 the data field will immediately follow its label field on the same line") . "</li>";
1350 echo "<li>" . xlt("If a field's Label Col = 1 the label field will go to a new line unless the previous field's total column values (Label + Data) is less than number of Layout columns from Group Properties or Layout Properties.") . "</li>";
1351 echo "<li>" . xlt("Generally, the first field in a group should be Label Cols = 1 Data Cols = number of Layout columns from Group Properties.") . "</li>";
1352 echo "<li>" . xlt("Make subsequent fields in the same row, Label = 0 Data = 0 and ensure enough columns are available from previous items to allow space for this new item. Otherwise result could be unpredictable") . "</li>";
1353 echo "<li>" . xlt("The Encounter Preview button is useful for showing encounter type layout forms as seen when using form in an encounter. Note, this feature is only useful for showing encounter forms and won't display system forms like Demographics") . "</li>";
1354 //echo "<li>" . xlt("") . "</li>";
1355 echo "<li>" . xlt("Please see http://www.open-emr.org/wiki/index.php/LBV_Forms for more on this topic") . "</li>";
1358 <button
class='btn btn-xs btn-success pull-right' onclick
='$("#tips").toggle();return false;'><?php
echo xlt('Dismiss')?
></button
>
1360 </section
></div
></div
>
1362 // Load array of properties for this layout and its groups.
1364 $gres = sqlStatement("SELECT * FROM layout_group_properties WHERE grp_form_id = ? " .
1365 "ORDER BY grp_group_id", array($layout_id));
1366 while ($grow = sqlFetchArray($gres)) {
1367 $grparr[$grow['grp_group_id']] = $grow;
1370 $prevgroup = "!@#asdf1234"; // an unlikely group ID
1371 $firstgroup = true; // flag indicates it's the first group to be displayed
1373 while ($row = sqlFetchArray($res)) {
1374 $group_id = $row['group_id'];
1375 if ($group_id != $prevgroup) {
1376 if ($firstgroup == false) {
1377 echo "</tbody></table></div>\n";
1378 echo "<div id='" . attr($group_id) . "' class='group'>";
1379 } else { // making first group flag useful for maintaining top fixed nav bar.
1380 echo "<div id='" . attr($group_id) . "' class='group' style='padding-top:40px'>";
1382 echo "<div class='text bold layouts_title' style='position:relative; background-color: #c9dbf2;'>";
1384 // Get the fully qualified descriptive name of this group (i.e. including ancestor names).
1386 for ($i = 1; $i <= strlen($group_id); ++
$i) {
1388 $gdispname .= ' / ';
1390 $gdispname .= $grparr[substr($group_id, 0, $i)]['grp_title'];
1392 $gmyname = $grparr[$group_id]['grp_title'];
1394 echo text($gdispname);
1396 // if not english and set to translate layout labels, then show the translation of group name
1397 if ($GLOBALS['translate_layout'] && $_SESSION['language_choice'] > 1) {
1398 echo "<span class='translation'>>> " . xlt($gdispname) . "</span>";
1403 echo " <input type='button' class='addfield' id='addto~" . attr($group_id) . "' value='" . xla('Add Field') . "'/>";
1404 echo " ";
1405 echo " <input type='button' class='renamegroup' id='" . attr($group_id) . "~" . attr($gmyname) . "' value='" . xla('Rename Group') . "'/>";
1406 /******************************************************************
1407 echo " ";
1408 echo " <input type='button' class='deletegroup' id='" . attr($group_id) . "' value='" . xla('Delete Group') . "'/>";
1409 ******************************************************************/
1410 echo " ";
1411 echo " <input type='button' class='movegroup' id='" . attr($group_id) . "~up' value='" . xla('Move Up') . "'/>";
1412 echo " ";
1413 echo " <input type='button' class='movegroup' id='" . attr($group_id) . "~down' value='" . xla('Move Down') . "'/>";
1414 echo " ";
1415 echo "<input type='button' value='" . xla('Group Properties') . "' onclick='edit_layout_props(" . attr_js($group_id) . ")' />";
1417 $firstgroup = false;
1419 <table
class='table table-condensed table-striped'>
1422 <th style
='width:1%'><?php
echo xlt('Order'); ?
></th
>
1423 <th
<?php
echo " $lbfonly"; ?
>style
='width:5%'><?php
echo xlt('Source'); ?
></th
>
1424 <th style
='width:5%'><?php
echo xlt('ID'); ?
> 
;<span
class="help" title
='<?php echo xla('A unique value to identify this field
, not visible to the user
'); ?>' >(?
)</span
></th
>
1425 <th style
='width:10%'><?php
echo xlt('Label'); ?
> 
;<span
class="help" title
='<?php echo xla('The label that appears to the user on the form
'); ?>' >(?
)</span
></th
>
1426 <?php
// if not english and showing layout label translations, then show translation header for title
1427 if ($GLOBALS['translate_layout'] && $_SESSION['language_choice'] > 1) {
1428 echo "<th>" . xlt('Translation')."<span class='help' title='" . xla('The translated label that will appear on the form in current language') . "'> (?)</span></th>";
1430 <th style
='width:6%'><?php
echo xlt('UOR'); ?
></th
>
1431 <th style
='width:10%'><?php
echo xlt('Data Type'); ?
></th
>
1432 <th style
='width:1%'><?php
echo xlt('Size'); ?
></th
>
1433 <th style
='width:3%'><?php
echo xlt('Max Size'); ?
></th
>
1434 <th style
='width:10%'><?php
echo xlt('List'); ?
></th
>
1435 <th style
='width:10%'><?php
echo xlt('Backup List'); ?
></th
>
1436 <th style
='width:1%'><?php
echo xlt('Label Cols'); ?
></th
>
1437 <th style
='width:1%'><?php
echo xlt('Data Cols'); ?
></th
>
1438 <th style
='width:10%'><?php
echo xlt('Options'); ?
></th
>
1439 <th style
='width:20%'><?php
echo xlt('Description'); ?
></th
>
1440 <?php
// if not english and showing layout label translations, then show translation header for description
1441 if ($GLOBALS['translate_layout'] && $_SESSION['language_choice'] > 1) {
1442 echo "<th>" . xlt('Translation')."<span class='help' title='" . xla('The translation of description in current language')."'> (?)</span></th>";
1444 <th style
='width:1%'><?php
echo xlt('?'); ?
></th
>
1450 } // end if-group_name
1452 writeFieldLine($row);
1453 $prevgroup = $group_id;
1460 <?php
echo $extra_html; ?
>
1464 <!-- template DIV that appears when user chooses to rename an existing group
-->
1465 <div id
="renamegroupdetail"
1466 style
="border: 1px solid black; padding: 3px; display: none; visibility: hidden; background-color: lightgrey;">
1467 <input type
="hidden" name
="renameoldgroupname" id
="renameoldgroupname" value
="" />
1468 <?php
echo xlt('Group Name'); ?
>:
1469 <input type
="text" size
="20" maxlength
="30" name
="renamegroupname" id
="renamegroupname" />
1471 <?php
echo xlt('Parent'); ?
>:
1472 <?php
echo genGroupSelector('renamegroupparent', $layout_id); ?
>
1474 <input type
="button" class="saverenamegroup .btn-save" value
="<?php echo xla('Rename Group'); ?>" />
1475 <input type
="button" class="cancelrenamegroup" value
="<?php echo xla('Cancel'); ?>" />
1478 <!-- template DIV that appears when user chooses to add a
new group
-->
1479 <div id
="groupdetail"
1480 style
="border: 1px solid black; padding: 3px; display: none; visibility: hidden; background-color: lightgrey;">
1482 <?php
echo xlt('Group Name'); ?
>:
1483 <input type
="text" size
="20" maxlength
="30" name
="newgroupname" id
="newgroupname" />
1485 <?php
echo xlt('Parent'); ?
>:
1486 <?php
echo genGroupSelector('newgroupparent', $layout_id); ?
>
1488 <table
class='table table-condensed table-striped' style
="border-collapse: collapse; margin-top: 5px;">
1491 <th style
='width:1%'><?php
echo xlt('Order'); ?
></th
>
1492 <th
<?php
echo " $lbfonly"; ?
>style
='width:5%'><?php
echo xlt('Source'); ?
></th
>
1493 <th style
='width:5%'><?php
echo xlt('ID'); ?
> 
;<span
class="help" title
='<?php echo xla('A unique value to identify this field
, not visible to the user
'); ?>' >(?
)</span
></th
>
1494 <th style
='width:10%'><?php
echo xlt('Label'); ?
> 
;<span
class="help" title
='<?php echo xla('The label that appears to the user on the form
'); ?>' >(?
)</span
></th
>
1495 <th style
='width:6%'><?php
echo xlt('UOR'); ?
></th
>
1496 <th style
='width:10%'><?php
echo xlt('Data Type'); ?
></th
>
1497 <th style
='width:1%'><?php
echo xlt('Size'); ?
></th
>
1498 <th style
='width:1%'><?php
echo xlt('Max Size'); ?
></th
>
1499 <th style
='width:10%'><?php
echo xlt('List'); ?
></th
>
1500 <th style
='width:10%'><?php
echo xlt('Backup List'); ?
></th
>
1501 <th style
='width:1%'><?php
echo xlt('Label Cols'); ?
></th
>
1502 <th style
='width:1%'><?php
echo xlt('Data Cols'); ?
></th
>
1503 <th style
='width:10%'><?php
echo xlt('Options'); ?
></th
>
1504 <th style
='width:20%'><?php
echo xlt('Description'); ?
></th
>
1509 <td
><input type
="text" name
="gnewseq" id
="gnewseq" value
="" size
="2" maxlength
="4"> </td
>
1510 <td
<?php
echo " $lbfonly"; ?
>>
1511 <select
class='form-control' name
='gnewsource' id
='gnewsource'>
1513 foreach ($sources as $key => $value) {
1514 echo "<option value='" . attr($key) . "'>" . text($value) . "</option>\n";
1519 <td
><input type
="text" name
="gnewid" id
="gnewid" value
="" size
="10" maxlength
="20"
1520 onclick
='FieldIDClicked(this)'> </td
>
1521 <td
><input type
="text" name
="gnewtitle" id
="gnewtitle" value
="" size
="20" maxlength
="63"> </td
>
1523 <select
class='form-control' name
="gnewuor" id
="gnewuor">
1524 <option value
="0"><?php
echo xlt('Unused'); ?
></option
>
1525 <option value
="1" selected
><?php
echo xlt('Optional'); ?
></option
>
1526 <option value
="2"><?php
echo xlt('Required'); ?
></option
>
1530 <select
class='form-control' name
='gnewdatatype' id
='gnewdatatype'>
1531 <option value
=''></option
>
1534 foreach ($datatypes as $key => $value) {
1535 echo "<option value='" . attr($key) . "'>" . text($value) . "</option>";
1540 <td
><input type
="text" name
="gnewlengthWidth" id
="gnewlengthWidth" value
="" size
="1" maxlength
="3" title
="<?php echo xla('Width'); ?>">
1541 <input type
="text" name
="gnewlengthHeight" id
="gnewlengthHeight" value
="" size
="1" maxlength
="3" title
="<?php echo xla('Height'); ?>"></td
>
1542 <td
><input type
="text" name
="gnewmaxSize" id
="gnewmaxSize" value
="" size
="1" maxlength
="3" title
="<?php echo xla('Maximum Size (entering 0 will allow any size)'); ?>"></td
>
1543 <td
><input type
="text" name
="gnewlistid" id
="gnewlistid" value
="" size
="8" maxlength
="100" class="listid">
1544 <select
class='form-control' name
='gcontextName' id
='gcontextName' style
='display:none'>
1546 $res = sqlStatement("SELECT * FROM customlists WHERE cl_list_type=2 AND cl_deleted=0");
1547 while ($row = sqlFetchArray($res)) {
1548 echo "<option value='" . attr($row['cl_list_item_long']) . "'>" . text($row['cl_list_item_long']) . "</option>";
1553 <td
><input type
="text" name
="gnewbackuplistid" id
="gnewbackuplistid" value
="" size
="8" maxlength
="100" class="listid"></td
>
1554 <td
><input type
="text" name
="gnewtitlecols" id
="gnewtitlecols" value
="" size
="3" maxlength
="3"> </td
>
1555 <td
><input type
="text" name
="gnewdatacols" id
="gnewdatacols" value
="" size
="3" maxlength
="3"> </td
>
1556 <td
><select name
="gnewedit_options[]" id
="gnewedit_options" class="typeAddons" multiple style
='width:100%' value
="" size
="3"></select
>
1557 <input type
="hidden" name
="gnewdefault" id
="gnewdefault" value
="" /> </td
>
1558 <td
><input type
="text" name
="gnewdesc" id
="gnewdesc" value
="" size
="30"> </td
>
1563 <input type
="button" class="savenewgroup" value
='<?php echo xla('Save
New Group
'); ?>'>
1564 <input type
="button" class="cancelnewgroup" value
='<?php echo xla('Cancel
'); ?>'>
1568 <!-- template DIV that appears when user chooses to add a
new field to a group
-->
1569 <div id
="fielddetail" class="fielddetail" style
="display: none; visibility: hidden">
1570 <input type
="hidden" name
="newfieldgroupid" id
="newfieldgroupid" value
="">
1571 <table
class="table table-condensed" style
="border-collapse: collapse;">
1574 <th style
='width:1%'><?php
echo xlt('Order'); ?
></th
>
1575 <th
<?php
echo " $lbfonly"; ?
>style
='width:5%'><?php
echo xlt('Source'); ?
></th
>
1576 <th style
='width:5%'><?php
echo xlt('ID'); ?
> 
;<span
class="help" title
='<?php echo xla('A unique value to identify this field
, not visible to the user
'); ?>' >(?
)</span
></th
>
1577 <th style
='width:10%'><?php
echo xlt('Label'); ?
> 
;<span
class="help" title
='<?php echo xla('The label that appears to the user on the form
'); ?>' >(?
)</span
></th
>
1578 <th style
='width:6%'><?php
echo xlt('UOR'); ?
></th
>
1579 <th style
='width:10%'><?php
echo xlt('Data Type'); ?
></th
>
1580 <th style
='width:1%'><?php
echo xlt('Size'); ?
></th
>
1581 <th style
='width:1%'><?php
echo xlt('Max Size'); ?
></th
>
1582 <th style
='width:10%'><?php
echo xlt('List'); ?
></th
>
1583 <th style
='width:10%'><?php
echo xlt('Backup List'); ?
></th
>
1584 <th style
='width:1%'><?php
echo xlt('Label Cols'); ?
></th
>
1585 <th style
='width:1%'><?php
echo xlt('Data Cols'); ?
></th
>
1586 <th style
='width:10%'><?php
echo xlt('Options'); ?
></th
>
1587 <th style
='width:20%'><?php
echo xlt('Description'); ?
></th
>
1592 <td
><input type
="text" name
="newseq" id
="newseq" value
="" size
="2" maxlength
="4"> </td
>
1593 <td
<?php
echo " $lbfonly"; ?
>>
1594 <select
class='form-control' name
='newsource' id
='newsource'>
1596 foreach ($sources as $key => $value) {
1597 echo " <option value='" . attr($key) . "'>" . text($value) . "</option>\n";
1602 <td
><input type
="text" name
="newid" id
="newid" value
="" size
="10" maxlength
="20"
1603 onclick
='FieldIDClicked(this)'> </td
>
1604 <td
><input type
="text" name
="newtitle" id
="newtitle" value
="" size
="20" maxlength
="63"> </td
>
1606 <select
class='form-control' name
="newuor" id
="newuor">
1607 <option value
="0"><?php
echo xlt('Unused'); ?
></option
>
1608 <option value
="1" selected
><?php
echo xlt('Optional'); ?
></option
>
1609 <option value
="2"><?php
echo xlt('Required'); ?
></option
>
1613 <select
class='form-control' name
='newdatatype' id
='newdatatype'>
1614 <option value
=''></option
>
1617 foreach ($datatypes as $key => $value) {
1618 echo " <option value='" . attr($key) . "'>" . text($value) . "</option>\n";
1623 <td
><input type
="text" name
="newlengthWidth" id
="newlengthWidth" value
="" size
="1" maxlength
="3" title
="<?php echo xla('Width'); ?>">
1624 <input type
="text" name
="newlengthHeight" id
="newlengthHeight" value
="" size
="1" maxlength
="3" title
="<?php echo xla('Height'); ?>"></td
>
1625 <td
><input type
="text" name
="newmaxSize" id
="newmaxSize" value
="" size
="1" maxlength
="3" title
="<?php echo xla('Maximum Size (entering 0 will allow any size)'); ?>"></td
>
1626 <td
><input type
="text" name
="newlistid" id
="newlistid" value
="" size
="8" maxlength
="31" class="listid">
1627 <select
class='form-control' name
='contextName' id
='contextName' style
='display:none'>
1629 $res = sqlStatement("SELECT * FROM customlists WHERE cl_list_type=2 AND cl_deleted=0");
1630 while ($row = sqlFetchArray($res)) {
1631 echo "<option value='" . attr($row['cl_list_item_long']) . "'>" . text($row['cl_list_item_long']) . "</option>";
1636 <td
><input type
="text" name
="newbackuplistid" id
="newbackuplistid" value
="" size
="8" maxlength
="31" class="listid"></td
>
1637 <td
><input type
="text" name
="newtitlecols" id
="newtitlecols" value
="" size
="3" maxlength
="3"> </td
>
1638 <td
><input type
="text" name
="newdatacols" id
="newdatacols" value
="" size
="3" maxlength
="3"> </td
>
1639 <td
><select name
="newedit_options[]" id
="newedit_options" multiple
class='typeAddons' style
='width:100%'></select
>
1640 <input type
="hidden" name
="newdefault" id
="newdefault" value
="" /> </td
>
1641 <td
><input type
="text" name
="newdesc" id
="newdesc" value
="" size
="30"> </td
>
1645 <input type
="button" class="savenewfield" value
='<?php echo xla('Save
New Field
'); ?>'>
1646 <input type
="button" class="cancelnewfield" value
='<?php echo xla('Cancel
'); ?>'>
1656 /* Field modifier objects - heading towards context based.
1657 Used by Select2 so rtl may be enabled*/
1658 <?php
echo "var fldOptions = [
1659 {id: 'A',text:" . xlj('Age') . ",ctx:['4'],ctxExcp:['0']},
1660 {id: 'B',text:" . xlj('Gestational Age') . ",ctx:['4'],ctxExcp:['0']},
1661 {id: 'F',text:" . xlj('Add Time to Date') . ",ctx:['4'],ctxExcp:['0']},
1662 {id: 'C',text:" . xlj('Capitalize') . ",ctx:['0'],ctxExcp:['4','15','40']},
1663 {id: 'D',text:" . xlj('Dup Check') . "},
1664 {id: 'E',text:" . xlj('Dup Check on only Edit') . "},
1665 {id: 'W',text:" . xlj('Dup Check on only New') . "},
1666 {id: 'G',text:" . xlj('Graphable') . "},
1667 {id: 'I',text:" . xlj('Initially Open Group') . "},
1668 {id: 'J',text:" . xlj('Jump to Next Row') . "},
1669 {id: 'K',text:" . xlj('Prepend Blank Row') . "},
1670 {id: 'L',text:" . xlj('Lab Order') . "},
1671 {id: 'M',text:" . xlj('Radio Group Master') . "},
1672 {id: 'm',text:" . xlj('Radio Group Member') . "},
1673 {id: 'N',text:" . xlj('New Patient Form') . "},
1674 {id: 'O',text:" . xlj('Order Processor') . "},
1675 {id: 'P',text:" . xlj('Default to previous value') . "},
1676 {id: 'R',text:" . xlj('Distributor') . "},
1677 {id: 'T',text:" . xlj('Description is default text') . "},
1678 {id: 'U',text:" . xlj('Capitalize all') . "},
1679 {id: 'V',text:" . xlj('Vendor') . "},
1680 {id: 'X',text:" . xlj('Do Not Print') . "},
1681 {id:'grp',text:" . xlj('Stylings') . ",children:[
1682 {id: 'RS',text:" . xlj('Add Bottom Border Row') . "},
1683 {id: 'RO',text:" . xlj('Outline Entire Row') . "},
1684 {id: 'DS',text:" . xlj('Add Data Bottom Border') . "},
1685 {id: 'DO',text:" . xlj('Outline Data Col') . "},
1686 {id: 'SP',text:" . xlj('Span Entire Row') . "}
1688 {id: '0',text:" . xlj('Read Only') . "},
1689 {id: '1',text:" . xlj('Write Once') . "},
1690 {id: '2',text:" . xlj('Billing Code Descriptions') . "}];\n";
1692 // Language direction for select2
1693 echo 'var langDirection = ' . js_escape($_SESSION['language_direction']) . ';';
1696 // used when selecting a list-name for a field
1699 // Support for beforeunload handler.
1700 var somethingChanged
= false;
1702 // Get the next logical sequence number for a field in the specified group.
1703 // Note it guesses and uses the existing increment value.
1704 function getNextSeq(group
) {
1705 var f
= document
.forms
[0];
1708 for (var i
= 1; true; ++i
) {
1709 var gelem
= f
['fld[' + i +
'][group]'];
1711 if (gelem
.value
!= group
) continue;
1712 var tmp
= parseInt(f
['fld[' + i +
'][seq]'].value
);
1713 if (isNaN(tmp
)) continue;
1714 if (tmp
<= seq
) continue;
1721 // Helper function for validating new fields.
1722 function validateNewField(idpfx
) {
1723 var f
= document
.forms
[0];
1724 var pfx
= '#' + idpfx
;
1725 var newid
= $
(pfx +
"id").val();
1727 // seq must be numeric and <= 9999
1728 if (! IsNumeric($
(pfx +
"seq").val(), 0, 9999)) {
1729 alert(<?php
echo xlj('Order must be a number between 1 and 9999'); ?
>);
1732 // length must be numeric and less than 999
1733 if (! IsNumeric($
(pfx +
"lengthWidth").val(), 0, 999)) {
1734 alert(<?php
echo xlj('Size must be a number between 1 and 999'); ?
>);
1737 // titlecols must be numeric and less than 100
1738 if (! IsNumeric($
(pfx +
"titlecols").val(), 0, 999)) {
1739 alert(<?php
echo xlj('LabelCols must be a number between 1 and 999'); ?
>);
1742 // datacols must be numeric and less than 100
1743 if (! IsNumeric($
(pfx +
"datacols").val(), 0, 999)) {
1744 alert(<?php
echo xlj('DataCols must be a number between 1 and 999'); ?
>);
1747 // the id field can only have letters, numbers and underscores
1748 if ($
(pfx +
"id").val() == "") {
1749 alert(<?php
echo xlj('ID cannot be blank'); ?
>);
1753 // Make sure the field ID is not duplicated.
1754 for (var j
= 1; f
['fld[' + j +
'][id]']; ++j
) {
1755 if (newid
.toLowerCase() == f
['fld[' + j +
'][id]'].value
.toLowerCase() ||
1756 newid
.toLowerCase() == f
['fld[' + j +
'][originalid]'].value
.toLowerCase())
1758 alert(<?php
echo xlj('Error: Duplicated field ID'); ?
> +
': ' + newid
);
1763 // the id field can only have letters, numbers and underscores
1764 var validid
= $
(pfx +
"id").val().replace(/(\s|\W
)/g
, "_"); // match any non-word characters and replace them
1765 $
(pfx +
"id").val(validid
);
1766 // similarly with the listid field
1767 validid
= $
(pfx +
"listid").val().replace(/(\s|\W
)/g
, "_");
1768 $
(pfx +
"listid").val(validid
);
1769 // similarly with the backuplistid field
1770 validid
= $
(pfx +
"backuplistid").val().replace(/(\s|\W
)/g
, "_");
1771 $
(pfx +
"backuplistid").val(validid
);
1776 // jQuery stuff to make the page a little easier to use
1781 $
('.typeAddons').select2({
1785 closeOnSelect
: false,
1787 minimumResultsForSearch
: 'Infinity',
1788 containerCssClass
: ':all:',
1790 <?php
require($GLOBALS['srcdir'] . '/js/xl/select2.js.php'); ?
>
1793 // Populate field option selects
1795 $
('.typeAddons').each(function(i
, obj
) {
1796 var v
= $
(this
).data('set')
1797 if(typeof v
!== 'undefined' && v
> ""){
1798 $
(this
).val(v
).trigger("change")
1801 somethingChanged
= false;
1804 $
("#save").click(function() { SaveChanges(); });
1805 $
("#layout_id").change(function() {
1806 if (!myChangeCheck()) {
1807 $
("#layout_id").val(<?php
echo js_escape($layout_id); ?
>);
1812 $
(".addgroup").click(function() { AddGroup(this
); });
1813 $
(".savenewgroup").click(function() { SaveNewGroup(this
); });
1814 /******************************************************************
1815 $(".deletegroup").click(function() { DeleteGroup(this); });
1816 ******************************************************************/
1817 $
(".cancelnewgroup").click(function() { CancelNewGroup(this
); });
1818 $
(".movegroup").click(function() { MoveGroup(this
); });
1819 $
(".renamegroup").click(function() { RenameGroup(this
); });
1820 $
(".saverenamegroup").click(function() { SaveRenameGroup(this
); });
1821 $
(".cancelrenamegroup").click(function() { CancelRenameGroup(this
); });
1822 $
(".addfield").click(function() { AddField(this
); });
1823 $
("#deletefields").click(function() { DeleteFields(this
); });
1824 $
(".selectfield").click(function() {
1825 var TRparent
= $
(this
).parent().parent();
1826 $
(TRparent
).children("td").toggleClass("highlight");
1827 // disable the delete-move buttons
1828 $
("#deletefields").attr("disabled", "disabled");
1829 $
("#movefields").attr("disabled", "disabled");
1830 $
(".selectfield").each(function(i
) {
1831 // if any field is selected, enable the delete-move buttons
1832 if ($
(this
).prop("checked") == true) {
1833 $
("#deletefields").removeAttr("disabled");
1834 $
("#movefields").removeAttr("disabled");
1839 $
("#movefields").click(function() { ShowGroups(this
); });
1840 $
(".savenewfield").click(function() { SaveNewField(this
); });
1841 $
(".cancelnewfield").click(function() { CancelNewField(this
); });
1842 $
("#newtitle").blur(function() { if ($
("#newid").val() == "") $
("#newid").val($
("#newtitle").val()); });
1843 $
("#newdatatype").change(function() { ChangeList(this
.value
);});
1844 $
("#gnewdatatype").change(function() { ChangeListg(this
.value
);});
1845 $
(".listid").click(function() { ShowLists(this
); });
1847 // special class that skips the element
1848 $
(".noselect").focus(function() { $
(this
).blur(); });
1850 // Save the changes made to the form
1851 var SaveChanges
= function () {
1852 var f
= document
.forms
[0];
1853 for (var i
= 1; f
['fld['+i+
'][id]']; ++i
) {
1854 var ival
= f
['fld['+i+
'][id]'].value
;
1855 for (var j
= i +
1; f
['fld['+j+
'][id]']; ++j
) {
1856 if (ival
.toLowerCase() == f
['fld['+j+
'][id]'].value
.toLowerCase() ||
1857 ival
.toLowerCase() == f
['fld['+j+
'][originalid]'].value
.toLowerCase())
1859 alert(<?php
echo xlj('Error: Duplicated field ID'); ?
> +
': ' + ival
);
1864 $
("#formaction").val("save");
1868 /****************************************************/
1869 /************ Group functions ***********************/
1870 /****************************************************/
1872 // display the 'new group' DIV
1873 var AddGroup
= function(btnObj
) {
1874 if (!myChangeCheck()) return;
1875 $
("#save").attr("disabled", true);
1876 // show the field details DIV
1877 $
('#groupdetail').css('visibility', 'visible');
1878 $
('#groupdetail').css('display', 'block');
1879 $
('#groupdetail').css('margin-top', '85px');
1880 $
(btnObj
).parent().after($
("#groupdetail"));
1881 $
("html, body").animate({ scrollTop
: 0 }, "slow");
1882 $
('#groupdetail > #newgroupname').focus();
1883 // Assign a sensible default sequence number.
1884 $
('#gnewseq').val(10);
1887 // save the new group to the form
1888 var SaveNewGroup
= function(btnObj
) {
1889 // the group name field can only have letters, numbers, spaces and underscores
1890 // AND it cannot start with a number
1891 if ($
("#newgroupname").val() == "") {
1892 alert(<?php
echo xlj('Group names cannot be blank'); ?
>);
1895 if ($
("#newgroupname").val().match(/^
(\d+|\s+
)/)) {
1896 alert(<?php
echo xlj('Group names cannot start with numbers or spaces.'); ?
>);
1899 var validname
= $
("#newgroupname").val().replace(/[^A
-za
-z0
-9 ]/g
, "_"); // match any non-word characters and replace them
1900 $
("#newgroupname").val(validname
);
1902 // now, check the first group field values
1903 if (!validateNewField('gnew')) return false;
1905 // submit the form to add a new field to a specific group
1906 $
("#formaction").val("addgroup");
1910 /******************************************************************
1911 // actually delete an entire group from the database
1912 var DeleteGroup = function(btnObj) {
1913 var parts = $(btnObj).attr("id");
1914 var groupname = parts.replace(/^\d+/, "");
1915 if (confirm(<?php echo xlj('WARNING') ?> + " - " + <?php echo xlj('This action cannot be undone.') ?> + "\n" + <?php echo xlj('Are you sure you wish to delete the entire group named'); ?> + " '" + groupname + "'?")) {
1916 // submit the form to add a new field to a specific group
1917 $("#formaction").val("deletegroup");
1918 $("#deletegroupname").val(parts);
1919 $("#theform").submit();
1922 ******************************************************************/
1924 // just hide the new field DIV
1925 var CancelNewGroup
= function(btnObj
) {
1926 // hide the field details DIV
1927 $
('#groupdetail').css('visibility', 'hidden');
1928 $
('#groupdetail').css('display', 'none');
1929 // reset the new group values to a default
1930 $
('#groupdetail > #newgroupname').val("");
1931 $
('#groupdetail > #newgroupparent').val("");
1932 $
("#save").attr("disabled", false);
1935 // display the 'new field' DIV
1936 var MoveGroup
= function(btnObj
) {
1937 if (!myChangeCheck()) return;
1938 var btnid
= $
(btnObj
).attr("id");
1939 var parts
= btnid
.split("~");
1940 var groupid
= parts
[0];
1941 var direction
= parts
[1];
1942 // submit the form to change group order
1943 $
("#formaction").val("movegroup");
1944 $
("#movegroupname").val(groupid
);
1945 $
("#movedirection").val(direction
);
1949 // show the rename group DIV
1950 var RenameGroup
= function(btnObj
) {
1951 if (!myChangeCheck()) return;
1952 $
("#save").attr("disabled", true);
1953 $
('#renamegroupdetail').css('visibility', 'visible');
1954 $
('#renamegroupdetail').css('display', 'block');
1955 $
(btnObj
).parent().append($
("#renamegroupdetail"));
1956 var parts
= $
(btnObj
).attr("id").split("~");
1957 $
('#renameoldgroupname').val(parts
[0]); // this is actually the existing group ID
1958 $
('#renamegroupname').val(parts
[1]); // the textual name of just this group
1959 var i
= parts
[0].length
;
1960 $
('[name=renamegroupparent]').val(i
> 0 ? parts
[0].substr(0, i
-1) : ''); // parent ID
1963 // save the new group to the form
1964 var SaveRenameGroup
= function(btnObj
) {
1965 // the group name field can only have letters, numbers, spaces and underscores
1966 // AND it cannot start with a number
1967 if ($
("#renamegroupname").val().match(/^\d+
/)) {
1968 alert(<?php
echo xlj('Group names cannot start with numbers.'); ?
>);
1971 var validname
= $
("#renamegroupname").val().replace(/[^A
-za
-z0
-9 ]/g
, "_"); // match any non-word characters and replace them
1972 $
("#renamegroupname").val(validname
);
1974 // submit the form to add a new field to a specific group
1975 $
("#formaction").val("renamegroup");
1979 // just hide the new field DIV
1980 var CancelRenameGroup
= function(btnObj
) {
1981 // hide the field details DIV
1982 $
('#renamegroupdetail').css('visibility', 'hidden');
1983 $
('#renamegroupdetail').css('display', 'none');
1984 // reset the rename group values to a default
1985 $
('#renameoldgroupname').val("");
1986 $
('#renamegroupname').val("");
1987 $
('#renamegroupparent').val("");
1990 /****************************************************/
1991 /************ Field functions ***********************/
1992 /****************************************************/
1994 // display the 'new field' DIV
1995 var AddField
= function(btnObj
) {
1996 if (!myChangeCheck()) return;
1997 $
("#save").attr("disabled", true);
1998 // update the fieldgroup value to be the groupid
1999 var btnid
= $
(btnObj
).attr("id");
2000 var parts
= btnid
.split("~");
2001 var groupid
= parts
[1];
2002 $
('#fielddetail > #newfieldgroupid').attr('value', groupid
);
2003 // show the field details DIV
2004 $
('#fielddetail').css('visibility', 'visible');
2005 $
('#fielddetail').css('display', 'block');
2006 $
(btnObj
).parent().append($
("#fielddetail"));
2007 // Assign a sensible default sequence number.
2008 $
('#newseq').val(getNextSeq(groupid
));
2011 var DeleteFields
= function(btnObj
) {
2012 if (!myChangeCheck()) return;
2013 if (confirm(<?php
echo xlj('WARNING'); ?
> +
" - " +
<?php
echo xlj('This action cannot be undone.'); ?
> +
'\n' +
<?php
echo xlj('Are you sure you wish to delete the selected fields?'); ?
>)) {
2015 $
(".selectfield").each(function(i
) {
2016 // build a list of selected field names to be moved
2017 if ($
(this
).prop("checked") == true) {
2018 var parts
= this
.id
.split("~");
2019 var currval
= $
("#selectedfields").val();
2020 $
("#selectedfields").val(currval+delim+parts
[1]);
2024 // submit the form to delete the field(s)
2025 $
("#formaction").val("deletefields");
2030 // save the new field to the form
2031 var SaveNewField
= function(btnObj
) {
2032 // check the new field values for correct formatting
2033 if (!validateNewField('new')) return false;
2035 // submit the form to add a new field to a specific group
2036 $
("#formaction").val("addfield");
2040 // just hide the new field DIV
2041 var CancelNewField
= function(btnObj
) {
2042 // hide the field details DIV
2043 $
('#fielddetail').css('visibility', 'hidden');
2044 $
('#fielddetail').css('display', 'none');
2045 // reset the new field values to a default
2046 ResetNewFieldValues();
2047 $
("#save").attr("disabled", false);
2050 // show the popup choice of lists
2051 var ShowLists
= function(btnObj
) {
2052 var title
= <?php
echo xlj('Select List');?
>;
2053 dlgopen('../patient_file/encounter/find_code_dynamic.php?what=lists',"_blank", 850, 750, "", title
);
2054 selectedfield
= btnObj
;
2057 // show the popup choice of groups
2058 var ShowGroups
= function(btnObj
) {
2059 if (!myChangeCheck()) return;
2060 var title
= <?php
echo xlj('Select Group');?
>;
2061 dlgopen('../patient_file/encounter/find_code_dynamic.php?what=groups&layout_id=' +
<?php
echo js_url($layout_id); ?
>,
2062 "_blank",850, 600,"", title
);
2065 // Show context DD for NationNotes
2066 var ChangeList
= function(btnObj
){
2068 $
('#newlistid').hide();
2069 $
('#contextName').show();
2072 $
('#newlistid').show();
2073 $
('#contextName').hide();
2076 var ChangeListg
= function(btnObj
){
2078 $
('#gnewlistid').hide();
2079 $
('#gcontextName').show();
2082 $
('#gnewlistid').show();
2083 $
('#gcontextName').hide();
2087 // Initialize list item selectors and value field visibilities in skip conditions.
2088 var f
= document
.forms
[0];
2089 for (var lino
= 1; f
['fld[' + lino +
'][id]']; ++lino
) {
2090 for (var seq
= 0; f
['fld[' + lino +
'][condition_itemid][' + seq +
']']; ++seq
) {
2091 setListItemOptions(lino
, seq
, true);
2093 actionChanged(lino
);
2096 // Support for beforeunload handler.
2097 $
('tbody input, tbody select, tbody textarea').not('.selectfield').change(function() {
2098 somethingChanged
= true;
2100 window
.addEventListener("beforeunload", function (e
) {
2101 if (somethingChanged
&& !top
.timed_out
) {
2102 var msg
= <?php
echo xlj('You have unsaved changes.'); ?
>;
2103 e
.returnValue
= msg
; // Gecko, Trident, Chrome 34+
2104 return msg
; // Gecko, WebKit, Chrome <34
2108 }); /* Ready Done */
2110 function layoutLook(){
2111 var form
= <?php
echo js_escape($layout_id);?
>;
2112 var btnName
= <?php
echo xlj('Back To Editor');?
>;
2113 var url
= "../patient_file/encounter/view_form.php?isShow&id=0&formname=" +
encodeURIComponent(form
);
2114 var title
= <?php
echo xlj('LBF Encounter Form Preview');?
>;
2115 dlgopen(url
, '_blank', 1250, 800, "", title
);
2119 function NationNotesContext(lineitem
, val
) {
2120 // Check if function is needed.
2121 if (!document
.getElementById("fld[" + lineitem +
"][contextName]") ||
!document
.getElementById("fld[" + lineitem +
"][list_id]")) {
2122 return false; // these elements don't exist yet so do nothing.
2125 document
.getElementById("fld[" + lineitem +
"][contextName]").style
.display
= '';
2126 document
.getElementById("fld[" + lineitem +
"][list_id]").style
.display
= 'none';
2127 document
.getElementById("fld[" + lineitem +
"][list_id]").value
= '';
2130 document
.getElementById("fld[" + lineitem +
"][list_id]").style
.display
= '';
2131 document
.getElementById("fld[" + lineitem +
"][contextName]").style
.display
= 'none';
2132 document
.getElementById("fld[" + lineitem +
"][list_id]").value
= '';
2136 function SetList(listid
) {
2137 $
(selectedfield
).val(listid
);
2140 //////////////////////////////////////////////////////////////////////
2141 // The following supports the field ID selection pop-up.
2142 //////////////////////////////////////////////////////////////////////
2144 var fieldselectfield
;
2146 function elemFromPart(part
) {
2147 var ename
= fieldselectfield
.name
;
2148 // ename is like one of the following:
2149 // fld[$fld_line_no][id]
2152 // and "part" is what we substitute for the "id" part.
2153 var i
= ename
.lastIndexOf('id');
2154 ename
= ename
.substr(0, i
) + part + ename
.substr(i+
2);
2155 return document
.forms
[0][ename
];
2158 function FieldIDClicked(elem
) {
2159 <?php
if (substr($layout_id, 0, 3) == 'LBF') { ?
>
2160 fieldselectfield
= elem
;
2161 var srcval
= elemFromPart('source').value
;
2162 // If the field ID is for the local form, allow direct entry.
2163 if (srcval
== 'F') return;
2164 // Otherwise pop up the selection window.
2165 var title
= <?php
echo xlj('Select Field');?
>;
2166 dlgopen('../patient_file/encounter/find_code_dynamic.php?what=fields&source='
2167 +
encodeURIComponent(srcval
), "_blank", 700, 600, "", title
);
2171 function SetField(field_id
, title
, data_type
, uor
, fld_length
, max_length
,
2172 list_id
, titlecols
, datacols
, edit_options
, description
, fld_rows
)
2174 fieldselectfield
.value
= field_id
;
2175 elemFromPart('title' ).value
= title
;
2176 elemFromPart('datatype' ).value
= data_type
;
2177 elemFromPart('uor' ).value
= uor
;
2178 elemFromPart('lengthWidth' ).value
= fld_length
;
2179 elemFromPart('maxSize' ).value
= max_length
;
2180 elemFromPart('list_id' ).value
= list_id
;
2181 elemFromPart('titlecols' ).value
= titlecols
;
2182 elemFromPart('datacols' ).value
= datacols
;
2183 elemFromPart('edit_options').value
= edit_options
;
2184 elemFromPart('desc' ).value
= description
;
2185 elemFromPart('lengthHeight').value
= fld_rows
;
2188 //////////////////////////////////////////////////////////////////////
2189 // End code for field ID selection pop-up.
2190 //////////////////////////////////////////////////////////////////////
2192 /* this is called after the user chooses a new group from the popup window
2193 * it will submit the page so the selected fields can be moved into
2196 function MoveFields(targetgroup
) {
2197 $
("#targetgroup").val(targetgroup
);
2199 $
(".selectfield").each(function(i
) {
2200 // build a list of selected field names to be moved
2201 if ($
(this
).prop("checked") == true) {
2202 var parts
= this
.id
.split("~");
2203 var currval
= $
("#selectedfields").val();
2204 $
("#selectedfields").val(currval+delim+parts
[1]);
2208 $
("#formaction").val("movefields");
2212 // set the new-field values to a default state
2213 function ResetNewFieldValues () {
2214 $
("#newseq").val("");
2215 $
("#newsource").val("");
2216 $
("#newid").val("");
2217 $
("#newtitle").val("");
2218 $
("#newuor").val(1);
2219 $
("#newlengthWidth").val("");
2220 $
("#newlengthHeight").val("");
2221 $
("#newmaxSize").val("");
2222 $
("#newdatatype").val("");
2223 $
("#newlistid").val("");
2224 $
("#newbackuplistid").val("");
2225 $
("#newtitlecols").val("");
2226 $
("#newdatacols").val("");
2227 $
("#newedit_options").val("");
2228 $
("#newdefault").val("");
2229 $
("#newdesc").val("");
2232 // is value an integer and between min and max
2233 function IsNumeric(value
, min
, max
) {
2234 if (value
== "" || value
== null) return false;
2236 parseInt(value
) < min ||
2237 parseInt(value
) > max
)
2243 /****************************************************/
2244 /****************************************************/
2245 /****************************************************/
2247 // tell if num is an Integer
2248 function IsN(num
) { return !/\D
/.test(num
); }