csrf ongoing work (#1803)
[openemr.git] / interface / super / edit_layout.php
blob931369bb449a4f661e22fd78e218520097df5cd0
1 <?php
2 /**
3 * Edit layouts gui
5 * @package OpenEMR
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-2017 Rod Roark <rod@sunsetsystems.com>
11 * @copyright Copyright (c) 2017 Jerry Padgett <sjpadgett@gmail.com>
12 * @copyright Copyright (c) 2017 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");
18 require_once("$srcdir/log.inc");
20 use OpenEMR\Core\Header;
22 function collectLayoutNames($condition, $mapping = '')
24 global $layouts;
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'];
31 if (!$tmp) {
32 $tmp = '(' . xl('No Name') . ')';
34 $layouts[$grow['grp_form_id']] = array($tmp, $grow['grp_title']);
37 $layouts = array();
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
52 $datatypes = array(
53 "1" => xl("List box"),
54 "2" => xl("Textbox"),
55 "3" => xl("Textarea"),
56 "4" => xl("Text-date"),
57 "10" => xl("Providers"),
58 "11" => xl("Providers NPI"),
59 "12" => xl("Pharmacies"),
60 "13" => xl("Squads"),
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"),
82 $sources = array(
83 'F' => xl('Form'),
84 'D' => xl('Patient'),
85 'H' => xl('History'),
86 'E' => xl('Visit'),
87 'V' => xl('VisForm'),
90 function nextGroupOrder($order)
92 if ($order == '9') {
93 $order = 'A';
94 } else if ($order == 'Z') {
95 $order = 'a';
96 } else {
97 $order = chr(ord($order) + 1);
100 return $order;
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 = '')
109 $res = sqlStatement(
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",
113 array($layout_id)
115 $s = "<select class='form-control' name='" . xla($name) . "'>";
116 $s .= "<option value=''>" . xlt('None') . "</option>";
117 $arr = array();
118 $arrid = '';
119 while ($row = sqlFetchArray($res)) {
120 $thisid = $row['grp_group_id'];
121 $i = 0;
122 // Compute number of initial matching groups.
123 while ($i < strlen($thisid) && $i < strlen($arrid) && $thisid[$i] == $arrid[$i]) {
124 ++$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'];
131 $gval = '';
132 foreach ($arr as $part) {
133 if ($gval) {
134 $gval .= ' / ';
136 $gval .= $part;
138 $s .= "<option value='" . attr($thisid) . "'";
139 if ($thisid == $default) {
140 $s .= ' selected';
142 $s .= ">" . text($gval) . "</option>";
144 $s .= "</select>";
145 return $s;
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)
156 global $layout_id;
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_%")
163 $maxnum = '1';
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)
179 global $layout_id;
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)
195 $i = 0;
196 while ($i < strlen($id1) && $i < strlen($id2) && $id1[$i] == $id2[$i]) {
197 ++$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") {
216 return '';
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";
228 } else {
229 die(xlt('Internal error in tableNameFromLayout') . '(' . text($layout_id) . ')');
231 return $tablename;
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);
240 if (!$tablename) {
241 return;
243 // Check if the column currently exists.
244 $tmp = sqlQuery("SHOW COLUMNS FROM `$tablename` LIKE '$field_id'");
245 $column_exists = !empty($tmp);
247 if ($add && !$column_exists) {
248 sqlStatement("ALTER TABLE `$tablename` ADD `$field_id` TEXT");
249 newEvent(
250 "alter_table",
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 `$field_id` FROM `$tablename` WHERE " .
259 "`$field_id` IS NOT NULL AND `$field_id` != '' LIMIT 1");
260 if (!isset($tmp['field_id'])) {
261 sqlStatement("ALTER TABLE `$tablename` DROP `$field_id`");
262 newEvent(
263 "alter_table",
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);
283 if (!$tablename) {
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.
290 return 2;
292 // Make sure new column does not exist.
293 $tmp = sqlQuery("SHOW COLUMNS FROM `$tablename` LIKE ?", array($new_field_id));
294 if (!empty($tmp)) {
295 // Error, new name already in use.
296 return 3;
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 .= " " . $colarr['Extra'];
309 $query = "ALTER TABLE `$tablename` CHANGE `$old_field_id` `$new_field_id` $colstr";
310 sqlStatement($query);
311 newEvent(
312 "alter_table",
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');
329 if (!$thisauth) {
330 die(xl('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 we are saving, then save.
343 $fld = $_POST['fld'];
344 for ($lino = 1; isset($fld[$lino]['id']); ++$lino) {
345 $iter = $fld[$lino];
346 $field_id = formTrim($iter['id']);
347 $field_id_original = formTrim($iter['originalid']);
348 $data_type = formTrim($iter['datatype']);
349 $listval = $data_type == 34 ? formTrim($iter['contextName']) : formTrim($iter['list_id']);
350 $action = $iter['action'];
351 if ($action == 'value') {
352 $action = 'value=' . $iter['value'];
355 // Skip conditions for the line are stored as a serialized array.
356 $condarr = array('action' => $action);
357 $cix = 0;
358 for (; !empty($iter['condition_id'][$cix]); ++$cix) {
359 $andor = empty($iter['condition_andor'][$cix]) ? '' : $iter['condition_andor'][$cix];
360 $condarr[$cix] = array(
361 'id' => strip_escape_custom($iter['condition_id' ][$cix]),
362 'itemid' => strip_escape_custom($iter['condition_itemid' ][$cix]),
363 'operator' => strip_escape_custom($iter['condition_operator'][$cix]),
364 'value' => strip_escape_custom($iter['condition_value' ][$cix]),
365 'andor' => strip_escape_custom($andor),
368 $conditions = $cix ? serialize($condarr) : '';
370 if ($field_id) {
371 if ($field_id != $field_id_original) {
372 if (renameColumn($layout_id, $field_id_original, $field_id) > 0) {
373 // If column rename had an error then don't rename it here.
374 $field_id = $field_id_original;
377 sqlStatement("UPDATE layout_options SET " .
378 "field_id = '" . formDataCore($field_id) . "', " .
379 "source = '" . formTrim($iter['source']) . "', " .
380 "title = '" . formDataCore($iter['title']) . "', " .
381 "group_id = '" . formTrim($iter['group']) . "', " .
382 "seq = '" . formTrim($iter['seq']) . "', " .
383 "uor = '" . formTrim($iter['uor']) . "', " .
384 "fld_length = '" . formTrim($iter['lengthWidth']) . "', " .
385 "fld_rows = '" . formTrim($iter['lengthHeight']) . "', " .
386 "max_length = '" . formTrim($iter['maxSize']) . "', " .
387 "titlecols = '" . formTrim($iter['titlecols']) . "', " .
388 "datacols = '" . formTrim($iter['datacols']) . "', " .
389 "data_type= '$data_type', " .
390 "list_id= '" . $listval . "', " .
391 "list_backup_id= '" . formTrim($iter['list_backup_id']) . "', " .
392 "edit_options = '" . encodeModifier($iter['edit_options']) . "', " .
393 "default_value = '" . formTrim($iter['default']) . "', " .
394 "description = '" . formTrim($iter['desc']) . "', " .
395 "conditions = '" . add_escape_custom($conditions) . "', " .
396 "validation = '" . formTrim($iter['validation']) . "' " .
397 "WHERE form_id = '$layout_id' AND field_id = '$field_id_original'");
400 } else if ($_POST['formaction'] == "addfield" && $layout_id) {
401 // Add a new field to a specific group
402 $data_type = formTrim($_POST['newdatatype']);
403 $max_length = $data_type == 3 ? 3 : 255;
404 $listval = $data_type == 34 ? formTrim($_POST['contextName']) : formTrim($_POST['newlistid']);
405 sqlStatement("INSERT INTO layout_options (" .
406 " form_id, source, field_id, title, group_id, seq, uor, fld_length, fld_rows" .
407 ", titlecols, datacols, data_type, edit_options, default_value, description" .
408 ", max_length, list_id, list_backup_id " .
409 ") VALUES ( " .
410 "'" . formTrim($_POST['layout_id']) . "'" .
411 ",'" . formTrim($_POST['newsource']) . "'" .
412 ",'" . formTrim($_POST['newid']) . "'" .
413 ",'" . formDataCore($_POST['newtitle']) . "'" .
414 ",'" . formTrim($_POST['newfieldgroupid']) . "'" .
415 ",'" . formTrim($_POST['newseq']) . "'" .
416 ",'" . formTrim($_POST['newuor']) . "'" .
417 ",'" . formTrim($_POST['newlengthWidth']) . "'" .
418 ",'" . formTrim($_POST['newlengthHeight']) . "'" .
419 ",'" . formTrim($_POST['newtitlecols']) . "'" .
420 ",'" . formTrim($_POST['newdatacols']) . "'" .
421 ",'$data_type'" .
422 ",'" . encodeModifier($_POST['newedit_options']) . "'" .
423 ",'" . formTrim($_POST['newdefault']) . "'" .
424 ",'" . formTrim($_POST['newdesc']) . "'" .
425 ",'" . formTrim($_POST['newmaxSize']) . "'" .
426 ",'" . $listval . "'" .
427 ",'" . formTrim($_POST['newbackuplistid']) . "'" .
428 " )");
429 addOrDeleteColumn($layout_id, formTrim($_POST['newid']), true);
430 } else if ($_POST['formaction'] == "movefields" && $layout_id) {
431 // Move field(s) to a new group in the layout
432 $sqlstmt = "UPDATE layout_options SET ".
433 " group_id = '" . $_POST['targetgroup'] . "' " .
434 " WHERE ".
435 " form_id = '" . $_POST['layout_id'] . "' ".
436 " AND field_id IN (";
437 $comma = "";
438 foreach (explode(" ", $_POST['selectedfields']) as $onefield) {
439 $sqlstmt .= $comma."'".$onefield."'";
440 $comma = ", ";
443 $sqlstmt .= ")";
444 //echo $sqlstmt;
445 sqlStatement($sqlstmt);
446 } else if ($_POST['formaction'] == "deletefields" && $layout_id) {
447 // Delete a field from a specific group
448 $sqlstmt = "DELETE FROM layout_options WHERE ".
449 " form_id = '".$_POST['layout_id']."' ".
450 " AND field_id IN (";
451 $comma = "";
452 foreach (explode(" ", $_POST['selectedfields']) as $onefield) {
453 $sqlstmt .= $comma."'".$onefield."'";
454 $comma = ", ";
457 $sqlstmt .= ")";
458 sqlStatement($sqlstmt);
459 foreach (explode(" ", $_POST['selectedfields']) as $onefield) {
460 addOrDeleteColumn($layout_id, $onefield, false);
462 } else if ($_POST['formaction'] == "addgroup" && $layout_id) {
463 // Generate new value for layout_items.group_id.
464 $newgroupid = genGroupId($_POST['newgroupparent']);
466 sqlStatement(
467 "INSERT INTO layout_group_properties SET " .
468 "grp_form_id = ?, " .
469 "grp_group_id = ?, " .
470 "grp_title = ?",
471 array($layout_id, $newgroupid, $_POST['newgroupname'])
474 $data_type = formTrim($_POST['gnewdatatype']);
475 $max_length = $data_type == 3 ? 3 : 255;
476 $listval = $data_type == 34 ? formTrim($_POST['gcontextName']) : formTrim($_POST['gnewlistid']);
477 // add a new group to the layout, with the defined field
478 sqlStatement("INSERT INTO layout_options (" .
479 " form_id, source, field_id, title, group_id, seq, uor, fld_length, fld_rows" .
480 ", titlecols, datacols, data_type, edit_options, default_value, description" .
481 ", max_length, list_id, list_backup_id " .
482 ") VALUES ( " .
483 "'" . formTrim($_POST['layout_id']) . "'" .
484 ",'" . formTrim($_POST['gnewsource']) . "'" .
485 ",'" . formTrim($_POST['gnewid']) . "'" .
486 ",'" . formDataCore($_POST['gnewtitle']) . "'" .
487 ",'" . formTrim($newgroupid) . "'" .
488 ",'" . formTrim($_POST['gnewseq']) . "'" .
489 ",'" . formTrim($_POST['gnewuor']) . "'" .
490 ",'" . formTrim($_POST['gnewlengthWidth']) . "'" .
491 ",'" . formTrim($_POST['gnewlengthHeight']) . "'" .
492 ",'" . formTrim($_POST['gnewtitlecols']) . "'" .
493 ",'" . formTrim($_POST['gnewdatacols']) . "'" .
494 ",'$data_type'" .
495 ",'" . encodeModifier($_POST['gnewedit_options']) . "'" .
496 ",'" . formTrim($_POST['gnewdefault']) . "'" .
497 ",'" . formTrim($_POST['gnewdesc']) . "'" .
498 ",'" . formTrim($_POST['gnewmaxSize']) . "'" .
499 ",'" . $listval . "'" .
500 ",'" . formTrim($_POST['gnewbackuplistid']) . "'" .
501 " )");
502 addOrDeleteColumn($layout_id, formTrim($_POST['gnewid']), true);
503 } /**********************************************************************
504 else if ($_POST['formaction'] == "deletegroup" && $layout_id) {
505 // drop the fields from the related table (this is critical)
506 $res = sqlStatement("SELECT field_id FROM layout_options WHERE " .
507 "form_id = '" . $_POST['layout_id'] . "' ".
508 "AND group_name = '" . $_POST['deletegroupname'] . "'");
509 while ($row = sqlFetchArray($res)) {
510 addOrDeleteColumn($layout_id, $row['field_id'], false);
513 // Delete an entire group from the form
514 sqlStatement("DELETE FROM layout_options WHERE ".
515 " form_id = '".$_POST['layout_id']."' ".
516 " AND group_name = '".$_POST['deletegroupname']."'"
519 **********************************************************************/
521 else if ($_POST['formaction'] == "movegroup" && $layout_id) {
522 // Note that in some cases below the swapGroups() call will do nothing.
523 $res = sqlStatement(
524 "SELECT DISTINCT group_id " .
525 "FROM layout_options WHERE form_id = ? ORDER BY group_id",
526 array($layout_id)
528 $row = sqlFetchArray($res);
529 $id1 = $row['group_id'];
530 while ($row = sqlFetchArray($res)) {
531 $id2 = $row['group_id'];
532 if ($_POST['movedirection'] == 'up') { // moving up
533 if ($id2 == $_POST['movegroupname']) {
534 swapGroups($id2, $id1);
535 break;
537 } else { // moving down
538 if ($id1 == $_POST['movegroupname']) {
539 swapGroups($id1, $id2);
540 break;
543 $id1 = $id2;
545 } // Renaming a group. This might include moving to a different parent group.
546 else if ($_POST['formaction'] == "renamegroup" && $layout_id) {
547 $newparent = $_POST['renamegroupparent']; // this is an ID
548 $oldid = $_POST['renameoldgroupname']; // this is an ID
549 $oldparent = substr($oldid, 0, -1);
550 $newid = $oldid;
551 if ($newparent != $oldparent) {
552 // Different parent, generate a new child prefix character.
553 $newid = genGroupId($newparent);
554 sqlStatement(
555 "UPDATE layout_options SET group_id = ? " .
556 "WHERE form_id = ? AND group_id = ?",
557 array($newid, $layout_id, $oldid)
560 $query = "UPDATE layout_group_properties SET " .
561 "grp_group_id = ?, grp_title = ? " .
562 "WHERE grp_form_id = ? AND grp_group_id = ?";
563 sqlStatement($query, array($newid, $_POST['renamegroupname'], $layout_id, $oldid));
566 // Get the selected form's elements.
567 if ($layout_id) {
568 $res = sqlStatement("SELECT * FROM layout_options WHERE " .
569 "form_id = '$layout_id' ORDER BY group_id, seq");
572 // global counter for field numbers
573 $fld_line_no = 0;
575 $extra_html = '';
577 // This is called to generate a select option list for fields within this form.
578 // Used for selecting a field for testing in a skip condition.
580 function genFieldOptionList($current = '')
582 global $layout_id;
583 $option_list = "<option value=''>-- " . xlt('Please Select') . " --</option>";
584 if ($layout_id) {
585 $query = "SELECT field_id FROM layout_options WHERE form_id = ? ORDER BY group_id, seq";
586 $res = sqlStatement($query, array($layout_id));
587 while ($row = sqlFetchArray($res)) {
588 $field_id = $row['field_id'];
589 $option_list .= "<option value='" . attr($field_id) . "'";
590 if ($field_id == $current) {
591 $option_list .= " selected";
593 $option_list .= ">" . text($field_id) . "</option>";
596 return $option_list;
599 // Write one option line to the form.
601 function writeFieldLine($linedata)
603 global $fld_line_no, $sources, $lbfonly, $extra_html,$validations;
604 ++$fld_line_no;
605 $checked = $linedata['default_value'] ? " checked" : "";
607 //echo " <tr bgcolor='$bgcolor'>\n";
608 echo " <tr id='fld[$fld_line_no]' class='".($fld_line_no % 2 ? 'even' : 'odd')."'>\n";
610 echo " <td class='optcell' nowrap>";
611 // tuck the group_name INPUT in here
612 echo "<input type='hidden' name='fld[$fld_line_no][group]' value='" .
613 htmlspecialchars($linedata['group_id'], ENT_QUOTES) . "' class='optin' />";
614 // Original field ID.
615 echo "<input type='hidden' name='fld[$fld_line_no][originalid]' value='" .
616 attr($linedata['field_id']) . "' />";
618 echo "<input type='checkbox' class='selectfield' ".
619 "name='" . $linedata['group_id'] . "~" . $linedata['field_id'] . "' " .
620 "id='" . $linedata['group_id'] . "~" . $linedata['field_id'] . "' " .
621 "title='" . xla('Select field') . "' />";
623 echo "<input type='text' name='fld[$fld_line_no][seq]' id='fld[$fld_line_no][seq]' value='" .
624 htmlspecialchars($linedata['seq'], ENT_QUOTES) . "' size='2' maxlength='4' " .
625 "class='optin' style='width:32pt' />";
626 echo "</td>\n";
628 echo " <td align='center' class='optcell' $lbfonly>";
629 echo "<select class='form-control' name='fld[$fld_line_no][source]' class='optin' $lbfonly>";
630 foreach ($sources as $key => $value) {
631 echo "<option value='" . attr($key) . "'";
632 if ($key == $linedata['source']) {
633 echo " selected";
636 echo ">" . text($value) . "</option>\n";
639 echo "</select>";
640 echo "</td>\n";
642 echo " <td align='left' class='optcell'>";
643 echo "<input type='text' name='fld[$fld_line_no][id]' value='" .
644 htmlspecialchars($linedata['field_id'], ENT_QUOTES) . "' size='15' maxlength='63' " .
645 "class='optin' style='width:100%' onclick='FieldIDClicked(this)' />";
646 echo "</td>\n";
648 echo " <td align='center' class='optcell'>";
649 echo "<input type='text' id='fld[$fld_line_no][title]' name='fld[$fld_line_no][title]' value='" .
650 htmlspecialchars($linedata['title'], ENT_QUOTES) . "' size='15' maxlength='63' class='optin' style='width:100%' />";
651 echo "</td>\n";
653 // if not english and set to translate layout labels, then show the translation
654 if ($GLOBALS['translate_layout'] && $_SESSION['language_choice'] > 1) {
655 echo "<td align='center' class='translation' >" . htmlspecialchars(xl($linedata['title']), ENT_QUOTES) . "</td>\n";
658 echo " <td align='center' class='optcell'>";
659 echo "<select class='form-control' name='fld[$fld_line_no][uor]' class='optin'>";
660 foreach (array(0 =>xl('Unused'), 1 =>xl('Optional'), 2 =>xl('Required')) as $key => $value) {
661 echo "<option value='$key'";
662 if ($key == $linedata['uor']) {
663 echo " selected";
666 echo ">$value</option>\n";
669 echo "</select>";
670 echo "</td>\n";
672 echo " <td align='center' class='optcell'>";
673 echo "<select class='form-control' name='fld[$fld_line_no][datatype]' id='fld[$fld_line_no][datatype]' onchange=NationNotesContext('".$fld_line_no."',this.value)>";
674 echo "<option value=''></option>";
675 global $datatypes;
676 foreach ($datatypes as $key => $value) {
677 if ($linedata['data_type'] == $key) {
678 echo "<option value='$key' selected>$value</option>";
679 } else {
680 echo "<option value='$key'>$value</option>";
684 echo "</select>";
685 echo " </td>";
687 echo " <td align='center' class='optcell'>";
688 if ($linedata['data_type'] == 2 || $linedata['data_type'] == 3 ||
689 $linedata['data_type'] == 21 || $linedata['data_type'] == 22 ||
690 $linedata['data_type'] == 23 || $linedata['data_type'] == 25 ||
691 $linedata['data_type'] == 27 || $linedata['data_type'] == 28 ||
692 $linedata['data_type'] == 32 || $linedata['data_type'] == 15 ||
693 $linedata['data_type'] == 40
695 // Show the width field
696 echo "<input type='text' name='fld[$fld_line_no][lengthWidth]' value='" .
697 htmlspecialchars($linedata['fld_length'], ENT_QUOTES) .
698 "' size='2' maxlength='10' class='optin' title='" . xla('Width') . "' />";
699 if ($linedata['data_type'] == 3 || $linedata['data_type'] == 40) {
700 // Show the height field
701 echo "<input type='text' name='fld[$fld_line_no][lengthHeight]' value='" .
702 htmlspecialchars($linedata['fld_rows'], ENT_QUOTES) .
703 "' size='2' maxlength='10' class='optin' title='" . xla('Height') . "' />";
704 } else {
705 // Hide the height field
706 echo "<input type='hidden' name='fld[$fld_line_no][lengthHeight]' value=''>";
708 } else {
709 // all other data_types (hide both the width and height fields
710 echo "<input type='hidden' name='fld[$fld_line_no][lengthWidth]' value=''>";
711 echo "<input type='hidden' name='fld[$fld_line_no][lengthHeight]' value=''>";
714 echo "</td>\n";
716 echo " <td align='center' class='optcell'>";
717 echo "<input type='text' name='fld[$fld_line_no][maxSize]' value='" .
718 htmlspecialchars($linedata['max_length'], ENT_QUOTES) .
719 "' size='1' maxlength='10' class='optin' style='width:100%' " .
720 "title='" . xla('Maximum Size (entering 0 will allow any size)') . "' />";
721 echo "</td>\n";
723 echo " <td align='center' class='optcell'>";
724 if ($linedata['data_type'] == 1 || $linedata['data_type'] == 21 ||
725 $linedata['data_type'] == 22 || $linedata['data_type'] == 23 ||
726 $linedata['data_type'] == 25 || $linedata['data_type'] == 26 ||
727 $linedata['data_type'] == 27 || $linedata['data_type'] == 32 ||
728 $linedata['data_type'] == 33 || $linedata['data_type'] == 34 ||
729 $linedata['data_type'] == 36) {
730 $type = "";
731 $disp = "style='display:none'";
732 if ($linedata['data_type'] == 34) {
733 $type = "style='display:none'";
734 $disp = "";
737 echo "<input type='text' name='fld[$fld_line_no][list_id]' id='fld[$fld_line_no][list_id]' value='" .
738 htmlspecialchars($linedata['list_id'], ENT_QUOTES) . "'".$type.
739 " size='6' maxlength='100' class='optin listid' style='width:100%;cursor:pointer'".
740 "title='". xl('Choose list') . "' />";
742 echo "<select class='form-control' name='fld[$fld_line_no][contextName]' id='fld[$fld_line_no][contextName]' ".$disp.">";
743 $res = sqlStatement("SELECT * FROM customlists WHERE cl_list_type=2 AND cl_deleted=0");
744 while ($row = sqlFetchArray($res)) {
745 $sel = '';
746 if ($linedata['list_id'] == $row['cl_list_item_long']) {
747 $sel = 'selected';
750 echo "<option value='".htmlspecialchars($row['cl_list_item_long'], ENT_QUOTES)."' ".$sel.">".htmlspecialchars($row['cl_list_item_long'], ENT_QUOTES)."</option>";
753 echo "</select>";
754 } else {
755 // all other data_types
756 echo "<input type='hidden' name='fld[$fld_line_no][list_id]' value=''>";
759 echo "</td>\n";
761 //Backup List Begin
762 echo " <td align='center' class='optcell'>";
763 if ($linedata['data_type'] == 1 || $linedata['data_type'] == 26 ||
764 $linedata['data_type'] == 33 || $linedata['data_type'] == 36) {
765 echo "<input type='text' name='fld[$fld_line_no][list_backup_id]' value='" .
766 htmlspecialchars($linedata['list_backup_id'], ENT_QUOTES) .
767 "' size='3' maxlength='100' class='optin listid' style='cursor:pointer; width:100%' />";
768 } else {
769 echo "<input type='hidden' name='fld[$fld_line_no][list_backup_id]' value=''>";
772 echo "</td>\n";
773 //Backup List End
775 echo " <td align='center' class='optcell'>";
776 echo "<input type='text' name='fld[$fld_line_no][titlecols]' value='" .
777 htmlspecialchars($linedata['titlecols'], ENT_QUOTES) . "' size='3' maxlength='10' class='optin' style='width:100%' />";
778 echo "</td>\n";
780 echo " <td align='center' class='optcell'>";
781 echo "<input type='text' name='fld[$fld_line_no][datacols]' value='" .
782 htmlspecialchars($linedata['datacols'], ENT_QUOTES) . "' size='3' maxlength='10' class='optin' style='width:100%' />";
783 echo "</td>\n";
784 /* Below for compatabilty with existing string modifiers. */
785 if (strpos($linedata['edit_options'], ',') === false && isset($linedata['edit_options'])) {
786 $t = json_decode($linedata['edit_options']);
787 if (json_last_error() !== JSON_ERROR_NONE || $t === 0) { // hopefully string of characters and 0 handled.
788 $t = str_split(trim($linedata['edit_options']));
789 $linedata['edit_options'] = json_encode($t); // convert to array select understands.
792 echo " <td align='center' class='optcell' title='" . xla("Add modifiers for this field type. You may select more than one.") . "'>";
793 echo "<select id='fld[$fld_line_no][edit_options]' name='fld[$fld_line_no][edit_options][]' class='typeAddons optin' size=3 multiple data-set='" .
794 trim($linedata['edit_options']) . "' ></select></td>\n";
796 if ($linedata['data_type'] == 31) {
797 echo " <td align='center' class='optcell'>";
798 echo "<textarea name='fld[$fld_line_no][desc]' rows='3' cols='35' class='optin' style='width:100%'>" .
799 $linedata['description'] . "</textarea>";
800 echo "<input type='hidden' name='fld[$fld_line_no][default]' value='" .
801 htmlspecialchars($linedata['default_value'], ENT_QUOTES) . "' />";
802 echo "</td>\n";
803 } else {
804 echo " <td align='center' class='optcell' >";
805 echo "<input type='text' name='fld[$fld_line_no][desc]' value='" .
806 htmlspecialchars($linedata['description'], ENT_QUOTES) .
807 "' size='30' class='optin' style='width:100%' />";
808 echo "<input type='hidden' name='fld[$fld_line_no][default]' value='" .
809 htmlspecialchars($linedata['default_value'], ENT_QUOTES) . "' />";
810 echo "</td>\n";
811 // if not english and showing layout labels, then show the translation of Description
812 if ($GLOBALS['translate_layout'] && $_SESSION['language_choice'] > 1) {
813 echo "<td align='center' class='translation'>" .
814 htmlspecialchars(xl($linedata['description']), ENT_QUOTES) . "</td>\n";
818 // The "?" to click on for yet more field attributes.
819 echo " <td class='bold' id='querytd_$fld_line_no' style='cursor:pointer;";
820 if (!empty($linedata['conditions']) || !empty($linedata['validation'])) {
821 echo "background-color:#77ff77;";
824 echo "' onclick='extShow($fld_line_no, this)' align='center' ";
825 echo "title='" . xla('Click here to view/edit more details') . "'>";
826 echo "&nbsp;?&nbsp;";
827 echo "</td>\n";
829 echo " </tr>\n";
831 // Create a floating div for the additional attributes of this field.
832 $conditions = empty($linedata['conditions']) ?
833 array(0 => array('id' => '', 'itemid' => '', 'operator' => '', 'value' => '')) :
834 unserialize($linedata['conditions']);
835 $action = empty($conditions['action']) ? 'skip' : $conditions['action'];
836 $action_value = $action == 'skip' ? '' : substr($action, 6);
838 $extra_html .= "<div id='ext_$fld_line_no' " .
839 "style='position:absolute;width:750px;border:1px solid black;" .
840 "padding:2px;background-color:#cccccc;visibility:hidden;" .
841 "z-index:1000;left:-1000px;top:0px;font-size:8pt;'>\n" .
842 "<table width='100%'>\n" .
843 " <tr>\n" .
844 " <th colspan='3' align='left' class='bold'>" .
845 xlt('For') . " " . text($linedata['field_id']) . " " .
846 "<select name='fld[$fld_line_no][action]' onchange='actionChanged($fld_line_no)'>" .
847 "<option value='skip' " . ($action == 'skip' ? 'selected' : '') . ">" . xlt('hide this field') . "</option>" .
848 "<option value='value' " . ($action != 'skip' ? 'selected' : '') . ">" . xlt('set value to') . "</option>" .
849 "</select>" .
850 "<input type='text' name='fld[$fld_line_no][value]' value='" . attr($action_value) . "' size='15' />" .
851 " " . xlt('if') .
852 "</th>\n" .
853 " <th colspan='2' align='right' class='text'><input type='button' " .
854 "value='" . xla('Close') . "' onclick='extShow($fld_line_no, false)' />&nbsp;</th>\n" .
855 " </tr>\n" .
856 " <tr>\n" .
857 " <th align='left' class='bold'>" . xlt('Field ID') . "</th>\n" .
858 " <th align='left' class='bold'>" . xlt('List item ID') . "</th>\n" .
859 " <th align='left' class='bold'>" . xlt('Operator') . "</th>\n" .
860 " <th align='left' class='bold'>" . xlt('Value if comparing') . "</th>\n" .
861 " <th align='left' class='bold'>&nbsp;</th>\n" .
862 " </tr>\n";
863 // There may be multiple condition lines for each field.
864 foreach ($conditions as $i => $condition) {
865 if (!is_numeric($i)) {
866 continue; // skip if 'action'
868 $extra_html .=
869 " <tr>\n" .
870 " <td align='left'>\n" .
871 " <select name='fld[$fld_line_no][condition_id][$i]' onchange='cidChanged($fld_line_no, $i)'>" .
872 genFieldOptionList($condition['id']) . " </select>\n" .
873 " </td>\n" .
874 " <td align='left'>\n" .
875 // List item choices are populated on the client side but will need the current value,
876 // so we insert a temporary option here to hold that value.
877 " <select name='fld[$fld_line_no][condition_itemid][$i]'><option value='" .
878 attr($condition['itemid']) . "'>...</option></select>\n" .
879 " </td>\n" .
880 " <td align='left'>\n" .
881 " <select name='fld[$fld_line_no][condition_operator][$i]'>\n";
882 foreach (array(
883 'eq' => xl('Equals'),
884 'ne' => xl('Does not equal'),
885 'se' => xl('Is selected'),
886 'ns' => xl('Is not selected'),
887 ) as $key => $value) {
888 $extra_html .= " <option value='$key'";
889 if ($key == $condition['operator']) {
890 $extra_html .= " selected";
893 $extra_html .= ">" . text($value) . "</option>\n";
896 $extra_html .=
897 " </select>\n" .
898 " </td>\n" .
899 " <td align='left' title='" . xla('Only for comparisons') . "'>\n" .
900 " <input type='text' name='fld[$fld_line_no][condition_value][$i]' value='" .
901 attr($condition['value']) . "' size='15' maxlength='63' />\n" .
902 " </td>\n";
903 if (!isset($conditions[$i + 1])) {
904 $extra_html .=
905 " <td align='right' title='" . xla('Add a condition') . "'>\n" .
906 " <input type='button' value='+' onclick='extAddCondition($fld_line_no,this)' />\n" .
907 " </td>\n";
908 } else {
909 $extra_html .=
910 " <td align='right'>\n" .
911 " <select name='fld[$fld_line_no][condition_andor][$i]'>\n";
912 foreach (array(
913 'and' => xl('And'),
914 'or' => xl('Or'),
915 ) as $key => $value) {
916 $extra_html .= " <option value='$key'";
917 if ($key == $condition['andor']) {
918 $extra_html .= " selected";
921 $extra_html .= ">" . text($value) . "</option>\n";
924 $extra_html .=
925 " </select>\n" .
926 " </td>\n";
929 $extra_html .=
930 " </tr>\n";
933 $extra_html .=
934 "</table>\n";
936 $extra_html .= "<table width='100%'>\n" .
937 " <tr>\n" .
938 " <td colspan='3' align='left' class='bold'>\"" . text($linedata['field_id']) . "\" " .
939 xlt('will have the following validation rules') . ":</td>\n" .
940 " </tr>\n" .
941 " <tr>\n" .
942 " <td align='left' class='bold'>" . xlt('Validation rule') . " </td>\n" .
943 " </tr>\n".
944 " <tr>\n" .
945 " <td align='left' title='" . xla('Select a validation rule') . "'>\n" .
948 " <select name='fld[$fld_line_no][validation]' onchange='valChanged($fld_line_no)'>\n" .
949 " <option value=''";
950 if (empty($linedata['validation'])) {
951 $extra_html .= " selected";
954 $extra_html .= ">-- " . xlt('Please Select') . " --</option>";
955 foreach ($validations as $key => $value) {
956 $extra_html .= " <option value='$key'";
957 if ($key == $linedata['validation']) {
958 $extra_html .= " selected";
961 $extra_html .= ">" . text($value) . "</option>\n";
964 $extra_html .="</select>\n" .
965 " </td>\n";
967 $extra_html .=
968 "</table>\n" .
969 "</div>\n";
972 <html>
974 <head>
976 <?php Header::setupHeader(['select2']); ?>
978 <title><?php xl('Layout Editor', 'e'); ?></title>
980 <style>
981 .orgTable tr.head { font-size:8pt; background-color:#cccccc; }
982 .orgTable tr.detail { font-size:8pt; }
983 .orgTable td { font-size:8pt; }
984 .orgTable input { font-size:8pt; }
985 .orgTable select { font-size:8pt; }
986 a, a:visited, a:hover { color:#0000cc; }
987 .optcell { }
988 .optin { background: transparent; }
989 .group {
990 margin: 0pt 0pt 8pt 0pt;
991 padding :0pt;
992 width: 100%;
995 .group table {
996 border-collapse: collapse;
997 width: 100%;
1000 .orgTable .odd td {
1001 background-color: #ddddff;
1002 padding: 3px 0px 3px 0px;
1004 .orgTable .even td {
1005 background-color: #ffdddd;
1006 padding: 3px 0px 3px 0px;
1008 .help { cursor: help; }
1009 .layouts_title { font-size: 110%; }
1010 .translation {
1011 color: green;
1012 font-size:8pt;
1014 .highlight * {
1015 border: 2px solid blue;
1016 background-color: yellow;
1017 color: black;
1019 .select2-container--default .select2-selection--multiple {
1020 cursor: pointer;
1022 .select2-search__field {
1023 cursor: pointer;
1024 width: 0 !important;
1026 .select2-selection__choice {
1027 font-size: 12px;
1029 .select2-container {
1030 cursor: pointer;
1031 opacity: 0.99 !important;
1033 .select2-dropdown {
1034 opacity: 0.99 !important;
1036 .tips {
1037 display: none;
1040 </style>
1042 <script>
1043 // Helper functions for positioning the floating divs.
1044 function extGetX(elem) {
1045 var x = 0;
1046 while(elem != null) {
1047 x += elem.offsetLeft;
1048 elem = elem.offsetParent;
1050 return x;
1052 function extGetY(elem) {
1053 var y = 0;
1054 while(elem != null) {
1055 y += elem.offsetTop;
1056 elem = elem.offsetParent;
1058 return y;
1061 // Show or hide the "extras" div for a row.
1062 var extdiv = null;
1063 function extShow(lino, show) {
1064 var thisdiv = document.getElementById("ext_" + lino);
1065 if (extdiv) {
1066 extdiv.style.visibility = 'hidden';
1067 extdiv.style.left = '-1000px';
1068 extdiv.style.top = '0px';
1070 if (show && thisdiv != extdiv) {
1071 extdiv = thisdiv;
1072 var dw = window.innerWidth ? window.innerWidth - 20 : document.body.clientWidth;
1073 x = dw - extdiv.offsetWidth;
1074 if (x < 0) x = 0;
1075 var y = extGetY(show) + show.offsetHeight;
1076 extdiv.style.left = x;
1077 extdiv.style.top = y;
1078 extdiv.style.visibility = 'visible';
1080 else {
1081 extdiv = null;
1085 // Show or hide the value field for a "Set value to" condition.
1086 function actionChanged(lino) {
1087 var f = document.forms[0];
1088 var eaction = f['fld[' + lino + '][action]'];
1089 var evalue = f['fld[' + lino + '][value]'];
1090 evalue.style.display = eaction.value == 'skip' ? 'none' : '';
1093 // Add an extra condition line for the given row.
1094 function extAddCondition(lino, btnelem) {
1095 var f = document.forms[0];
1096 var i = 0;
1098 // Get index of next condition line.
1099 while (f['fld[' + lino + '][condition_id][' + i + ']']) ++i;
1100 if (i == 0) alert('f["fld[' + lino + '][condition_id][' + i + ']"] <?php echo xls('not found') ?>');
1102 // Get containing <td>, <tr> and <table> nodes of the "+" button.
1103 var tdplus = btnelem.parentNode;
1104 var trelem = tdplus.parentNode;
1105 var telem = trelem.parentNode;
1107 // Replace contents of the tdplus cell.
1108 tdplus.innerHTML =
1109 "<select name='fld[" + lino + "][condition_andor][" + i + "]'>" +
1110 "<option value='and'><?php echo xls('And') ?></option>" +
1111 "<option value='or' ><?php echo xls('Or') ?></option>" +
1112 "</select>";
1114 // Add the new row.
1115 var newtrelem = telem.insertRow(i+2);
1116 newtrelem.innerHTML =
1117 "<td align='left'>" +
1118 "<select name='fld[" + lino + "][condition_id][" + i + "]' onchange='cidChanged(" + lino + "," + i + ")'>" +
1119 "<?php echo addslashes(genFieldOptionList()) ?>" +
1120 "</select>" +
1121 "</td>" +
1122 "<td align='left'>" +
1123 "<select name='fld[" + lino + "][condition_itemid][" + i + "]' style='display:none' />" +
1124 "</td>" +
1125 "<td align='left'>" +
1126 "<select name='fld[" + lino + "][condition_operator][" + i + "]'>" +
1127 "<option value='eq'><?php echo xls('Equals') ?></option>" +
1128 "<option value='ne'><?php echo xls('Does not equal') ?></option>" +
1129 "<option value='se'><?php echo xls('Is selected') ?></option>" +
1130 "<option value='ns'><?php echo xls('Is not selected') ?></option>" +
1131 "</select>" +
1132 "</td>" +
1133 "<td align='left'>" +
1134 "<input type='text' name='fld[" + lino + "][condition_value][" + i + "]' value='' size='15' maxlength='63' />" +
1135 "</td>" +
1136 "<td align='right'>" +
1137 "<input type='button' value='+' onclick='extAddCondition(" + lino + ",this)' />" +
1138 "</td>";
1141 // This is called when a field ID is chosen for testing within a skip condition.
1142 // It checks to see if a corresponding list item must also be chosen for the test, and
1143 // if so then inserts the dropdown for selecting an item from the appropriate list.
1144 function setListItemOptions(lino, seq, init) {
1145 var f = document.forms[0];
1146 var target = 'fld[' + lino + '][condition_itemid][' + seq + ']';
1147 // field_id is the ID of the field that the condition will test.
1148 var field_id = f['fld[' + lino + '][condition_id][' + seq + ']'].value;
1149 if (!field_id) {
1150 f[target].options.length = 0;
1151 f[target].style.display = 'none';
1152 return;
1154 // Find the occurrence of that field in the layout.
1155 var i = 1;
1156 while (true) {
1157 var idname = 'fld[' + i + '][id]';
1158 if (!f[idname]) {
1159 alert('<?php echo xls('Condition field not found') ?>: ' + field_id);
1160 return;
1162 if (f[idname].value == field_id) break;
1163 ++i;
1165 // If this is startup initialization then preserve the current value.
1166 var current = init ? f[target].value : '';
1167 f[target].options.length = 0;
1168 // Get the corresponding data type and list ID.
1169 var data_type = f['fld[' + i + '][datatype]'].value;
1170 var list_id = f['fld[' + i + '][list_id]'].value;
1171 // WARNING: If new data types are defined the following test may need enhancing.
1172 // We're getting out if the type does not generate multiple fields with different names.
1173 if (data_type != '21' && data_type != '22' && data_type != '23' && data_type != '25') {
1174 f[target].style.display = 'none';
1175 return;
1177 // OK, list item IDs do apply so go get 'em.
1178 // This happens asynchronously so the generated code needs to stand alone.
1179 f[target].style.display = '';
1180 $.getScript('layout_listitems_ajax.php' +
1181 '?listid=' + encodeURIComponent(list_id) +
1182 '&target=' + encodeURIComponent(target) +
1183 '&current=' + encodeURIComponent(current) +
1184 '&csrf_token_form=' + encodeURIComponent(<?php echo attr($_SESSION['csrf_token']); ?>));
1187 // This is called whenever a condition's field ID selection is changed.
1188 function cidChanged(lino, seq) {
1189 changeColor(lino);
1190 setListItemOptions(lino, seq, false);
1193 // This invokes the popup to edit layout properties or add a new layout.
1194 function edit_layout_props(groupid) {
1195 var title = "<?php echo xlt('Layout Properties');?>";
1196 dlgopen('edit_layout_props.php?layout_id=<?php echo attr($layout_id); ?>&group_id=' + groupid,
1197 '_blank', 775, 550, "", title);
1200 // callback from edit_layout_props.php:
1201 function refreshme(layout_id) {
1202 location.href = 'edit_layout.php?layout_id=' + layout_id;
1205 // This is called whenever a validation rule field ID selection is changed.
1206 function valChanged(lino) {
1207 changeColor(lino);
1210 function changeColor(lino){
1211 var thisid = document.forms[0]['fld[' + lino + '][condition_id][0]'].value;
1212 var thisValId = document.forms[0]['fld[' + lino + '][validation]'].value;
1213 var thistd = document.getElementById("querytd_" + lino);
1214 if(thisid !='' || thisValId!='') {
1215 thistd.style.backgroundColor = '#77ff77';
1216 }else{
1217 thistd.style.backgroundColor ='';
1221 // Call this to disable the warning about unsaved changes and submit the form.
1222 function mySubmit() {
1223 somethingChanged = false;
1224 top.restoreSession();
1225 document.forms[0].submit();
1228 // User is about to do something that would discard any unsaved changes.
1229 // Return true if that is OK.
1230 function myChangeCheck() {
1231 if (somethingChanged) {
1232 if (!confirm('<?php echo xls('You have unsaved changes. Abandon them?'); ?>')) {
1233 return false;
1235 // Do not set somethingChanged to false here because if they cancel the
1236 // action then the previously changed values will still be of interest.
1238 return true;
1241 </script>
1243 </head>
1245 <body class="body_top admin-layout">
1246 <div class="container-responsive">
1247 <form method='post' name='theform' id='theform' action='edit_layout.php'>
1248 <input type="hidden" name="formaction" id="formaction" value="">
1249 <!-- elements used to identify a field to delete -->
1250 <input type="hidden" name="deletefieldid" id="deletefieldid" value="">
1251 <input type="hidden" name="deletefieldgroup" id="deletefieldgroup" value="">
1252 <!-- elements used to identify a group to delete -->
1253 <!--
1254 <input type="hidden" name="deletegroupname" id="deletegroupname" value="">
1256 <!-- elements used to change the group order -->
1257 <input type="hidden" name="movegroupname" id="movegroupname" value="">
1258 <input type="hidden" name="movedirection" id="movedirection" value="">
1259 <!-- elements used to select more than one field -->
1260 <input type="hidden" name="selectedfields" id="selectedfields" value="">
1261 <input type="hidden" id="targetgroup" name="targetgroup" value="">
1263 <div class="menubar" style='padding:5px 0;'>
1265 <b><?php xl('Edit layout', 'e'); ?>:</b>&nbsp;
1266 <select name='layout_id' id='layout_id' class='form-control' style='display:inline-block;margin-bottom:5px;width:20%;'>
1267 <option value=''>-- <?php echo xl('Select') ?> --</option>
1268 <?php
1269 $lastgroup = '';
1270 foreach ($layouts as $key => $value) {
1271 if ($value[0] != $lastgroup) {
1272 if ($lastgroup) {
1273 echo " </optgroup>\n";
1275 echo " <optgroup label='" . attr($value[0]) . "'>\n";
1276 $lastgroup = $value[0];
1278 echo " <option value='" . attr($key) . "'";
1279 if ($key == $layout_id) {
1280 echo " selected";
1282 echo ">" . text($value[1]) . "</option>\n";
1284 if ($lastgroup) {
1285 echo " </optgroup>\n";
1288 </select>
1290 <?php if ($layout_id) { ?>
1291 <input type='button' value='<?php echo xla('Layout Properties'); ?>' onclick='edit_layout_props("")' />&nbsp;
1292 <input type='button' class='addgroup' id='addgroup' value='<?php echo xla('Add Group'); ?>' />
1293 <span style="font-size:90%"> &nbsp;
1294 <input type='button' class="btn btn-danger" name='save' id='save' value='<?php xl('Save Changes', 'e'); ?>' /></span> &nbsp;&nbsp;
1295 <?php xl('With selected:', 'e');?>
1296 <input type='button' name='deletefields' id='deletefields' value='<?php xl('Delete', 'e'); ?>' style="font-size:90%" disabled="disabled" />
1297 <input type='button' name='movefields' id='movefields' value='<?php xl('Move to...', 'e'); ?>' style="font-size:90%" disabled="disabled" />
1298 <input type='button' value='<?php echo xla('Tips'); ?>' onclick='$("#tips").toggle();' />&nbsp;
1299 <input type='button' value='<?php echo xla('Encounter Preview'); ?>' onclick='layoutLook();' />
1301 <?php } else { ?>
1302 <input type='button' value='<?php echo xla('New Layout'); ?>' onclick='edit_layout_props("")' />&nbsp;
1303 <?php } ?>
1305 <div id="tips" class="container tips"><section class="panel panel-primary">
1306 <header class="panel-heading">
1307 <h3 class="panel-title"><?php echo xlt('Usage Tips') ?></h3>
1308 </header>
1309 <div class="panel-body">
1310 <ul>
1311 <?php
1312 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>";
1313 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>";
1314 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>";
1315 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>";
1316 echo "<li>" . xlt("If a field's Data Col = 0 the data field will immediately follow its label field on the same line") . "</li>";
1317 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>";
1318 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>";
1319 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>";
1320 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>";
1321 //echo "<li>" . xlt("") . "</li>";
1322 echo "<li>" . xlt("Please see http://www.open-emr.org/wiki/index.php/LBV_Forms for more on this topic") . "</li>";
1324 </ul>
1325 <button class='btn btn-xs btn-success pull-right' onclick='$("#tips").toggle();return false;'><?php echo xlt('Dismiss')?></button>
1326 </div>
1327 </section></div></div>
1328 <?php
1329 // Load array of properties for this layout and its groups.
1330 $grparr = array();
1331 $gres = sqlStatement("SELECT * FROM layout_group_properties WHERE grp_form_id = ? " .
1332 "ORDER BY grp_group_id", array($layout_id));
1333 while ($grow = sqlFetchArray($gres)) {
1334 $grparr[$grow['grp_group_id']] = $grow;
1337 $prevgroup = "!@#asdf1234"; // an unlikely group ID
1338 $firstgroup = true; // flag indicates it's the first group to be displayed
1340 while ($row = sqlFetchArray($res)) {
1341 $group_id = $row['group_id'];
1342 if ($group_id != $prevgroup) {
1343 if ($firstgroup == false) {
1344 echo "</tbody></table></div>\n";
1345 echo "<div id='" . $group_id . "' class='group'>";
1346 } else { // making first group flag useful for maintaining top fixed nav bar.
1347 echo "<div id='" . $group_id . "' class='group' style='padding-top:40px'>";
1349 echo "<div class='text bold layouts_title' style='position:relative; background-color: #c9dbf2;'>";
1351 // Get the fully qualified descriptive name of this group (i.e. including ancestor names).
1352 $gdispname = '';
1353 for ($i = 1; $i <= strlen($group_id); ++$i) {
1354 if ($gdispname) {
1355 $gdispname .= ' / ';
1357 $gdispname .= $grparr[substr($group_id, 0, $i)]['grp_title'];
1359 $gmyname = $grparr[$group_id]['grp_title'];
1361 echo text($gdispname);
1363 // if not english and set to translate layout labels, then show the translation of group name
1364 if ($GLOBALS['translate_layout'] && $_SESSION['language_choice'] > 1) {
1365 echo "<span class='translation'&gt;&gt;&gt;&nbsp; " . xlt($gdispname) . "</span>";
1366 echo "&nbsp; ";
1369 echo "&nbsp; ";
1370 echo " <input type='button' class='addfield' id='addto~$group_id' value='" . xla('Add Field') . "'/>";
1371 echo "&nbsp; &nbsp; ";
1372 echo " <input type='button' class='renamegroup' id='$group_id~$gmyname' value='" . xla('Rename Group') . "'/>";
1373 /******************************************************************
1374 echo "&nbsp; &nbsp; ";
1375 echo " <input type='button' class='deletegroup' id='$group_id' value='" . xl('Delete Group') . "'/>";
1376 ******************************************************************/
1377 echo "&nbsp; &nbsp; ";
1378 echo " <input type='button' class='movegroup' id='$group_id~up' value='" . xl('Move Up') . "'/>";
1379 echo "&nbsp; &nbsp; ";
1380 echo " <input type='button' class='movegroup' id='$group_id~down' value='" . xl('Move Down') . "'/>";
1381 echo "&nbsp; &nbsp; ";
1382 echo "<input type='button' value='" . xla('Group Properties') . "' onclick='edit_layout_props(\"$group_id\")' />";
1383 echo "</div>";
1384 $firstgroup = false;
1386 <table class='table table-condensed table-striped'>
1387 <thead>
1388 <tr class='head'>
1389 <th style='width:1%'><?php xl('Order', 'e'); ?></th>
1390 <th <?php echo " $lbfonly"; ?>style='width:5%'><?php xl('Source', 'e'); ?></th>
1391 <th style='width:5%'><?php xl('ID', 'e'); ?>&nbsp;<span class="help" title=<?php xl('A unique value to identify this field, not visible to the user', 'e', '\'', '\''); ?> >(?)</span></th>
1392 <th style='width:10%'><?php xl('Label', 'e'); ?>&nbsp;<span class="help" title=<?php xl('The label that appears to the user on the form', 'e', '\'', '\''); ?> >(?)</span></th>
1393 <?php // if not english and showing layout label translations, then show translation header for title
1394 if ($GLOBALS['translate_layout'] && $_SESSION['language_choice'] > 1) {
1395 echo "<th>" . xl('Translation')."<span class='help' title='" . xl('The translated label that will appear on the form in current language') . "'>&nbsp;(?)</span></th>";
1396 } ?>
1397 <th style='width:6%'><?php xl('UOR', 'e'); ?></th>
1398 <th style='width:10%'><?php xl('Data Type', 'e'); ?></th>
1399 <th style='width:1%'><?php xl('Size', 'e'); ?></th>
1400 <th style='width:3%'><?php xl('Max Size', 'e'); ?></th>
1401 <th style='width:10%'><?php xl('List', 'e'); ?></th>
1402 <th style='width:10%'><?php xl('Backup List', 'e'); ?></th>
1403 <th style='width:1%'><?php xl('Label Cols', 'e'); ?></th>
1404 <th style='width:1%'><?php xl('Data Cols', 'e'); ?></th>
1405 <th style='width:10%'><?php xl('Options', 'e'); ?></th>
1406 <th style='width:20%'><?php xl('Description', 'e'); ?></th>
1407 <?php // if not english and showing layout label translations, then show translation header for description
1408 if ($GLOBALS['translate_layout'] && $_SESSION['language_choice'] > 1) {
1409 echo "<th>" . xl('Translation')."<span class='help' title='" . xl('The translation of description in current language')."'>&nbsp;(?)</span></th>";
1410 } ?>
1411 <th style='width:1%'><?php echo xlt('?'); ?></th>
1412 </tr>
1413 </thead>
1414 <tbody>
1416 <?php
1417 } // end if-group_name
1419 writeFieldLine($row);
1420 $prevgroup = $group_id;
1421 } // end while loop
1424 </tbody>
1425 </table>
1427 <?php echo $extra_html; ?>
1429 </form>
1431 <!-- template DIV that appears when user chooses to rename an existing group -->
1432 <div id="renamegroupdetail"
1433 style="border: 1px solid black; padding: 3px; display: none; visibility: hidden; background-color: lightgrey;">
1434 <input type="hidden" name="renameoldgroupname" id="renameoldgroupname" value="" />
1435 <?php echo xlt('Group Name'); ?>:
1436 <input type="text" size="20" maxlength="30" name="renamegroupname" id="renamegroupname" />
1437 &nbsp;&nbsp;
1438 <?php echo xlt('Parent'); ?>:
1439 <?php echo genGroupSelector('renamegroupparent', $layout_id); ?>
1440 <br>
1441 <input type="button" class="saverenamegroup .btn-save" value="<?php echo xla('Rename Group'); ?>" />
1442 <input type="button" class="cancelrenamegroup" value="<?php echo xla('Cancel'); ?>" />
1443 </div>
1445 <!-- template DIV that appears when user chooses to add a new group -->
1446 <div id="groupdetail"
1447 style="border: 1px solid black; padding: 3px; display: none; visibility: hidden; background-color: lightgrey;">
1448 <span class='bold'>
1449 <?php echo xlt('Group Name'); ?>:
1450 <input type="text" size="20" maxlength="30" name="newgroupname" id="newgroupname" />
1451 &nbsp;&nbsp;
1452 <?php echo xlt('Parent'); ?>:
1453 <?php echo genGroupSelector('newgroupparent', $layout_id); ?>
1454 <br>
1455 <table class='table table-condensed table-striped' style="border-collapse: collapse; margin-top: 5px;">
1456 <thead>
1457 <tr class='head'>
1458 <th style='width:1%'><?php xl('Order', 'e'); ?></th>
1459 <th <?php echo " $lbfonly"; ?>style='width:5%'><?php xl('Source', 'e'); ?></th>
1460 <th style='width:5%'><?php xl('ID', 'e'); ?>&nbsp;<span class="help" title=<?php xl('A unique value to identify this field, not visible to the user', 'e', '\'', '\''); ?> >(?)</span></th>
1461 <th style='width:10%'><?php xl('Label', 'e'); ?>&nbsp;<span class="help" title=<?php xl('The label that appears to the user on the form', 'e', '\'', '\''); ?> >(?)</span></th>
1462 <th style='width:6%'><?php xl('UOR', 'e'); ?></th>
1463 <th style='width:10%'><?php xl('Data Type', 'e'); ?></th>
1464 <th style='width:1%'><?php xl('Size', 'e'); ?></th>
1465 <th style='width:1%'><?php xl('Max Size', 'e'); ?></th>
1466 <th style='width:10%'><?php xl('List', 'e'); ?></th>
1467 <th style='width:10%'><?php xl('Backup List', 'e'); ?></th>
1468 <th style='width:1%'><?php xl('Label Cols', 'e'); ?></th>
1469 <th style='width:1%'><?php xl('Data Cols', 'e'); ?></th>
1470 <th style='width:10%'><?php xl('Options', 'e'); ?></th>
1471 <th style='width:20%'><?php xl('Description', 'e'); ?></th>
1472 </tr>
1473 </thead>
1474 <tbody>
1475 <tr class='center'>
1476 <td ><input type="text" name="gnewseq" id="gnewseq" value="" size="2" maxlength="4"> </td>
1477 <td<?php echo " $lbfonly"; ?>>
1478 <select class='form-control' name='gnewsource' id='gnewsource'>
1479 <?php
1480 foreach ($sources as $key => $value) {
1481 echo "<option value='" . attr($key) . "'>" . text($value) . "</option>\n";
1484 </select>
1485 </td>
1486 <td><input type="text" name="gnewid" id="gnewid" value="" size="10" maxlength="20"
1487 onclick='FieldIDClicked(this)'> </td>
1488 <td><input type="text" name="gnewtitle" id="gnewtitle" value="" size="20" maxlength="63"> </td>
1489 <td>
1490 <select class='form-control' name="gnewuor" id="gnewuor">
1491 <option value="0"><?php xl('Unused', 'e'); ?></option>
1492 <option value="1" selected><?php xl('Optional', 'e'); ?></option>
1493 <option value="2"><?php xl('Required', 'e'); ?></option>
1494 </select>
1495 </td>
1496 <td align='center'>
1497 <select class='form-control' name='gnewdatatype' id='gnewdatatype'>
1498 <option value=''></option>
1499 <?php
1500 global $datatypes;
1501 foreach ($datatypes as $key => $value) {
1502 echo "<option value='$key'>$value</option>";
1505 </select>
1506 </td>
1507 <td><input type="text" name="gnewlengthWidth" id="gnewlengthWidth" value="" size="1" maxlength="3" title="<?php echo xla('Width'); ?>">
1508 <input type="text" name="gnewlengthHeight" id="gnewlengthHeight" value="" size="1" maxlength="3" title="<?php echo xla('Height'); ?>"></td>
1509 <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>
1510 <td><input type="text" name="gnewlistid" id="gnewlistid" value="" size="8" maxlength="100" class="listid">
1511 <select class='form-control' name='gcontextName' id='gcontextName' style='display:none'>
1512 <?php
1513 $res = sqlStatement("SELECT * FROM customlists WHERE cl_list_type=2 AND cl_deleted=0");
1514 while ($row = sqlFetchArray($res)) {
1515 echo "<option value='".htmlspecialchars($row['cl_list_item_long'], ENT_QUOTES)."'>".htmlspecialchars($row['cl_list_item_long'], ENT_QUOTES)."</option>";
1518 </select>
1519 </td>
1520 <td><input type="text" name="gnewbackuplistid" id="gnewbackuplistid" value="" size="8" maxlength="100" class="listid"></td>
1521 <td><input type="text" name="gnewtitlecols" id="gnewtitlecols" value="" size="3" maxlength="3"> </td>
1522 <td><input type="text" name="gnewdatacols" id="gnewdatacols" value="" size="3" maxlength="3"> </td>
1523 <td><select name="gnewedit_options[]" id="gnewedit_options" class="typeAddons" multiple style='width:100%' value="" size="3"></select>
1524 <input type="hidden" name="gnewdefault" id="gnewdefault" value="" /> </td>
1525 <td><input type="text" name="gnewdesc" id="gnewdesc" value="" size="30"> </td>
1526 </tr>
1527 </tbody>
1528 </table>
1529 <br>
1530 <input type="button" class="savenewgroup" value=<?php xl('Save New Group', 'e', '\'', '\''); ?>>
1531 <input type="button" class="cancelnewgroup" value=<?php xl('Cancel', 'e', '\'', '\''); ?>>
1532 </span>
1533 </div>
1535 <!-- template DIV that appears when user chooses to add a new field to a group -->
1536 <div id="fielddetail" class="fielddetail" style="display: none; visibility: hidden">
1537 <input type="hidden" name="newfieldgroupid" id="newfieldgroupid" value="">
1538 <table class="table table-condensed" style="border-collapse: collapse;">
1539 <thead>
1540 <tr class='head'>
1541 <th style='width:1%'><?php xl('Order', 'e'); ?></th>
1542 <th <?php echo " $lbfonly"; ?>style='width:5%'><?php xl('Source', 'e'); ?></th>
1543 <th style='width:5%'><?php xl('ID', 'e'); ?>&nbsp;<span class="help" title=<?php xl('A unique value to identify this field, not visible to the user', 'e', '\'', '\''); ?> >(?)</span></th>
1544 <th style='width:10%'><?php xl('Label', 'e'); ?>&nbsp;<span class="help" title=<?php xl('The label that appears to the user on the form', 'e', '\'', '\''); ?> >(?)</span></th>
1545 <th style='width:6%'><?php xl('UOR', 'e'); ?></th>
1546 <th style='width:10%'><?php xl('Data Type', 'e'); ?></th>
1547 <th style='width:1%'><?php xl('Size', 'e'); ?></th>
1548 <th style='width:1%'><?php xl('Max Size', 'e'); ?></th>
1549 <th style='width:10%'><?php xl('List', 'e'); ?></th>
1550 <th style='width:10%'><?php xl('Backup List', 'e'); ?></th>
1551 <th style='width:1%'><?php xl('Label Cols', 'e'); ?></th>
1552 <th style='width:1%'><?php xl('Data Cols', 'e'); ?></th>
1553 <th style='width:10%'><?php xl('Options', 'e'); ?></th>
1554 <th style='width:20%'><?php xl('Description', 'e'); ?></th>
1555 </tr>
1556 </thead>
1557 <tbody>
1558 <tr class='center'>
1559 <td ><input type="text" name="newseq" id="newseq" value="" size="2" maxlength="4"> </td>
1560 <td<?php echo " $lbfonly"; ?>>
1561 <select class='form-control' name='newsource' id='newsource'>
1562 <?php
1563 foreach ($sources as $key => $value) {
1564 echo " <option value='" . attr($key) . "'>" . text($value) . "</option>\n";
1567 </select>
1568 </td>
1569 <td ><input type="text" name="newid" id="newid" value="" size="10" maxlength="20"
1570 onclick='FieldIDClicked(this)'> </td>
1571 <td><input type="text" name="newtitle" id="newtitle" value="" size="20" maxlength="63"> </td>
1572 <td>
1573 <select class='form-control' name="newuor" id="newuor">
1574 <option value="0"><?php xl('Unused', 'e'); ?></option>
1575 <option value="1" selected><?php xl('Optional', 'e'); ?></option>
1576 <option value="2"><?php xl('Required', 'e'); ?></option>
1577 </select>
1578 </td>
1579 <td align='center'>
1580 <select class='form-control' name='newdatatype' id='newdatatype'>
1581 <option value=''></option>
1582 <?php
1583 global $datatypes;
1584 foreach ($datatypes as $key => $value) {
1585 echo " <option value='$key'>$value</option>\n";
1588 </select>
1589 </td>
1590 <td><input type="text" name="newlengthWidth" id="newlengthWidth" value="" size="1" maxlength="3" title="<?php echo xla('Width'); ?>">
1591 <input type="text" name="newlengthHeight" id="newlengthHeight" value="" size="1" maxlength="3" title="<?php echo xla('Height'); ?>"></td>
1592 <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>
1593 <td><input type="text" name="newlistid" id="newlistid" value="" size="8" maxlength="31" class="listid">
1594 <select class='form-control' name='contextName' id='contextName' style='display:none'>
1595 <?php
1596 $res = sqlStatement("SELECT * FROM customlists WHERE cl_list_type=2 AND cl_deleted=0");
1597 while ($row = sqlFetchArray($res)) {
1598 echo "<option value='".htmlspecialchars($row['cl_list_item_long'], ENT_QUOTES)."'>".htmlspecialchars($row['cl_list_item_long'], ENT_QUOTES)."</option>";
1601 </select>
1602 </td>
1603 <td><input type="text" name="newbackuplistid" id="newbackuplistid" value="" size="8" maxlength="31" class="listid"></td>
1604 <td><input type="text" name="newtitlecols" id="newtitlecols" value="" size="3" maxlength="3"> </td>
1605 <td><input type="text" name="newdatacols" id="newdatacols" value="" size="3" maxlength="3"> </td>
1606 <td><select name="newedit_options[]" id="newedit_options" multiple class='typeAddons' style='width:100%'></select>
1607 <input type="hidden" name="newdefault" id="newdefault" value="" /> </td>
1608 <td><input type="text" name="newdesc" id="newdesc" value="" size="30"> </td>
1609 </tr>
1610 <tr>
1611 <td colspan="9">
1612 <input type="button" class="savenewfield" value=<?php xl('Save New Field', 'e', '\'', '\''); ?>>
1613 <input type="button" class="cancelnewfield" value=<?php xl('Cancel', 'e', '\'', '\''); ?>>
1614 </td>
1615 </tr>
1616 </tbody>
1617 </table>
1618 </div>
1619 </div>
1620 </body>
1622 <script>
1623 /* Field modifier objects - heading towards context based.
1624 Used by Select2 so rtl may be enabled*/
1625 <?php echo "var fldOptions = [
1626 {id: 'A',text:'" . xla('Age') . "',ctx:['4'],ctxExcp:['0']},
1627 {id: 'B',text:'" . xla('Gestational Age') . "',ctx:['4'],ctxExcp:['0']},
1628 {id: 'F',text:'" . xla('Add Time to Date') . "',ctx:['4'],ctxExcp:['0']},
1629 {id: 'C',text:'" . xla('Capitalize') . "',ctx:['0'],ctxExcp:['4','15','40']},
1630 {id: 'D',text:'" . xla('Dup Check') . "'},
1631 {id: 'E',text:'" . xla('Dup Check on only Edit') . "'},
1632 {id: 'W',text:'" . xla('Dup Check on only New') . "'},
1633 {id: 'G',text:'" . xla('Graphable') . "'},
1634 {id: 'I',text:'" . xla('Initially Open Group') . "'},
1635 {id: 'L',text:'" . xla('Lab Order') . "'},
1636 {id: 'N',text:'" . xla('New Patient Form') . "'},
1637 {id: 'O',text:'" . xla('Order Processor') . "'},
1638 {id: 'P',text:'" . xla('Default to previous value') . "'},
1639 {id: 'R',text:'" . xla('Distributor') . "'},
1640 {id: 'T',text:'" . xla('Description is default text') . "'},
1641 {id: 'U',text:'" . xla('Capitalize all') . "'},
1642 {id: 'V',text:'" . xla('Vendor') . "'},
1643 {id: 'X',text:'" . xla('Do Not Print') . "'},
1644 {id:'grp',text:'" . xla('Stylings') . "',children:[
1645 {id: 'RS',text:'" . xla('Add Bottom Border Row') . "'},
1646 {id: 'RO',text:'" . xla('Outline Entire Row') . "'},
1647 {id: 'DS',text:'" . xla('Add Data Bottom Border') . "'},
1648 {id: 'DO',text:'" . xla('Outline Data Col') . "'},
1649 {id: 'SP',text:'" . xla('Span Entire Row') . "'}
1651 {id: '0',text:'" . xla('Read Only') . "'},
1652 {id: '1',text:'" . xla('Write Once') . "'},
1653 {id: '2',text:'" . xla('Billing Code Descriptions') . "'}];\n";
1655 // Language direction for select2
1656 echo 'var langDirection = "' . $_SESSION['language_direction'] . '";';
1659 // used when selecting a list-name for a field
1660 var selectedfield;
1662 // Support for beforeunload handler.
1663 var somethingChanged = false;
1665 // Get the next logical sequence number for a field in the specified group.
1666 // Note it guesses and uses the existing increment value.
1667 function getNextSeq(group) {
1668 var f = document.forms[0];
1669 var seq = 0;
1670 var delta = 10;
1671 for (var i = 1; true; ++i) {
1672 var gelem = f['fld[' + i + '][group]'];
1673 if (!gelem) break;
1674 if (gelem.value != group) continue;
1675 var tmp = parseInt(f['fld[' + i + '][seq]'].value);
1676 if (isNaN(tmp)) continue;
1677 if (tmp <= seq) continue;
1678 delta = tmp - seq;
1679 seq = tmp;
1681 return seq + delta;
1684 // jQuery stuff to make the page a little easier to use
1686 $(document).ready(function(){
1688 $(function () {
1689 $('.typeAddons').select2({
1690 data: fldOptions,
1691 theme: 'default',
1692 multiple: true,
1693 closeOnSelect: false,
1694 width:'100%',
1695 minimumResultsForSearch: 'Infinity',
1696 containerCssClass: ':all:',
1697 allowClear: false,
1698 <?php require($GLOBALS['srcdir'] . '/js/xl/select2.js.php'); ?>
1701 // Populate field option selects
1702 $(function() {
1703 $('.typeAddons').each(function(i, obj) {
1704 var v = $(this).data('set')
1705 if(typeof v !== 'undefined' && v > ""){
1706 $(this).val(v).trigger("change")
1709 somethingChanged = false;
1712 $("#save").click(function() { SaveChanges(); });
1713 $("#layout_id").change(function() {
1714 if (!myChangeCheck()) {
1715 $("#layout_id").val("<?php echo $layout_id; ?>");
1716 return;
1718 mySubmit();
1720 $(".addgroup").click(function() { AddGroup(this); });
1721 $(".savenewgroup").click(function() { SaveNewGroup(this); });
1722 /******************************************************************
1723 $(".deletegroup").click(function() { DeleteGroup(this); });
1724 ******************************************************************/
1725 $(".cancelnewgroup").click(function() { CancelNewGroup(this); });
1726 $(".movegroup").click(function() { MoveGroup(this); });
1727 $(".renamegroup").click(function() { RenameGroup(this); });
1728 $(".saverenamegroup").click(function() { SaveRenameGroup(this); });
1729 $(".cancelrenamegroup").click(function() { CancelRenameGroup(this); });
1730 $(".addfield").click(function() { AddField(this); });
1731 $("#deletefields").click(function() { DeleteFields(this); });
1732 $(".selectfield").click(function() {
1733 var TRparent = $(this).parent().parent();
1734 $(TRparent).children("td").toggleClass("highlight");
1735 // disable the delete-move buttons
1736 $("#deletefields").attr("disabled", "disabled");
1737 $("#movefields").attr("disabled", "disabled");
1738 $(".selectfield").each(function(i) {
1739 // if any field is selected, enable the delete-move buttons
1740 if ($(this).prop("checked") == true) {
1741 $("#deletefields").removeAttr("disabled");
1742 $("#movefields").removeAttr("disabled");
1747 $("#movefields").click(function() { ShowGroups(this); });
1748 $(".savenewfield").click(function() { SaveNewField(this); });
1749 $(".cancelnewfield").click(function() { CancelNewField(this); });
1750 $("#newtitle").blur(function() { if ($("#newid").val() == "") $("#newid").val($("#newtitle").val()); });
1751 $("#newdatatype").change(function() { ChangeList(this.value);});
1752 $("#gnewdatatype").change(function() { ChangeListg(this.value);});
1753 $(".listid").click(function() { ShowLists(this); });
1755 // special class that skips the element
1756 $(".noselect").focus(function() { $(this).blur(); });
1758 // Save the changes made to the form
1759 var SaveChanges = function () {
1760 var f = document.forms[0];
1761 for (var i = 1; f['fld['+i+'][id]']; ++i) {
1762 var ival = f['fld['+i+'][id]'].value;
1763 for (var j = i + 1; f['fld['+j+'][id]']; ++j) {
1764 if (ival == f['fld['+j+'][id]'].value || ival == f['fld['+j+'][originalid]'].value) {
1765 alert('<?php echo xls('Error: Duplicated field ID'); ?>: ' + ival);
1766 return;
1770 $("#formaction").val("save");
1771 mySubmit();
1774 /****************************************************/
1775 /************ Group functions ***********************/
1776 /****************************************************/
1778 // display the 'new group' DIV
1779 var AddGroup = function(btnObj) {
1780 if (!myChangeCheck()) return;
1781 $("#save").attr("disabled", true);
1782 // show the field details DIV
1783 $('#groupdetail').css('visibility', 'visible');
1784 $('#groupdetail').css('display', 'block');
1785 $('#groupdetail').css('margin-top', '85px');
1786 $(btnObj).parent().after($("#groupdetail"));
1787 $("html, body").animate({ scrollTop: 0 }, "slow");
1788 $('#groupdetail > #newgroupname').focus();
1789 // Assign a sensible default sequence number.
1790 $('#gnewseq').val(10);
1793 // save the new group to the form
1794 var SaveNewGroup = function(btnObj) {
1795 // the group name field can only have letters, numbers, spaces and underscores
1796 // AND it cannot start with a number
1797 if ($("#newgroupname").val() == "") {
1798 alert("<?php xl('Group names cannot be blank', 'e'); ?>");
1799 return false;
1801 if ($("#newgroupname").val().match(/^(\d+|\s+)/)) {
1802 alert("<?php xl('Group names cannot start with numbers or spaces.', 'e'); ?>");
1803 return false;
1805 var validname = $("#newgroupname").val().replace(/[^A-za-z0-9 ]/g, "_"); // match any non-word characters and replace them
1806 $("#newgroupname").val(validname);
1808 // now, check the first group field values
1810 // seq must be numeric and <= 9999
1811 if (! IsNumeric($("#gnewseq").val(), 0, 9999)) {
1812 alert("<?php xl('Order must be a number between 1 and 9999', 'e'); ?>");
1813 return false;
1815 // length must be numeric and less than 999
1816 if (! IsNumeric($("#gnewlengthWidth").val(), 0, 999)) {
1817 alert("<?php xl('Size must be a number between 1 and 999', 'e'); ?>");
1818 return false;
1820 // titlecols must be numeric and less than 100
1821 if (! IsNumeric($("#gnewtitlecols").val(), 0, 999)) {
1822 alert("<?php xl('LabelCols must be a number between 1 and 999', 'e'); ?>");
1823 return false;
1825 // datacols must be numeric and less than 100
1826 if (! IsNumeric($("#gnewdatacols").val(), 0, 999)) {
1827 alert("<?php xl('DataCols must be a number between 1 and 999', 'e'); ?>");
1828 return false;
1830 // the id field can only have letters, numbers and underscores
1831 if ($("#gnewid").val() == "") {
1832 alert("<?php xl('ID cannot be blank', 'e'); ?>");
1833 return false;
1835 var validid = $("#gnewid").val().replace(/(\s|\W)/g, "_"); // match any non-word characters and replace them
1836 $("#gnewid").val(validid);
1837 // similarly with the listid field
1838 validid = $("#gnewlistid").val().replace(/(\s|\W)/g, "_");
1839 $("#gnewlistid").val(validid);
1840 // similarly with the backuplistid field
1841 validid = $("#gnewbackuplistid").val().replace(/(\s|\W)/g, "_");
1842 $("#gnewbackuplistid").val(validid);
1845 // submit the form to add a new field to a specific group
1846 $("#formaction").val("addgroup");
1847 mySubmit();
1850 /******************************************************************
1851 // actually delete an entire group from the database
1852 var DeleteGroup = function(btnObj) {
1853 var parts = $(btnObj).attr("id");
1854 var groupname = parts.replace(/^\d+/, "");
1855 if (confirm("<?php xl('WARNING', 'e', '', ' - ') . xl('This action cannot be undone.', 'e', '', '\n') . xl('Are you sure you wish to delete the entire group named', 'e', '', ' '); ?>'"+groupname+"'?")) {
1856 // submit the form to add a new field to a specific group
1857 $("#formaction").val("deletegroup");
1858 $("#deletegroupname").val(parts);
1859 $("#theform").submit();
1862 ******************************************************************/
1864 // just hide the new field DIV
1865 var CancelNewGroup = function(btnObj) {
1866 // hide the field details DIV
1867 $('#groupdetail').css('visibility', 'hidden');
1868 $('#groupdetail').css('display', 'none');
1869 // reset the new group values to a default
1870 $('#groupdetail > #newgroupname').val("");
1871 $('#groupdetail > #newgroupparent').val("");
1872 $("#save").attr("disabled", false);
1875 // display the 'new field' DIV
1876 var MoveGroup = function(btnObj) {
1877 if (!myChangeCheck()) return;
1878 var btnid = $(btnObj).attr("id");
1879 var parts = btnid.split("~");
1880 var groupid = parts[0];
1881 var direction = parts[1];
1882 // submit the form to change group order
1883 $("#formaction").val("movegroup");
1884 $("#movegroupname").val(groupid);
1885 $("#movedirection").val(direction);
1886 mySubmit();
1889 // show the rename group DIV
1890 var RenameGroup = function(btnObj) {
1891 if (!myChangeCheck()) return;
1892 $("#save").attr("disabled", true);
1893 $('#renamegroupdetail').css('visibility', 'visible');
1894 $('#renamegroupdetail').css('display', 'block');
1895 $(btnObj).parent().append($("#renamegroupdetail"));
1896 var parts = $(btnObj).attr("id").split("~");
1897 $('#renameoldgroupname').val(parts[0]); // this is actually the existing group ID
1898 $('#renamegroupname').val(parts[1]); // the textual name of just this group
1899 var i = parts[0].length;
1900 $('[name=renamegroupparent]').val(i > 0 ? parts[0].substr(0, i-1) : ''); // parent ID
1903 // save the new group to the form
1904 var SaveRenameGroup = function(btnObj) {
1905 // the group name field can only have letters, numbers, spaces and underscores
1906 // AND it cannot start with a number
1907 if ($("#renamegroupname").val().match(/^\d+/)) {
1908 alert("<?php xl('Group names cannot start with numbers.', 'e'); ?>");
1909 return false;
1911 var validname = $("#renamegroupname").val().replace(/[^A-za-z0-9 ]/g, "_"); // match any non-word characters and replace them
1912 $("#renamegroupname").val(validname);
1914 // submit the form to add a new field to a specific group
1915 $("#formaction").val("renamegroup");
1916 mySubmit();
1919 // just hide the new field DIV
1920 var CancelRenameGroup = function(btnObj) {
1921 // hide the field details DIV
1922 $('#renamegroupdetail').css('visibility', 'hidden');
1923 $('#renamegroupdetail').css('display', 'none');
1924 // reset the rename group values to a default
1925 $('#renameoldgroupname').val("");
1926 $('#renamegroupname').val("");
1927 $('#renamegroupparent').val("");
1930 /****************************************************/
1931 /************ Field functions ***********************/
1932 /****************************************************/
1934 // display the 'new field' DIV
1935 var AddField = function(btnObj) {
1936 if (!myChangeCheck()) return;
1937 $("#save").attr("disabled", true);
1938 // update the fieldgroup value to be the groupid
1939 var btnid = $(btnObj).attr("id");
1940 var parts = btnid.split("~");
1941 var groupid = parts[1];
1942 $('#fielddetail > #newfieldgroupid').attr('value', groupid);
1943 // show the field details DIV
1944 $('#fielddetail').css('visibility', 'visible');
1945 $('#fielddetail').css('display', 'block');
1946 $(btnObj).parent().append($("#fielddetail"));
1947 // Assign a sensible default sequence number.
1948 $('#newseq').val(getNextSeq(groupid));
1951 var DeleteFields = function(btnObj) {
1952 if (!myChangeCheck()) return;
1953 if (confirm("<?php xl('WARNING', 'e', '', ' - ') . xl('This action cannot be undone.', 'e', '', '\n') . xl('Are you sure you wish to delete the selected fields?', 'e'); ?>")) {
1954 var delim = "";
1955 $(".selectfield").each(function(i) {
1956 // build a list of selected field names to be moved
1957 if ($(this).prop("checked") == true) {
1958 var parts = this.id.split("~");
1959 var currval = $("#selectedfields").val();
1960 $("#selectedfields").val(currval+delim+parts[1]);
1961 delim = " ";
1964 // submit the form to delete the field(s)
1965 $("#formaction").val("deletefields");
1966 mySubmit();
1970 // save the new field to the form
1971 var SaveNewField = function(btnObj) {
1972 // check the new field values for correct formatting
1974 // seq must be numeric and <= 9999
1975 if (! IsNumeric($("#newseq").val(), 0, 9999)) {
1976 alert("<?php xl('Order must be a number between 1 and 9999', 'e'); ?>");
1977 return false;
1979 // length must be numeric and less than 999
1980 if (! IsNumeric($("#newlengthWidth").val(), 0, 999)) {
1981 alert("<?php xl('Size must be a number between 1 and 999', 'e'); ?>");
1982 return false;
1984 // titlecols must be numeric and less than 100
1985 if (! IsNumeric($("#newtitlecols").val(), 0, 999)) {
1986 alert("<?php xl('LabelCols must be a number between 1 and 999', 'e'); ?>");
1987 return false;
1989 // datacols must be numeric and less than 100
1990 if (! IsNumeric($("#newdatacols").val(), 0, 999)) {
1991 alert("<?php xl('DataCols must be a number between 1 and 999', 'e'); ?>");
1992 return false;
1994 // the id field can only have letters, numbers and underscores
1995 var validid = $("#newid").val().replace(/(\s|\W)/g, "_"); // match any non-word characters and replace them
1996 $("#newid").val(validid);
1997 // similarly with the listid field
1998 validid = $("#newlistid").val().replace(/(\s|\W)/g, "_");
1999 $("#newlistid").val(validid);
2000 // similarly with the backuplistid field
2001 validid = $("#newbackuplistid").val().replace(/(\s|\W)/g, "_");
2002 $("#newbackuplistid").val(validid);
2004 // submit the form to add a new field to a specific group
2005 $("#formaction").val("addfield");
2006 mySubmit();
2009 // just hide the new field DIV
2010 var CancelNewField = function(btnObj) {
2011 // hide the field details DIV
2012 $('#fielddetail').css('visibility', 'hidden');
2013 $('#fielddetail').css('display', 'none');
2014 // reset the new field values to a default
2015 ResetNewFieldValues();
2016 $("#save").attr("disabled", false);
2019 // show the popup choice of lists
2020 var ShowLists = function(btnObj) {
2021 var title = "<?php echo xla('Select List');?>";
2022 dlgopen('../patient_file/encounter/find_code_dynamic.php?what=lists',"_blank", 850, 750, "", title);
2023 selectedfield = btnObj;
2026 // show the popup choice of groups
2027 var ShowGroups = function(btnObj) {
2028 if (!myChangeCheck()) return;
2029 var title = "<?php echo xlt('Select Group');?>";
2030 dlgopen('../patient_file/encounter/find_code_dynamic.php?what=groups&layout_id=<?php echo addslashes($layout_id); ?>',
2031 "_blank",850, 600,"", title);
2034 // Show context DD for NationNotes
2035 var ChangeList = function(btnObj){
2036 if(btnObj==34){
2037 $('#newlistid').hide();
2038 $('#contextName').show();
2040 else{
2041 $('#newlistid').show();
2042 $('#contextName').hide();
2045 var ChangeListg = function(btnObj){
2046 if(btnObj==34){
2047 $('#gnewlistid').hide();
2048 $('#gcontextName').show();
2050 else{
2051 $('#gnewlistid').show();
2052 $('#gcontextName').hide();
2056 // Initialize list item selectors and value field visibilities in skip conditions.
2057 var f = document.forms[0];
2058 for (var lino = 1; f['fld[' + lino + '][id]']; ++lino) {
2059 for (var seq = 0; f['fld[' + lino + '][condition_itemid][' + seq + ']']; ++seq) {
2060 setListItemOptions(lino, seq, true);
2062 actionChanged(lino);
2065 // Support for beforeunload handler.
2066 $('tbody input, tbody select, tbody textarea').not('.selectfield').change(function() {
2067 somethingChanged = true;
2069 window.addEventListener("beforeunload", function (e) {
2070 if (somethingChanged && !top.timed_out) {
2071 var msg = "<?php echo xls('You have unsaved changes.'); ?>";
2072 e.returnValue = msg; // Gecko, Trident, Chrome 34+
2073 return msg; // Gecko, WebKit, Chrome <34
2077 }); /* Ready Done */
2079 function layoutLook(){
2080 var form = "<?php echo attr($layout_id);?>";
2081 var btnName = "<?php echo xla('Back To Editor');?>";
2082 var url = "../patient_file/encounter/view_form.php?isShow&id=0&formname=" + form;
2083 var title = "<?php echo xlt('LBF Encounter Form Preview');?>";
2084 dlgopen(url, '_blank', 1250, 800, "", title);
2085 return false;
2088 function NationNotesContext(lineitem, val) {
2089 // Check if function is needed.
2090 if (!document.getElementById("fld[" + lineitem + "][contextName]") || !document.getElementById("fld[" + lineitem + "][list_id]")) {
2091 return false; // these elements don't exist yet so do nothing.
2093 if (val == 34) {
2094 document.getElementById("fld[" + lineitem + "][contextName]").style.display = '';
2095 document.getElementById("fld[" + lineitem + "][list_id]").style.display = 'none';
2096 document.getElementById("fld[" + lineitem + "][list_id]").value = '';
2098 else {
2099 document.getElementById("fld[" + lineitem + "][list_id]").style.display = '';
2100 document.getElementById("fld[" + lineitem + "][contextName]").style.display = 'none';
2101 document.getElementById("fld[" + lineitem + "][list_id]").value = '';
2105 function SetList(listid) {
2106 $(selectedfield).val(listid);
2109 //////////////////////////////////////////////////////////////////////
2110 // The following supports the field ID selection pop-up.
2111 //////////////////////////////////////////////////////////////////////
2113 var fieldselectfield;
2115 function elemFromPart(part) {
2116 var ename = fieldselectfield.name;
2117 // ename is like one of the following:
2118 // fld[$fld_line_no][id]
2119 // gnewid
2120 // newid
2121 // and "part" is what we substitute for the "id" part.
2122 var i = ename.lastIndexOf('id');
2123 ename = ename.substr(0, i) + part + ename.substr(i+2);
2124 return document.forms[0][ename];
2127 function FieldIDClicked(elem) {
2128 <?php if (substr($layout_id, 0, 3) == 'LBF') { ?>
2129 fieldselectfield = elem;
2130 var srcval = elemFromPart('source').value;
2131 // If the field ID is for the local form, allow direct entry.
2132 if (srcval == 'F') return;
2133 // Otherwise pop up the selection window.
2134 var title = "<?php echo xlt('Select Field');?>";
2135 dlgopen('../patient_file/encounter/find_code_dynamic.php?what=fields&source='
2136 + srcval, "_blank", 700, 600, "", title);
2137 <?php } ?>
2140 function SetField(field_id, title, data_type, uor, fld_length, max_length,
2141 list_id, titlecols, datacols, edit_options, description, fld_rows)
2143 fieldselectfield.value = field_id;
2144 elemFromPart('title' ).value = title;
2145 elemFromPart('datatype' ).value = data_type;
2146 elemFromPart('uor' ).value = uor;
2147 elemFromPart('lengthWidth' ).value = fld_length;
2148 elemFromPart('maxSize' ).value = max_length;
2149 elemFromPart('list_id' ).value = list_id;
2150 elemFromPart('titlecols' ).value = titlecols;
2151 elemFromPart('datacols' ).value = datacols;
2152 elemFromPart('edit_options').value = edit_options;
2153 elemFromPart('desc' ).value = description;
2154 elemFromPart('lengthHeight').value = fld_rows;
2157 //////////////////////////////////////////////////////////////////////
2158 // End code for field ID selection pop-up.
2159 //////////////////////////////////////////////////////////////////////
2161 /* this is called after the user chooses a new group from the popup window
2162 * it will submit the page so the selected fields can be moved into
2163 * the target group
2165 function MoveFields(targetgroup) {
2166 $("#targetgroup").val(targetgroup);
2167 var delim = "";
2168 $(".selectfield").each(function(i) {
2169 // build a list of selected field names to be moved
2170 if ($(this).prop("checked") == true) {
2171 var parts = this.id.split("~");
2172 var currval = $("#selectedfields").val();
2173 $("#selectedfields").val(currval+delim+parts[1]);
2174 delim = " ";
2177 $("#formaction").val("movefields");
2178 mySubmit();
2181 // set the new-field values to a default state
2182 function ResetNewFieldValues () {
2183 $("#newseq").val("");
2184 $("#newsource").val("");
2185 $("#newid").val("");
2186 $("#newtitle").val("");
2187 $("#newuor").val(1);
2188 $("#newlengthWidth").val("");
2189 $("#newlengthHeight").val("");
2190 $("#newmaxSize").val("");
2191 $("#newdatatype").val("");
2192 $("#newlistid").val("");
2193 $("#newbackuplistid").val("");
2194 $("#newtitlecols").val("");
2195 $("#newdatacols").val("");
2196 $("#newedit_options").val("");
2197 $("#newdefault").val("");
2198 $("#newdesc").val("");
2201 // is value an integer and between min and max
2202 function IsNumeric(value, min, max) {
2203 if (value == "" || value == null) return false;
2204 if (! IsN(value) ||
2205 parseInt(value) < min ||
2206 parseInt(value) > max)
2207 return false;
2209 return true;
2212 /****************************************************/
2213 /****************************************************/
2214 /****************************************************/
2216 // tell if num is an Integer
2217 function IsN(num) { return !/\D/.test(num); }
2219 </script>
2221 </html>