minor adjustments to prior commit
[openemr.git] / interface / super / edit_layout.php
blobfc746425000fd9dd92ecea0cbaea14db6234eda1
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 // Check authorization.
322 $thisauth = acl_check('admin', 'super');
323 if (!$thisauth) {
324 die(xl('Not authorized'));
327 // The layout ID identifies the layout to be edited.
328 $layout_id = empty($_REQUEST['layout_id']) ? '' : $_REQUEST['layout_id'];
330 // Tag style for stuff to hide if not an LBF layout. Currently just for the Source column.
331 $lbfonly = substr($layout_id, 0, 3) == 'LBF' ? "" : "style='display:none;'";
333 // Handle the Form actions
335 if ($_POST['formaction'] == "save" && $layout_id) {
336 // If we are saving, then save.
337 $fld = $_POST['fld'];
338 for ($lino = 1; isset($fld[$lino]['id']); ++$lino) {
339 $iter = $fld[$lino];
340 $field_id = formTrim($iter['id']);
341 $field_id_original = formTrim($iter['originalid']);
342 $data_type = formTrim($iter['datatype']);
343 $listval = $data_type == 34 ? formTrim($iter['contextName']) : formTrim($iter['list_id']);
344 $action = $iter['action'];
345 if ($action == 'value') {
346 $action = 'value=' . $iter['value'];
349 // Skip conditions for the line are stored as a serialized array.
350 $condarr = array('action' => $action);
351 $cix = 0;
352 for (; !empty($iter['condition_id'][$cix]); ++$cix) {
353 $andor = empty($iter['condition_andor'][$cix]) ? '' : $iter['condition_andor'][$cix];
354 $condarr[$cix] = array(
355 'id' => strip_escape_custom($iter['condition_id' ][$cix]),
356 'itemid' => strip_escape_custom($iter['condition_itemid' ][$cix]),
357 'operator' => strip_escape_custom($iter['condition_operator'][$cix]),
358 'value' => strip_escape_custom($iter['condition_value' ][$cix]),
359 'andor' => strip_escape_custom($andor),
362 $conditions = $cix ? serialize($condarr) : '';
364 if ($field_id) {
365 if ($field_id != $field_id_original) {
366 if (renameColumn($layout_id, $field_id_original, $field_id) > 0) {
367 // If column rename had an error then don't rename it here.
368 $field_id = $field_id_original;
371 sqlStatement("UPDATE layout_options SET " .
372 "field_id = '" . formDataCore($field_id) . "', " .
373 "source = '" . formTrim($iter['source']) . "', " .
374 "title = '" . formDataCore($iter['title']) . "', " .
375 "group_id = '" . formTrim($iter['group']) . "', " .
376 "seq = '" . formTrim($iter['seq']) . "', " .
377 "uor = '" . formTrim($iter['uor']) . "', " .
378 "fld_length = '" . formTrim($iter['lengthWidth']) . "', " .
379 "fld_rows = '" . formTrim($iter['lengthHeight']) . "', " .
380 "max_length = '" . formTrim($iter['maxSize']) . "', " .
381 "titlecols = '" . formTrim($iter['titlecols']) . "', " .
382 "datacols = '" . formTrim($iter['datacols']) . "', " .
383 "data_type= '$data_type', " .
384 "list_id= '" . $listval . "', " .
385 "list_backup_id= '" . formTrim($iter['list_backup_id']) . "', " .
386 "edit_options = '" . json_encode($iter['edit_options']) . "', " .
387 "default_value = '" . formTrim($iter['default']) . "', " .
388 "description = '" . formTrim($iter['desc']) . "', " .
389 "conditions = '" . add_escape_custom($conditions) . "', " .
390 "validation = '" . formTrim($iter['validation']) . "' " .
391 "WHERE form_id = '$layout_id' AND field_id = '$field_id_original'");
394 } else if ($_POST['formaction'] == "addfield" && $layout_id) {
395 // Add a new field to a specific group
396 $data_type = formTrim($_POST['newdatatype']);
397 $max_length = $data_type == 3 ? 3 : 255;
398 $listval = $data_type == 34 ? formTrim($_POST['contextName']) : formTrim($_POST['newlistid']);
399 sqlStatement("INSERT INTO layout_options (" .
400 " form_id, source, field_id, title, group_id, seq, uor, fld_length, fld_rows" .
401 ", titlecols, datacols, data_type, edit_options, default_value, description" .
402 ", max_length, list_id, list_backup_id " .
403 ") VALUES ( " .
404 "'" . formTrim($_POST['layout_id']) . "'" .
405 ",'" . formTrim($_POST['newsource']) . "'" .
406 ",'" . formTrim($_POST['newid']) . "'" .
407 ",'" . formDataCore($_POST['newtitle']) . "'" .
408 ",'" . formTrim($_POST['newfieldgroupid']) . "'" .
409 ",'" . formTrim($_POST['newseq']) . "'" .
410 ",'" . formTrim($_POST['newuor']) . "'" .
411 ",'" . formTrim($_POST['newlengthWidth']) . "'" .
412 ",'" . formTrim($_POST['newlengthHeight']) . "'" .
413 ",'" . formTrim($_POST['newtitlecols']) . "'" .
414 ",'" . formTrim($_POST['newdatacols']) . "'" .
415 ",'$data_type'" .
416 ",'" . json_encode($_POST['newedit_options']) . "'" .
417 ",'" . formTrim($_POST['newdefault']) . "'" .
418 ",'" . formTrim($_POST['newdesc']) . "'" .
419 ",'" . formTrim($_POST['newmaxSize']) . "'" .
420 ",'" . $listval . "'" .
421 ",'" . formTrim($_POST['newbackuplistid']) . "'" .
422 " )");
423 addOrDeleteColumn($layout_id, formTrim($_POST['newid']), true);
424 } else if ($_POST['formaction'] == "movefields" && $layout_id) {
425 // Move field(s) to a new group in the layout
426 $sqlstmt = "UPDATE layout_options SET ".
427 " group_id = '" . $_POST['targetgroup'] . "' " .
428 " WHERE ".
429 " form_id = '" . $_POST['layout_id'] . "' ".
430 " AND field_id IN (";
431 $comma = "";
432 foreach (explode(" ", $_POST['selectedfields']) as $onefield) {
433 $sqlstmt .= $comma."'".$onefield."'";
434 $comma = ", ";
437 $sqlstmt .= ")";
438 //echo $sqlstmt;
439 sqlStatement($sqlstmt);
440 } else if ($_POST['formaction'] == "deletefields" && $layout_id) {
441 // Delete a field from a specific group
442 $sqlstmt = "DELETE FROM layout_options WHERE ".
443 " form_id = '".$_POST['layout_id']."' ".
444 " AND field_id IN (";
445 $comma = "";
446 foreach (explode(" ", $_POST['selectedfields']) as $onefield) {
447 $sqlstmt .= $comma."'".$onefield."'";
448 $comma = ", ";
451 $sqlstmt .= ")";
452 sqlStatement($sqlstmt);
453 foreach (explode(" ", $_POST['selectedfields']) as $onefield) {
454 addOrDeleteColumn($layout_id, $onefield, false);
456 } else if ($_POST['formaction'] == "addgroup" && $layout_id) {
457 // Generate new value for layout_items.group_id.
458 $newgroupid = genGroupId($_POST['newgroupparent']);
460 sqlStatement(
461 "INSERT INTO layout_group_properties SET " .
462 "grp_form_id = ?, " .
463 "grp_group_id = ?, " .
464 "grp_title = ?",
465 array($layout_id, $newgroupid, $_POST['newgroupname'])
468 $data_type = formTrim($_POST['gnewdatatype']);
469 $max_length = $data_type == 3 ? 3 : 255;
470 $listval = $data_type == 34 ? formTrim($_POST['gcontextName']) : formTrim($_POST['gnewlistid']);
471 // add a new group to the layout, with the defined field
472 sqlStatement("INSERT INTO layout_options (" .
473 " form_id, source, field_id, title, group_id, seq, uor, fld_length, fld_rows" .
474 ", titlecols, datacols, data_type, edit_options, default_value, description" .
475 ", max_length, list_id, list_backup_id " .
476 ") VALUES ( " .
477 "'" . formTrim($_POST['layout_id']) . "'" .
478 ",'" . formTrim($_POST['gnewsource']) . "'" .
479 ",'" . formTrim($_POST['gnewid']) . "'" .
480 ",'" . formDataCore($_POST['gnewtitle']) . "'" .
481 ",'" . formTrim($newgroupid) . "'" .
482 ",'" . formTrim($_POST['gnewseq']) . "'" .
483 ",'" . formTrim($_POST['gnewuor']) . "'" .
484 ",'" . formTrim($_POST['gnewlengthWidth']) . "'" .
485 ",'" . formTrim($_POST['gnewlengthHeight']) . "'" .
486 ",'" . formTrim($_POST['gnewtitlecols']) . "'" .
487 ",'" . formTrim($_POST['gnewdatacols']) . "'" .
488 ",'$data_type'" .
489 ",'" . json_encode($_POST['gnewedit_options']) . "'" .
490 ",'" . formTrim($_POST['gnewdefault']) . "'" .
491 ",'" . formTrim($_POST['gnewdesc']) . "'" .
492 ",'" . formTrim($_POST['gnewmaxSize']) . "'" .
493 ",'" . $listval . "'" .
494 ",'" . formTrim($_POST['gnewbackuplistid']) . "'" .
495 " )");
496 addOrDeleteColumn($layout_id, formTrim($_POST['gnewid']), true);
497 } /**********************************************************************
498 else if ($_POST['formaction'] == "deletegroup" && $layout_id) {
499 // drop the fields from the related table (this is critical)
500 $res = sqlStatement("SELECT field_id FROM layout_options WHERE " .
501 "form_id = '" . $_POST['layout_id'] . "' ".
502 "AND group_name = '" . $_POST['deletegroupname'] . "'");
503 while ($row = sqlFetchArray($res)) {
504 addOrDeleteColumn($layout_id, $row['field_id'], false);
507 // Delete an entire group from the form
508 sqlStatement("DELETE FROM layout_options WHERE ".
509 " form_id = '".$_POST['layout_id']."' ".
510 " AND group_name = '".$_POST['deletegroupname']."'"
513 **********************************************************************/
515 else if ($_POST['formaction'] == "movegroup" && $layout_id) {
516 // Note that in some cases below the swapGroups() call will do nothing.
517 $res = sqlStatement(
518 "SELECT DISTINCT group_id " .
519 "FROM layout_options WHERE form_id = ? ORDER BY group_id",
520 array($layout_id)
522 $row = sqlFetchArray($res);
523 $id1 = $row['group_id'];
524 while ($row = sqlFetchArray($res)) {
525 $id2 = $row['group_id'];
526 if ($_POST['movedirection'] == 'up') { // moving up
527 if ($id2 == $_POST['movegroupname']) {
528 swapGroups($id2, $id1);
529 break;
531 } else { // moving down
532 if ($id1 == $_POST['movegroupname']) {
533 swapGroups($id1, $id2);
534 break;
537 $id1 = $id2;
539 } // Renaming a group. This might include moving to a different parent group.
540 else if ($_POST['formaction'] == "renamegroup" && $layout_id) {
541 $newparent = $_POST['renamegroupparent']; // this is an ID
542 $oldid = $_POST['renameoldgroupname']; // this is an ID
543 $oldparent = substr($oldid, 0, -1);
544 $newid = $oldid;
545 if ($newparent != $oldparent) {
546 // Different parent, generate a new child prefix character.
547 $newid = genGroupId($newparent);
548 sqlStatement(
549 "UPDATE layout_options SET group_id = ? " .
550 "WHERE form_id = ? AND group_id = ?",
551 array($newid, $layout_id, $oldid)
554 $query = "UPDATE layout_group_properties SET " .
555 "grp_group_id = ?, grp_title = ? " .
556 "WHERE grp_form_id = ? AND grp_group_id = ?";
557 sqlStatement($query, array($newid, $_POST['renamegroupname'], $layout_id, $oldid));
560 // Get the selected form's elements.
561 if ($layout_id) {
562 $res = sqlStatement("SELECT * FROM layout_options WHERE " .
563 "form_id = '$layout_id' ORDER BY group_id, seq");
566 // global counter for field numbers
567 $fld_line_no = 0;
569 $extra_html = '';
571 // This is called to generate a select option list for fields within this form.
572 // Used for selecting a field for testing in a skip condition.
574 function genFieldOptionList($current = '')
576 global $layout_id;
577 $option_list = "<option value=''>-- " . xlt('Please Select') . " --</option>";
578 if ($layout_id) {
579 $query = "SELECT field_id FROM layout_options WHERE form_id = ? ORDER BY group_id, seq";
580 $res = sqlStatement($query, array($layout_id));
581 while ($row = sqlFetchArray($res)) {
582 $field_id = $row['field_id'];
583 $option_list .= "<option value='" . attr($field_id) . "'";
584 if ($field_id == $current) {
585 $option_list .= " selected";
587 $option_list .= ">" . text($field_id) . "</option>";
590 return $option_list;
593 // Write one option line to the form.
595 function writeFieldLine($linedata)
597 global $fld_line_no, $sources, $lbfonly, $extra_html,$validations;
598 ++$fld_line_no;
599 $checked = $linedata['default_value'] ? " checked" : "";
601 //echo " <tr bgcolor='$bgcolor'>\n";
602 echo " <tr id='fld[$fld_line_no]' class='".($fld_line_no % 2 ? 'even' : 'odd')."'>\n";
604 echo " <td class='optcell' nowrap>";
605 // tuck the group_name INPUT in here
606 echo "<input type='hidden' name='fld[$fld_line_no][group]' value='" .
607 htmlspecialchars($linedata['group_id'], ENT_QUOTES) . "' class='optin' />";
608 // Original field ID.
609 echo "<input type='hidden' name='fld[$fld_line_no][originalid]' value='" .
610 attr($linedata['field_id']) . "' />";
612 echo "<input type='checkbox' class='selectfield' ".
613 "name='" . $linedata['group_id'] . "~" . $linedata['field_id'] . "' " .
614 "id='" . $linedata['group_id'] . "~" . $linedata['field_id'] . "' " .
615 "title='" . xla('Select field') . "' />";
617 echo "<input type='text' name='fld[$fld_line_no][seq]' id='fld[$fld_line_no][seq]' value='" .
618 htmlspecialchars($linedata['seq'], ENT_QUOTES) . "' size='2' maxlength='4' " .
619 "class='optin' style='width:32pt' />";
620 echo "</td>\n";
622 echo " <td align='center' class='optcell' $lbfonly>";
623 echo "<select class='form-control' name='fld[$fld_line_no][source]' class='optin' $lbfonly>";
624 foreach ($sources as $key => $value) {
625 echo "<option value='" . attr($key) . "'";
626 if ($key == $linedata['source']) {
627 echo " selected";
630 echo ">" . text($value) . "</option>\n";
633 echo "</select>";
634 echo "</td>\n";
636 echo " <td align='left' class='optcell'>";
637 echo "<input type='text' name='fld[$fld_line_no][id]' value='" .
638 htmlspecialchars($linedata['field_id'], ENT_QUOTES) . "' size='15' maxlength='63' " .
639 "class='optin' style='width:100%' onclick='FieldIDClicked(this)' />";
640 echo "</td>\n";
642 echo " <td align='center' class='optcell'>";
643 echo "<input type='text' id='fld[$fld_line_no][title]' name='fld[$fld_line_no][title]' value='" .
644 htmlspecialchars($linedata['title'], ENT_QUOTES) . "' size='15' maxlength='63' class='optin' style='width:100%' />";
645 echo "</td>\n";
647 // if not english and set to translate layout labels, then show the translation
648 if ($GLOBALS['translate_layout'] && $_SESSION['language_choice'] > 1) {
649 echo "<td align='center' class='translation' >" . htmlspecialchars(xl($linedata['title']), ENT_QUOTES) . "</td>\n";
652 echo " <td align='center' class='optcell'>";
653 echo "<select class='form-control' name='fld[$fld_line_no][uor]' class='optin'>";
654 foreach (array(0 =>xl('Unused'), 1 =>xl('Optional'), 2 =>xl('Required')) as $key => $value) {
655 echo "<option value='$key'";
656 if ($key == $linedata['uor']) {
657 echo " selected";
660 echo ">$value</option>\n";
663 echo "</select>";
664 echo "</td>\n";
666 echo " <td align='center' class='optcell'>";
667 echo "<select class='form-control' name='fld[$fld_line_no][datatype]' id='fld[$fld_line_no][datatype]' onchange=NationNotesContext('".$fld_line_no."',this.value)>";
668 echo "<option value=''></option>";
669 global $datatypes;
670 foreach ($datatypes as $key => $value) {
671 if ($linedata['data_type'] == $key) {
672 echo "<option value='$key' selected>$value</option>";
673 } else {
674 echo "<option value='$key'>$value</option>";
678 echo "</select>";
679 echo " </td>";
681 echo " <td align='center' class='optcell'>";
682 if ($linedata['data_type'] == 2 || $linedata['data_type'] == 3 ||
683 $linedata['data_type'] == 21 || $linedata['data_type'] == 22 ||
684 $linedata['data_type'] == 23 || $linedata['data_type'] == 25 ||
685 $linedata['data_type'] == 27 || $linedata['data_type'] == 28 ||
686 $linedata['data_type'] == 32 || $linedata['data_type'] == 15 ||
687 $linedata['data_type'] == 40
689 // Show the width field
690 echo "<input type='text' name='fld[$fld_line_no][lengthWidth]' value='" .
691 htmlspecialchars($linedata['fld_length'], ENT_QUOTES) .
692 "' size='2' maxlength='10' class='optin' title='" . xla('Width') . "' />";
693 if ($linedata['data_type'] == 3 || $linedata['data_type'] == 40) {
694 // Show the height field
695 echo "<input type='text' name='fld[$fld_line_no][lengthHeight]' value='" .
696 htmlspecialchars($linedata['fld_rows'], ENT_QUOTES) .
697 "' size='2' maxlength='10' class='optin' title='" . xla('Height') . "' />";
698 } else {
699 // Hide the height field
700 echo "<input type='hidden' name='fld[$fld_line_no][lengthHeight]' value=''>";
702 } else {
703 // all other data_types (hide both the width and height fields
704 echo "<input type='hidden' name='fld[$fld_line_no][lengthWidth]' value=''>";
705 echo "<input type='hidden' name='fld[$fld_line_no][lengthHeight]' value=''>";
708 echo "</td>\n";
710 echo " <td align='center' class='optcell'>";
711 echo "<input type='text' name='fld[$fld_line_no][maxSize]' value='" .
712 htmlspecialchars($linedata['max_length'], ENT_QUOTES) .
713 "' size='1' maxlength='10' class='optin' style='width:100%' " .
714 "title='" . xla('Maximum Size (entering 0 will allow any size)') . "' />";
715 echo "</td>\n";
717 echo " <td align='center' class='optcell'>";
718 if ($linedata['data_type'] == 1 || $linedata['data_type'] == 21 ||
719 $linedata['data_type'] == 22 || $linedata['data_type'] == 23 ||
720 $linedata['data_type'] == 25 || $linedata['data_type'] == 26 ||
721 $linedata['data_type'] == 27 || $linedata['data_type'] == 32 ||
722 $linedata['data_type'] == 33 || $linedata['data_type'] == 34 ||
723 $linedata['data_type'] == 36) {
724 $type = "";
725 $disp = "style='display:none'";
726 if ($linedata['data_type'] == 34) {
727 $type = "style='display:none'";
728 $disp = "";
731 echo "<input type='text' name='fld[$fld_line_no][list_id]' id='fld[$fld_line_no][list_id]' value='" .
732 htmlspecialchars($linedata['list_id'], ENT_QUOTES) . "'".$type.
733 " size='6' maxlength='100' class='optin listid' style='width:100%;cursor:pointer'".
734 "title='". xl('Choose list') . "' />";
736 echo "<select class='form-control' name='fld[$fld_line_no][contextName]' id='fld[$fld_line_no][contextName]' ".$disp.">";
737 $res = sqlStatement("SELECT * FROM customlists WHERE cl_list_type=2 AND cl_deleted=0");
738 while ($row = sqlFetchArray($res)) {
739 $sel = '';
740 if ($linedata['list_id'] == $row['cl_list_item_long']) {
741 $sel = 'selected';
744 echo "<option value='".htmlspecialchars($row['cl_list_item_long'], ENT_QUOTES)."' ".$sel.">".htmlspecialchars($row['cl_list_item_long'], ENT_QUOTES)."</option>";
747 echo "</select>";
748 } else {
749 // all other data_types
750 echo "<input type='hidden' name='fld[$fld_line_no][list_id]' value=''>";
753 echo "</td>\n";
755 //Backup List Begin
756 echo " <td align='center' class='optcell'>";
757 if ($linedata['data_type'] == 1 || $linedata['data_type'] == 26 ||
758 $linedata['data_type'] == 33 || $linedata['data_type'] == 36) {
759 echo "<input type='text' name='fld[$fld_line_no][list_backup_id]' value='" .
760 htmlspecialchars($linedata['list_backup_id'], ENT_QUOTES) .
761 "' size='3' maxlength='100' class='optin listid' style='cursor:pointer; width:100%' />";
762 } else {
763 echo "<input type='hidden' name='fld[$fld_line_no][list_backup_id]' value=''>";
766 echo "</td>\n";
767 //Backup List End
769 echo " <td align='center' class='optcell'>";
770 echo "<input type='text' name='fld[$fld_line_no][titlecols]' value='" .
771 htmlspecialchars($linedata['titlecols'], ENT_QUOTES) . "' size='3' maxlength='10' class='optin' style='width:100%' />";
772 echo "</td>\n";
774 echo " <td align='center' class='optcell'>";
775 echo "<input type='text' name='fld[$fld_line_no][datacols]' value='" .
776 htmlspecialchars($linedata['datacols'], ENT_QUOTES) . "' size='3' maxlength='10' class='optin' style='width:100%' />";
777 echo "</td>\n";
778 /* Below for compatabilty with existing string modifiers. */
779 if (strpos($linedata['edit_options'], ',') === false && ! empty($linedata['edit_options'])) {
780 json_decode($linedata['edit_options']);
781 if (is_string($linedata['edit_options']) && ! (json_last_error() === JSON_ERROR_NONE)) { // hopefully string of characters.
782 $t = str_split(trim($linedata['edit_options']));
783 $linedata['edit_options'] = json_encode($t); // convert to array select understands.
786 echo " <td align='center' class='optcell' title='" . xla("Add modifiers for this field type. You may select more than one.") . "'>";
787 echo "<select id='fld[$fld_line_no][edit_options]' name='fld[$fld_line_no][edit_options][]' class='typeAddons optin' size=3 multiple data-set='" .
788 trim($linedata['edit_options']) . "' ></select></td>\n";
790 if ($linedata['data_type'] == 31) {
791 echo " <td align='center' class='optcell'>";
792 echo "<textarea name='fld[$fld_line_no][desc]' rows='3' cols='35' class='optin' style='width:100%'>" .
793 $linedata['description'] . "</textarea>";
794 echo "<input type='hidden' name='fld[$fld_line_no][default]' value='" .
795 htmlspecialchars($linedata['default_value'], ENT_QUOTES) . "' />";
796 echo "</td>\n";
797 } else {
798 echo " <td align='center' class='optcell' >";
799 echo "<input type='text' name='fld[$fld_line_no][desc]' value='" .
800 htmlspecialchars($linedata['description'], ENT_QUOTES) .
801 "' size='30' class='optin' style='width:100%' />";
802 echo "<input type='hidden' name='fld[$fld_line_no][default]' value='" .
803 htmlspecialchars($linedata['default_value'], ENT_QUOTES) . "' />";
804 echo "</td>\n";
805 // if not english and showing layout labels, then show the translation of Description
806 if ($GLOBALS['translate_layout'] && $_SESSION['language_choice'] > 1) {
807 echo "<td align='center' class='translation'>" .
808 htmlspecialchars(xl($linedata['description']), ENT_QUOTES) . "</td>\n";
812 // The "?" to click on for yet more field attributes.
813 echo " <td class='bold' id='querytd_$fld_line_no' style='cursor:pointer;";
814 if (!empty($linedata['conditions']) || !empty($linedata['validation'])) {
815 echo "background-color:#77ff77;";
818 echo "' onclick='extShow($fld_line_no, this)' align='center' ";
819 echo "title='" . xla('Click here to view/edit more details') . "'>";
820 echo "&nbsp;?&nbsp;";
821 echo "</td>\n";
823 echo " </tr>\n";
825 // Create a floating div for the additional attributes of this field.
826 $conditions = empty($linedata['conditions']) ?
827 array(0 => array('id' => '', 'itemid' => '', 'operator' => '', 'value' => '')) :
828 unserialize($linedata['conditions']);
829 $action = empty($conditions['action']) ? 'skip' : $conditions['action'];
830 $action_value = $action == 'skip' ? '' : substr($action, 6);
832 $extra_html .= "<div id='ext_$fld_line_no' " .
833 "style='position:absolute;width:750px;border:1px solid black;" .
834 "padding:2px;background-color:#cccccc;visibility:hidden;" .
835 "z-index:1000;left:-1000px;top:0px;font-size:8pt;'>\n" .
836 "<table width='100%'>\n" .
837 " <tr>\n" .
838 " <th colspan='3' align='left' class='bold'>" .
839 xlt('For') . " " . text($linedata['field_id']) . " " .
840 "<select name='fld[$fld_line_no][action]' onchange='actionChanged($fld_line_no)'>" .
841 "<option value='skip' " . ($action == 'skip' ? 'selected' : '') . ">" . xlt('hide this field') . "</option>" .
842 "<option value='value' " . ($action != 'skip' ? 'selected' : '') . ">" . xlt('set value to') . "</option>" .
843 "</select>" .
844 "<input type='text' name='fld[$fld_line_no][value]' value='" . attr($action_value) . "' size='15' />" .
845 " " . xlt('if') .
846 "</th>\n" .
847 " <th colspan='2' align='right' class='text'><input type='button' " .
848 "value='" . xla('Close') . "' onclick='extShow($fld_line_no, false)' />&nbsp;</th>\n" .
849 " </tr>\n" .
850 " <tr>\n" .
851 " <th align='left' class='bold'>" . xlt('Field ID') . "</th>\n" .
852 " <th align='left' class='bold'>" . xlt('List item ID') . "</th>\n" .
853 " <th align='left' class='bold'>" . xlt('Operator') . "</th>\n" .
854 " <th align='left' class='bold'>" . xlt('Value if comparing') . "</th>\n" .
855 " <th align='left' class='bold'>&nbsp;</th>\n" .
856 " </tr>\n";
857 // There may be multiple condition lines for each field.
858 foreach ($conditions as $i => $condition) {
859 if (!is_numeric($i)) {
860 continue; // skip if 'action'
862 $extra_html .=
863 " <tr>\n" .
864 " <td align='left'>\n" .
865 " <select name='fld[$fld_line_no][condition_id][$i]' onchange='cidChanged($fld_line_no, $i)'>" .
866 genFieldOptionList($condition['id']) . " </select>\n" .
867 " </td>\n" .
868 " <td align='left'>\n" .
869 // List item choices are populated on the client side but will need the current value,
870 // so we insert a temporary option here to hold that value.
871 " <select name='fld[$fld_line_no][condition_itemid][$i]'><option value='" .
872 attr($condition['itemid']) . "'>...</option></select>\n" .
873 " </td>\n" .
874 " <td align='left'>\n" .
875 " <select name='fld[$fld_line_no][condition_operator][$i]'>\n";
876 foreach (array(
877 'eq' => xl('Equals'),
878 'ne' => xl('Does not equal'),
879 'se' => xl('Is selected'),
880 'ns' => xl('Is not selected'),
881 ) as $key => $value) {
882 $extra_html .= " <option value='$key'";
883 if ($key == $condition['operator']) {
884 $extra_html .= " selected";
887 $extra_html .= ">" . text($value) . "</option>\n";
890 $extra_html .=
891 " </select>\n" .
892 " </td>\n" .
893 " <td align='left' title='" . xla('Only for comparisons') . "'>\n" .
894 " <input type='text' name='fld[$fld_line_no][condition_value][$i]' value='" .
895 attr($condition['value']) . "' size='15' maxlength='63' />\n" .
896 " </td>\n";
897 if (!isset($conditions[$i + 1])) {
898 $extra_html .=
899 " <td align='right' title='" . xla('Add a condition') . "'>\n" .
900 " <input type='button' value='+' onclick='extAddCondition($fld_line_no,this)' />\n" .
901 " </td>\n";
902 } else {
903 $extra_html .=
904 " <td align='right'>\n" .
905 " <select name='fld[$fld_line_no][condition_andor][$i]'>\n";
906 foreach (array(
907 'and' => xl('And'),
908 'or' => xl('Or'),
909 ) as $key => $value) {
910 $extra_html .= " <option value='$key'";
911 if ($key == $condition['andor']) {
912 $extra_html .= " selected";
915 $extra_html .= ">" . text($value) . "</option>\n";
918 $extra_html .=
919 " </select>\n" .
920 " </td>\n";
923 $extra_html .=
924 " </tr>\n";
927 $extra_html .=
928 "</table>\n";
930 $extra_html .= "<table width='100%'>\n" .
931 " <tr>\n" .
932 " <td colspan='3' align='left' class='bold'>\"" . text($linedata['field_id']) . "\" " .
933 xlt('will have the following validation rules') . ":</td>\n" .
934 " </tr>\n" .
935 " <tr>\n" .
936 " <td align='left' class='bold'>" . xlt('Validation rule') . " </td>\n" .
937 " </tr>\n".
938 " <tr>\n" .
939 " <td align='left' title='" . xla('Select a validation rule') . "'>\n" .
942 " <select name='fld[$fld_line_no][validation]' onchange='valChanged($fld_line_no)'>\n" .
943 " <option value=''";
944 if (empty($linedata['validation'])) {
945 $extra_html .= " selected";
948 $extra_html .= ">-- " . xlt('Please Select') . " --</option>";
949 foreach ($validations as $key => $value) {
950 $extra_html .= " <option value='$key'";
951 if ($key == $linedata['validation']) {
952 $extra_html .= " selected";
955 $extra_html .= ">" . text($value) . "</option>\n";
958 $extra_html .="</select>\n" .
959 " </td>\n";
961 $extra_html .=
962 "</table>\n" .
963 "</div>\n";
966 <html>
968 <head>
970 <?php Header::setupHeader('select2'); ?>
972 <title><?php xl('Layout Editor', 'e'); ?></title>
974 <style>
975 .orgTable tr.head { font-size:8pt; background-color:#cccccc; }
976 .orgTable tr.detail { font-size:8pt; }
977 .orgTable td { font-size:8pt; }
978 .orgTable input { font-size:8pt; }
979 .orgTable select { font-size:8pt; }
980 a, a:visited, a:hover { color:#0000cc; }
981 .optcell { }
982 .optin { background: transparent; }
983 .group {
984 margin: 0pt 0pt 8pt 0pt;
985 padding :0pt;
986 width: 100%;
989 .group table {
990 border-collapse: collapse;
991 width: 100%;
994 .orgTable .odd td {
995 background-color: #ddddff;
996 padding: 3px 0px 3px 0px;
998 .orgTable .even td {
999 background-color: #ffdddd;
1000 padding: 3px 0px 3px 0px;
1002 .help { cursor: help; }
1003 .layouts_title { font-size: 110%; }
1004 .translation {
1005 color: green;
1006 font-size:8pt;
1008 .highlight * {
1009 border: 2px solid blue;
1010 background-color: yellow;
1011 color: black;
1013 .select2-container--default .select2-selection--multiple {
1014 cursor: pointer;
1016 .select2-search__field {
1017 cursor: pointer;
1018 width: 0 !important;
1020 .select2-selection__choice {
1021 font-size: 12px;
1023 .select2-container {
1024 cursor: pointer;
1025 opacity: 0.99 !important;
1027 </style>
1029 <script>
1030 // Helper functions for positioning the floating divs.
1031 function extGetX(elem) {
1032 var x = 0;
1033 while(elem != null) {
1034 x += elem.offsetLeft;
1035 elem = elem.offsetParent;
1037 return x;
1039 function extGetY(elem) {
1040 var y = 0;
1041 while(elem != null) {
1042 y += elem.offsetTop;
1043 elem = elem.offsetParent;
1045 return y;
1048 // Show or hide the "extras" div for a row.
1049 var extdiv = null;
1050 function extShow(lino, show) {
1051 var thisdiv = document.getElementById("ext_" + lino);
1052 if (extdiv) {
1053 extdiv.style.visibility = 'hidden';
1054 extdiv.style.left = '-1000px';
1055 extdiv.style.top = '0px';
1057 if (show && thisdiv != extdiv) {
1058 extdiv = thisdiv;
1059 var dw = window.innerWidth ? window.innerWidth - 20 : document.body.clientWidth;
1060 x = dw - extdiv.offsetWidth;
1061 if (x < 0) x = 0;
1062 var y = extGetY(show) + show.offsetHeight;
1063 extdiv.style.left = x;
1064 extdiv.style.top = y;
1065 extdiv.style.visibility = 'visible';
1067 else {
1068 extdiv = null;
1072 // Show or hide the value field for a "Set value to" condition.
1073 function actionChanged(lino) {
1074 var f = document.forms[0];
1075 var eaction = f['fld[' + lino + '][action]'];
1076 var evalue = f['fld[' + lino + '][value]'];
1077 evalue.style.display = eaction.value == 'skip' ? 'none' : '';
1080 // Add an extra condition line for the given row.
1081 function extAddCondition(lino, btnelem) {
1082 var f = document.forms[0];
1083 var i = 0;
1085 // Get index of next condition line.
1086 while (f['fld[' + lino + '][condition_id][' + i + ']']) ++i;
1087 if (i == 0) alert('f["fld[' + lino + '][condition_id][' + i + ']"] <?php echo xls('not found') ?>');
1089 // Get containing <td>, <tr> and <table> nodes of the "+" button.
1090 var tdplus = btnelem.parentNode;
1091 var trelem = tdplus.parentNode;
1092 var telem = trelem.parentNode;
1094 // Replace contents of the tdplus cell.
1095 tdplus.innerHTML =
1096 "<select name='fld[" + lino + "][condition_andor][" + i + "]'>" +
1097 "<option value='and'><?php echo xls('And') ?></option>" +
1098 "<option value='or' ><?php echo xls('Or') ?></option>" +
1099 "</select>";
1101 // Add the new row.
1102 var newtrelem = telem.insertRow(i+2);
1103 newtrelem.innerHTML =
1104 "<td align='left'>" +
1105 "<select name='fld[" + lino + "][condition_id][" + i + "]' onchange='cidChanged(" + lino + "," + i + ")'>" +
1106 "<?php echo addslashes(genFieldOptionList()) ?>" +
1107 "</select>" +
1108 "</td>" +
1109 "<td align='left'>" +
1110 "<select name='fld[" + lino + "][condition_itemid][" + i + "]' style='display:none' />" +
1111 "</td>" +
1112 "<td align='left'>" +
1113 "<select name='fld[" + lino + "][condition_operator][" + i + "]'>" +
1114 "<option value='eq'><?php echo xls('Equals') ?></option>" +
1115 "<option value='ne'><?php echo xls('Does not equal') ?></option>" +
1116 "<option value='se'><?php echo xls('Is selected') ?></option>" +
1117 "<option value='ns'><?php echo xls('Is not selected') ?></option>" +
1118 "</select>" +
1119 "</td>" +
1120 "<td align='left'>" +
1121 "<input type='text' name='fld[" + lino + "][condition_value][" + i + "]' value='' size='15' maxlength='63' />" +
1122 "</td>" +
1123 "<td align='right'>" +
1124 "<input type='button' value='+' onclick='extAddCondition(" + lino + ",this)' />" +
1125 "</td>";
1128 // This is called when a field ID is chosen for testing within a skip condition.
1129 // It checks to see if a corresponding list item must also be chosen for the test, and
1130 // if so then inserts the dropdown for selecting an item from the appropriate list.
1131 function setListItemOptions(lino, seq, init) {
1132 var f = document.forms[0];
1133 var target = 'fld[' + lino + '][condition_itemid][' + seq + ']';
1134 // field_id is the ID of the field that the condition will test.
1135 var field_id = f['fld[' + lino + '][condition_id][' + seq + ']'].value;
1136 if (!field_id) {
1137 f[target].options.length = 0;
1138 f[target].style.display = 'none';
1139 return;
1141 // Find the occurrence of that field in the layout.
1142 var i = 1;
1143 while (true) {
1144 var idname = 'fld[' + i + '][id]';
1145 if (!f[idname]) {
1146 alert('<?php echo xls('Condition field not found') ?>: ' + field_id);
1147 return;
1149 if (f[idname].value == field_id) break;
1150 ++i;
1152 // If this is startup initialization then preserve the current value.
1153 var current = init ? f[target].value : '';
1154 f[target].options.length = 0;
1155 // Get the corresponding data type and list ID.
1156 var data_type = f['fld[' + i + '][datatype]'].value;
1157 var list_id = f['fld[' + i + '][list_id]'].value;
1158 // WARNING: If new data types are defined the following test may need enhancing.
1159 // We're getting out if the type does not generate multiple fields with different names.
1160 if (data_type != '21' && data_type != '22' && data_type != '23' && data_type != '25') {
1161 f[target].style.display = 'none';
1162 return;
1164 // OK, list item IDs do apply so go get 'em.
1165 // This happens asynchronously so the generated code needs to stand alone.
1166 f[target].style.display = '';
1167 $.getScript('layout_listitems_ajax.php' +
1168 '?listid=' + encodeURIComponent(list_id) +
1169 '&target=' + encodeURIComponent(target) +
1170 '&current=' + encodeURIComponent(current));
1173 // This is called whenever a condition's field ID selection is changed.
1174 function cidChanged(lino, seq) {
1175 changeColor(lino);
1176 setListItemOptions(lino, seq, false);
1179 // This invokes the popup to edit layout properties or add a new layout.
1180 function edit_layout_props(groupid) {
1181 dlgopen('edit_layout_props.php?layout_id=<?php echo attr($layout_id); ?>&group_id=' + groupid,
1182 '_blank', 700, 550);
1185 // callback from edit_layout_props.php:
1186 function refreshme(layout_id) {
1187 location.href = 'edit_layout.php?layout_id=' + layout_id;
1190 // This is called whenever a validation rule field ID selection is changed.
1191 function valChanged(lino) {
1192 changeColor(lino);
1195 function changeColor(lino){
1196 var thisid = document.forms[0]['fld[' + lino + '][condition_id][0]'].value;
1197 var thisValId = document.forms[0]['fld[' + lino + '][validation]'].value;
1198 var thistd = document.getElementById("querytd_" + lino);
1199 if(thisid !='' || thisValId!='') {
1200 thistd.style.backgroundColor = '#77ff77';
1201 }else{
1202 thistd.style.backgroundColor ='';
1206 // Call this to disable the warning about unsaved changes and submit the form.
1207 function mySubmit() {
1208 somethingChanged = false;
1209 top.restoreSession();
1210 document.forms[0].submit();
1213 // User is about to do something that would discard any unsaved changes.
1214 // Return true if that is OK.
1215 function myChangeCheck() {
1216 if (somethingChanged) {
1217 if (!confirm('<?php echo xls('You have unsaved changes. Abandon them?'); ?>')) {
1218 return false;
1220 // Do not set somethingChanged to false here because if they cancel the
1221 // action then the previously changed values will still be of interest.
1223 return true;
1226 </script>
1228 </head>
1230 <body class="body_top admin-layout">
1231 <div class="container-responsive">
1232 <form method='post' name='theform' id='theform' action='edit_layout.php'>
1233 <input type="hidden" name="formaction" id="formaction" value="">
1234 <!-- elements used to identify a field to delete -->
1235 <input type="hidden" name="deletefieldid" id="deletefieldid" value="">
1236 <input type="hidden" name="deletefieldgroup" id="deletefieldgroup" value="">
1237 <!-- elements used to identify a group to delete -->
1238 <!--
1239 <input type="hidden" name="deletegroupname" id="deletegroupname" value="">
1241 <!-- elements used to change the group order -->
1242 <input type="hidden" name="movegroupname" id="movegroupname" value="">
1243 <input type="hidden" name="movedirection" id="movedirection" value="">
1244 <!-- elements used to select more than one field -->
1245 <input type="hidden" name="selectedfields" id="selectedfields" value="">
1246 <input type="hidden" id="targetgroup" name="targetgroup" value="">
1247 <div class="lbfmenubar">
1248 <span>
1249 <b><?php xl('Edit layout', 'e'); ?>:</b>&nbsp;
1250 <select name='layout_id' id='layout_id' class='form-control' style='display:inline-block;margin-bottom:5px;width:15%;'>
1251 <option value=''>-- <?php echo xl('Select') ?> --</option>
1252 <?php
1253 $lastgroup = '';
1254 foreach ($layouts as $key => $value) {
1255 if ($value[0] != $lastgroup) {
1256 if ($lastgroup) {
1257 echo " </optgroup>\n";
1259 echo " <optgroup label='" . attr($value[0]) . "'>\n";
1260 $lastgroup = $value[0];
1262 echo " <option value='" . attr($key) . "'";
1263 if ($key == $layout_id) {
1264 echo " selected";
1266 echo ">" . text($value[1]) . "</option>\n";
1268 if ($lastgroup) {
1269 echo " </optgroup>\n";
1272 </select>
1273 </span>
1274 <div><p>
1275 <?php if ($layout_id) { ?>
1276 <input type='button' value='<?php echo xla('Layout Properties'); ?>' onclick='edit_layout_props("")' />&nbsp;
1277 <input type='button' class='addgroup' id='addgroup' value='<?php echo xla('Add Group'); ?>' />
1278 <span style="font-size:90%"> &nbsp;
1279 <input type='button' class="btn btn-danger"name='save' id='save' value='<?php xl('Save Changes', 'e'); ?>' /></span> &nbsp;&nbsp;
1280 <?php xl('With selected:', 'e');?>
1281 <input type='button' name='deletefields' id='deletefields' value='<?php xl('Delete', 'e'); ?>' style="font-size:90%" disabled="disabled" />
1282 <input type='button' name='movefields' id='movefields' value='<?php xl('Move to...', 'e'); ?>' style="font-size:90%" disabled="disabled" /></span>
1283 <?php } else { ?>
1284 <input type='button' value='<?php echo xla('New Layout'); ?>' onclick='edit_layout_props("")' />&nbsp;
1285 <?php } ?>
1286 </p></div>
1287 </div>
1289 <?php
1290 // Load array of properties for this layout and its groups.
1291 $grparr = array();
1292 $gres = sqlStatement("SELECT * FROM layout_group_properties WHERE grp_form_id = ? " .
1293 "ORDER BY grp_group_id", array($layout_id));
1294 while ($grow = sqlFetchArray($gres)) {
1295 $grparr[$grow['grp_group_id']] = $grow;
1298 $prevgroup = "!@#asdf1234"; // an unlikely group ID
1299 $firstgroup = true; // flag indicates it's the first group to be displayed
1301 while ($row = sqlFetchArray($res)) {
1302 $group_id = $row['group_id'];
1303 if ($group_id != $prevgroup) {
1304 if ($firstgroup == false) {
1305 echo "</tbody></table></div>\n";
1307 echo "<div id='" . $group_id . "' class='group'>";
1308 echo "<div class='text bold layouts_title' style='position:relative; background-color: #eef'>";
1310 // Get the fully qualified descriptive name of this group (i.e. including ancestor names).
1311 $gdispname = '';
1312 for ($i = 1; $i <= strlen($group_id); ++$i) {
1313 if ($gdispname) {
1314 $gdispname .= ' / ';
1316 $gdispname .= $grparr[substr($group_id, 0, $i)]['grp_title'];
1318 $gmyname = $grparr[$group_id]['grp_title'];
1320 echo text($gdispname);
1322 // if not english and set to translate layout labels, then show the translation of group name
1323 if ($GLOBALS['translate_layout'] && $_SESSION['language_choice'] > 1) {
1324 echo "<span class='translation'&gt;&gt;&gt;&nbsp; " . xlt($gdispname) . "</span>";
1325 echo "&nbsp; ";
1328 echo "&nbsp; ";
1329 echo " <input type='button' class='addfield' id='addto~$group_id' value='" . xla('Add Field') . "'/>";
1330 echo "&nbsp; &nbsp; ";
1331 echo " <input type='button' class='renamegroup' id='$group_id~$gmyname' value='" . xla('Rename Group') . "'/>";
1332 /******************************************************************
1333 echo "&nbsp; &nbsp; ";
1334 echo " <input type='button' class='deletegroup' id='$group_id' value='" . xl('Delete Group') . "'/>";
1335 ******************************************************************/
1336 echo "&nbsp; &nbsp; ";
1337 echo " <input type='button' class='movegroup' id='$group_id~up' value='" . xl('Move Up') . "'/>";
1338 echo "&nbsp; &nbsp; ";
1339 echo " <input type='button' class='movegroup' id='$group_id~down' value='" . xl('Move Down') . "'/>";
1340 echo "&nbsp; &nbsp; ";
1341 echo "<input type='button' value='" . xla('Group Properties') . "' onclick='edit_layout_props(\"$group_id\")' />";
1342 echo "</div>";
1343 $firstgroup = false;
1345 <table class='table table-condensed table-striped'>
1346 <thead>
1347 <tr class='head'>
1348 <th style='width:1%'><?php xl('Order', 'e'); ?></th>
1349 <th <?php echo " $lbfonly"; ?>style='width:5%'><?php xl('Source', 'e'); ?></th>
1350 <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>
1351 <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>
1352 <?php // if not english and showing layout label translations, then show translation header for title
1353 if ($GLOBALS['translate_layout'] && $_SESSION['language_choice'] > 1) {
1354 echo "<th>" . xl('Translation')."<span class='help' title='" . xl('The translated label that will appear on the form in current language') . "'>&nbsp;(?)</span></th>";
1355 } ?>
1356 <th style='width:6%'><?php xl('UOR', 'e'); ?></th>
1357 <th style='width:10%'><?php xl('Data Type', 'e'); ?></th>
1358 <th style='width:1%'><?php xl('Size', 'e'); ?></th>
1359 <th style='width:1%'><?php xl('Max Size', 'e'); ?></th>
1360 <th style='width:10%'><?php xl('List', 'e'); ?></th>
1361 <th style='width:10%'><?php xl('Backup List', 'e'); ?></th>
1362 <th style='width:1%'><?php xl('Label Cols', 'e'); ?></th>
1363 <th style='width:1%'><?php xl('Data Cols', 'e'); ?></th>
1364 <th style='width:5%'><?php xl('Options', 'e'); ?></th>
1365 <th style='width:20%'><?php xl('Description', 'e'); ?></th>
1366 <?php // if not english and showing layout label translations, then show translation header for description
1367 if ($GLOBALS['translate_layout'] && $_SESSION['language_choice'] > 1) {
1368 echo "<th>" . xl('Translation')."<span class='help' title='" . xl('The translation of description in current language')."'>&nbsp;(?)</span></th>";
1369 } ?>
1370 <th style='width:1%'><?php echo xlt('?'); ?></th>
1371 </tr>
1372 </thead>
1373 <tbody>
1375 <?php
1376 } // end if-group_name
1378 writeFieldLine($row);
1379 $prevgroup = $group_id;
1380 } // end while loop
1383 </tbody>
1384 </table>
1386 <?php echo $extra_html; ?>
1388 </form>
1390 <!-- template DIV that appears when user chooses to rename an existing group -->
1391 <div id="renamegroupdetail"
1392 style="border: 1px solid black; padding: 3px; display: none; visibility: hidden; background-color: lightgrey;">
1393 <input type="hidden" name="renameoldgroupname" id="renameoldgroupname" value="" />
1394 <?php echo xlt('Group Name'); ?>:
1395 <input type="text" size="20" maxlength="30" name="renamegroupname" id="renamegroupname" />
1396 &nbsp;&nbsp;
1397 <?php echo xlt('Parent'); ?>:
1398 <?php echo genGroupSelector('renamegroupparent', $layout_id); ?>
1399 <br>
1400 <input type="button" class="saverenamegroup .btn-save" value="<?php echo xla('Rename Group'); ?>" />
1401 <input type="button" class="cancelrenamegroup" value="<?php echo xla('Cancel'); ?>" />
1402 </div>
1404 <!-- template DIV that appears when user chooses to add a new group -->
1405 <div id="groupdetail"
1406 style="border: 1px solid black; padding: 3px; display: none; visibility: hidden; background-color: lightgrey;">
1407 <span class='bold'>
1408 <?php echo xlt('Group Name'); ?>:
1409 <input type="text" size="20" maxlength="30" name="newgroupname" id="newgroupname" />
1410 &nbsp;&nbsp;
1411 <?php echo xlt('Parent'); ?>:
1412 <?php echo genGroupSelector('newgroupparent', $layout_id); ?>
1413 <br>
1414 <table class='table table-condensed table-striped' style="border-collapse: collapse; margin-top: 5px;">
1415 <thead>
1416 <tr class='head'>
1417 <th style='width:1%'><?php xl('Order', 'e'); ?></th>
1418 <th <?php echo " $lbfonly"; ?>style='width:5%'><?php xl('Source', 'e'); ?></th>
1419 <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>
1420 <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>
1421 <th style='width:6%'><?php xl('UOR', 'e'); ?></th>
1422 <th style='width:10%'><?php xl('Data Type', 'e'); ?></th>
1423 <th style='width:1%'><?php xl('Size', 'e'); ?></th>
1424 <th style='width:1%'><?php xl('Max Size', 'e'); ?></th>
1425 <th style='width:10%'><?php xl('List', 'e'); ?></th>
1426 <th style='width:10%'><?php xl('Backup List', 'e'); ?></th>
1427 <th style='width:1%'><?php xl('Label Cols', 'e'); ?></th>
1428 <th style='width:1%'><?php xl('Data Cols', 'e'); ?></th>
1429 <th style='width:10%'><?php xl('Options', 'e'); ?></th>
1430 <th style='width:20%'><?php xl('Description', 'e'); ?></th>
1431 </tr>
1432 </thead>
1433 <tbody>
1434 <tr class='center'>
1435 <td ><input type="text" name="gnewseq" id="gnewseq" value="" size="2" maxlength="4"> </td>
1436 <td<?php echo " $lbfonly"; ?>>
1437 <select class='form-control' name='gnewsource' id='gnewsource'>
1438 <?php
1439 foreach ($sources as $key => $value) {
1440 echo "<option value='" . attr($key) . "'>" . text($value) . "</option>\n";
1443 </select>
1444 </td>
1445 <td><input type="text" name="gnewid" id="gnewid" value="" size="10" maxlength="20"
1446 onclick='FieldIDClicked(this)'> </td>
1447 <td><input type="text" name="gnewtitle" id="gnewtitle" value="" size="20" maxlength="63"> </td>
1448 <td>
1449 <select class='form-control' name="gnewuor" id="gnewuor">
1450 <option value="0"><?php xl('Unused', 'e'); ?></option>
1451 <option value="1" selected><?php xl('Optional', 'e'); ?></option>
1452 <option value="2"><?php xl('Required', 'e'); ?></option>
1453 </select>
1454 </td>
1455 <td align='center'>
1456 <select class='form-control' name='gnewdatatype' id='gnewdatatype'>
1457 <option value=''></option>
1458 <?php
1459 global $datatypes;
1460 foreach ($datatypes as $key => $value) {
1461 echo "<option value='$key'>$value</option>";
1464 </select>
1465 </td>
1466 <td><input type="text" name="gnewlengthWidth" id="gnewlengthWidth" value="" size="1" maxlength="3" title="<?php echo xla('Width'); ?>">
1467 <input type="text" name="gnewlengthHeight" id="gnewlengthHeight" value="" size="1" maxlength="3" title="<?php echo xla('Height'); ?>"></td>
1468 <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>
1469 <td><input type="text" name="gnewlistid" id="gnewlistid" value="" size="8" maxlength="100" class="listid">
1470 <select class='form-control' name='gcontextName' id='gcontextName' style='display:none'>
1471 <?php
1472 $res = sqlStatement("SELECT * FROM customlists WHERE cl_list_type=2 AND cl_deleted=0");
1473 while ($row = sqlFetchArray($res)) {
1474 echo "<option value='".htmlspecialchars($row['cl_list_item_long'], ENT_QUOTES)."'>".htmlspecialchars($row['cl_list_item_long'], ENT_QUOTES)."</option>";
1477 </select>
1478 </td>
1479 <td><input type="text" name="gnewbackuplistid" id="gnewbackuplistid" value="" size="8" maxlength="100" class="listid"></td>
1480 <td><input type="text" name="gnewtitlecols" id="gnewtitlecols" value="" size="3" maxlength="3"> </td>
1481 <td><input type="text" name="gnewdatacols" id="gnewdatacols" value="" size="3" maxlength="3"> </td>
1482 <td><select name="gnewedit_options[]" id="gnewedit_options" class="typeAddons" multiple style='width:100%' value="" size="3"></select>
1483 <input type="hidden" name="gnewdefault" id="gnewdefault" value="" /> </td>
1484 <td><input type="text" name="gnewdesc" id="gnewdesc" value="" size="30"> </td>
1485 </tr>
1486 </tbody>
1487 </table>
1488 <br>
1489 <input type="button" class="savenewgroup" value=<?php xl('Save New Group', 'e', '\'', '\''); ?>>
1490 <input type="button" class="cancelnewgroup" value=<?php xl('Cancel', 'e', '\'', '\''); ?>>
1491 </span>
1492 </div>
1494 <!-- template DIV that appears when user chooses to add a new field to a group -->
1495 <div id="fielddetail" class="fielddetail" style="display: none; visibility: hidden">
1496 <input type="hidden" name="newfieldgroupid" id="newfieldgroupid" value="">
1497 <table class="table table-condensed" style="border-collapse: collapse;">
1498 <thead>
1499 <tr class='head'>
1500 <th style='width:1%'><?php xl('Order', 'e'); ?></th>
1501 <th <?php echo " $lbfonly"; ?>style='width:5%'><?php xl('Source', 'e'); ?></th>
1502 <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>
1503 <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>
1504 <th style='width:6%'><?php xl('UOR', 'e'); ?></th>
1505 <th style='width:10%'><?php xl('Data Type', 'e'); ?></th>
1506 <th style='width:1%'><?php xl('Size', 'e'); ?></th>
1507 <th style='width:1%'><?php xl('Max Size', 'e'); ?></th>
1508 <th style='width:10%'><?php xl('List', 'e'); ?></th>
1509 <th style='width:10%'><?php xl('Backup List', 'e'); ?></th>
1510 <th style='width:1%'><?php xl('Label Cols', 'e'); ?></th>
1511 <th style='width:1%'><?php xl('Data Cols', 'e'); ?></th>
1512 <th style='width:10%'><?php xl('Options', 'e'); ?></th>
1513 <th style='width:20%'><?php xl('Description', 'e'); ?></th>
1514 </tr>
1515 </thead>
1516 <tbody>
1517 <tr class='center'>
1518 <td ><input type="text" name="newseq" id="newseq" value="" size="2" maxlength="4"> </td>
1519 <td<?php echo " $lbfonly"; ?>>
1520 <select class='form-control' name='newsource' id='newsource'>
1521 <?php
1522 foreach ($sources as $key => $value) {
1523 echo " <option value='" . attr($key) . "'>" . text($value) . "</option>\n";
1526 </select>
1527 </td>
1528 <td ><input type="text" name="newid" id="newid" value="" size="10" maxlength="20"
1529 onclick='FieldIDClicked(this)'> </td>
1530 <td><input type="text" name="newtitle" id="newtitle" value="" size="20" maxlength="63"> </td>
1531 <td>
1532 <select class='form-control' name="newuor" id="newuor">
1533 <option value="0"><?php xl('Unused', 'e'); ?></option>
1534 <option value="1" selected><?php xl('Optional', 'e'); ?></option>
1535 <option value="2"><?php xl('Required', 'e'); ?></option>
1536 </select>
1537 </td>
1538 <td align='center'>
1539 <select class='form-control' name='newdatatype' id='newdatatype'>
1540 <option value=''></option>
1541 <?php
1542 global $datatypes;
1543 foreach ($datatypes as $key => $value) {
1544 echo " <option value='$key'>$value</option>\n";
1547 </select>
1548 </td>
1549 <td><input type="text" name="newlengthWidth" id="newlengthWidth" value="" size="1" maxlength="3" title="<?php echo xla('Width'); ?>">
1550 <input type="text" name="newlengthHeight" id="newlengthHeight" value="" size="1" maxlength="3" title="<?php echo xla('Height'); ?>"></td>
1551 <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>
1552 <td><input type="text" name="newlistid" id="newlistid" value="" size="8" maxlength="31" class="listid">
1553 <select class='form-control' name='contextName' id='contextName' style='display:none'>
1554 <?php
1555 $res = sqlStatement("SELECT * FROM customlists WHERE cl_list_type=2 AND cl_deleted=0");
1556 while ($row = sqlFetchArray($res)) {
1557 echo "<option value='".htmlspecialchars($row['cl_list_item_long'], ENT_QUOTES)."'>".htmlspecialchars($row['cl_list_item_long'], ENT_QUOTES)."</option>";
1560 </select>
1561 </td>
1562 <td><input type="text" name="newbackuplistid" id="newbackuplistid" value="" size="8" maxlength="31" class="listid"></td>
1563 <td><input type="text" name="newtitlecols" id="newtitlecols" value="" size="3" maxlength="3"> </td>
1564 <td><input type="text" name="newdatacols" id="newdatacols" value="" size="3" maxlength="3"> </td>
1565 <td><select name="newedit_options[]" id="newedit_options" multiple class='typeAddons' style='width:100%'></select>
1566 <input type="hidden" name="newdefault" id="newdefault" value="" /> </td>
1567 <td><input type="text" name="newdesc" id="newdesc" value="" size="30"> </td>
1568 </tr>
1569 <tr>
1570 <td colspan="9">
1571 <input type="button" class="savenewfield" value=<?php xl('Save New Field', 'e', '\'', '\''); ?>>
1572 <input type="button" class="cancelnewfield" value=<?php xl('Cancel', 'e', '\'', '\''); ?>>
1573 </td>
1574 </tr>
1575 </tbody>
1576 </table>
1577 </div>
1578 </div>
1579 </body>
1581 <script>
1582 /* Field modifier objects - heading towards context based.
1583 Used by Select2 so rtl may be enabled*/
1584 <?php echo "var fldOptions = [
1585 {id: 'A',text:'" . xla('Age') . "',ctx:['4'],ctxExcp:['0']},
1586 {id: 'B',text:'" . xla('Gestational Age') . "',ctx:['4'],ctxExcp:['0']},
1587 {id: 'F',text:'" . xla('Add Time to Date') . "',ctx:['4'],ctxExcp:['0']},
1588 {id: 'C',text:'" . xla('Capitalize') . "',ctx:['0'],ctxExcp:['4','15','40']},
1589 {id: 'D',text:'" . xla('Dup Check') . "'},
1590 {id: 'E',text:'" . xla('Dup Check on only Edit') . "'},
1591 {id: 'W',text:'" . xla('Dup Check on only New') . "'},
1592 {id: 'G',text:'" . xla('Graphable') . "'},
1593 {id: 'I',text:'" . xla('Initially Open Group') . "'},
1594 {id: 'L',text:'" . xla('Lab Order') . "'},
1595 {id: 'N',text:'" . xla('New Patient Form') . "'},
1596 {id: 'O',text:'" . xla('Order Processor') . "'},
1597 {id: 'P',text:'" . xla('Default to previous value') . "'},
1598 {id: 'R',text:'" . xla('Distributor') . "'},
1599 {id: 'T',text:'" . xla('Description is default text') . "'},
1600 {id: 'U',text:'" . xla('Capitalize all') . "'},
1601 {id: 'V',text:'" . xla('Vendor') . "'},
1602 {id: 'X',text:'" . xla('Do Not Print') . "'},
1603 {id: '0',text:'" . xla('Read Only') . "'},
1604 {id: '1',text:'" . xla('Write Once') . "'},
1605 {id: '2',text:'" . xla('Billing Code Descriptions') . "'}];\n";
1607 // Language direction for select2
1608 echo 'var langDirection = "' . $_SESSION['language_direction'] . '";';
1611 // used when selecting a list-name for a field
1612 var selectedfield;
1614 // Support for beforeunload handler.
1615 var somethingChanged = false;
1617 // Get the next logical sequence number for a field in the specified group.
1618 // Note it guesses and uses the existing increment value.
1619 function getNextSeq(group) {
1620 var f = document.forms[0];
1621 var seq = 0;
1622 var delta = 10;
1623 for (var i = 1; true; ++i) {
1624 var gelem = f['fld[' + i + '][group]'];
1625 if (!gelem) break;
1626 if (gelem.value != group) continue;
1627 var tmp = parseInt(f['fld[' + i + '][seq]'].value);
1628 if (isNaN(tmp)) continue;
1629 if (tmp <= seq) continue;
1630 delta = tmp - seq;
1631 seq = tmp;
1633 return seq + delta;
1636 // jQuery stuff to make the page a little easier to use
1638 $(document).ready(function(){
1640 $(function () {
1641 $('.typeAddons').select2({
1642 data: fldOptions,
1643 theme: 'default',
1644 multiple: true,
1645 closeOnSelect: false,
1646 width:'100%',
1647 minimumResultsForSearch: 'Infinity',
1648 containerCssClass: ':all:',
1649 dir: langDirection,
1650 allowClear: false
1653 // Populate field option selects
1654 $(function() {
1655 $('.typeAddons').each(function(i, obj) {
1656 var v = $(this).data('set')
1657 if(typeof v !== 'undefined' && v > ""){
1658 $(this).select2().val(v).trigger("change")
1661 somethingChanged = false;
1664 $("#save").click(function() { SaveChanges(); });
1665 $("#layout_id").change(function() {
1666 if (!myChangeCheck()) {
1667 $("#layout_id").val("<?php echo $layout_id; ?>");
1668 return;
1670 mySubmit();
1672 $(".addgroup").click(function() { AddGroup(this); });
1673 $(".savenewgroup").click(function() { SaveNewGroup(this); });
1674 /******************************************************************
1675 $(".deletegroup").click(function() { DeleteGroup(this); });
1676 ******************************************************************/
1677 $(".cancelnewgroup").click(function() { CancelNewGroup(this); });
1678 $(".movegroup").click(function() { MoveGroup(this); });
1679 $(".renamegroup").click(function() { RenameGroup(this); });
1680 $(".saverenamegroup").click(function() { SaveRenameGroup(this); });
1681 $(".cancelrenamegroup").click(function() { CancelRenameGroup(this); });
1682 $(".addfield").click(function() { AddField(this); });
1683 $("#deletefields").click(function() { DeleteFields(this); });
1684 $(".selectfield").click(function() {
1685 var TRparent = $(this).parent().parent();
1686 $(TRparent).children("td").toggleClass("highlight");
1687 // disable the delete-move buttons
1688 $("#deletefields").attr("disabled", "disabled");
1689 $("#movefields").attr("disabled", "disabled");
1690 $(".selectfield").each(function(i) {
1691 // if any field is selected, enable the delete-move buttons
1692 if ($(this).prop("checked") == true) {
1693 $("#deletefields").removeAttr("disabled");
1694 $("#movefields").removeAttr("disabled");
1699 $("#movefields").click(function() { ShowGroups(this); });
1700 $(".savenewfield").click(function() { SaveNewField(this); });
1701 $(".cancelnewfield").click(function() { CancelNewField(this); });
1702 $("#newtitle").blur(function() { if ($("#newid").val() == "") $("#newid").val($("#newtitle").val()); });
1703 $("#newdatatype").change(function() { ChangeList(this.value);});
1704 $("#gnewdatatype").change(function() { ChangeListg(this.value);});
1705 $(".listid").click(function() { ShowLists(this); });
1707 // special class that skips the element
1708 $(".noselect").focus(function() { $(this).blur(); });
1710 // Save the changes made to the form
1711 var SaveChanges = function () {
1712 var f = document.forms[0];
1713 for (var i = 1; f['fld['+i+'][id]']; ++i) {
1714 var ival = f['fld['+i+'][id]'].value;
1715 for (var j = i + 1; f['fld['+j+'][id]']; ++j) {
1716 if (ival == f['fld['+j+'][id]'].value || ival == f['fld['+j+'][originalid]'].value) {
1717 alert('<?php echo xls('Error: Duplicated field ID'); ?>: ' + ival);
1718 return;
1722 $("#formaction").val("save");
1723 mySubmit();
1726 /****************************************************/
1727 /************ Group functions ***********************/
1728 /****************************************************/
1730 // display the 'new group' DIV
1731 var AddGroup = function(btnObj) {
1732 if (!myChangeCheck()) return;
1733 $("#save").attr("disabled", true);
1734 // show the field details DIV
1735 $('#groupdetail').css('visibility', 'visible');
1736 $('#groupdetail').css('display', 'block');
1737 $(btnObj).parent().append($("#groupdetail"));
1738 $('#groupdetail > #newgroupname').focus();
1739 // Assign a sensible default sequence number.
1740 $('#gnewseq').val(10);
1743 // save the new group to the form
1744 var SaveNewGroup = function(btnObj) {
1745 // the group name field can only have letters, numbers, spaces and underscores
1746 // AND it cannot start with a number
1747 if ($("#newgroupname").val() == "") {
1748 alert("<?php xl('Group names cannot be blank', 'e'); ?>");
1749 return false;
1751 if ($("#newgroupname").val().match(/^(\d+|\s+)/)) {
1752 alert("<?php xl('Group names cannot start with numbers or spaces.', 'e'); ?>");
1753 return false;
1755 var validname = $("#newgroupname").val().replace(/[^A-za-z0-9 ]/g, "_"); // match any non-word characters and replace them
1756 $("#newgroupname").val(validname);
1758 // now, check the first group field values
1760 // seq must be numeric and <= 9999
1761 if (! IsNumeric($("#gnewseq").val(), 0, 9999)) {
1762 alert("<?php xl('Order must be a number between 1 and 9999', 'e'); ?>");
1763 return false;
1765 // length must be numeric and less than 999
1766 if (! IsNumeric($("#gnewlengthWidth").val(), 0, 999)) {
1767 alert("<?php xl('Size must be a number between 1 and 999', 'e'); ?>");
1768 return false;
1770 // titlecols must be numeric and less than 100
1771 if (! IsNumeric($("#gnewtitlecols").val(), 0, 999)) {
1772 alert("<?php xl('LabelCols must be a number between 1 and 999', 'e'); ?>");
1773 return false;
1775 // datacols must be numeric and less than 100
1776 if (! IsNumeric($("#gnewdatacols").val(), 0, 999)) {
1777 alert("<?php xl('DataCols must be a number between 1 and 999', 'e'); ?>");
1778 return false;
1780 // the id field can only have letters, numbers and underscores
1781 if ($("#gnewid").val() == "") {
1782 alert("<?php xl('ID cannot be blank', 'e'); ?>");
1783 return false;
1785 var validid = $("#gnewid").val().replace(/(\s|\W)/g, "_"); // match any non-word characters and replace them
1786 $("#gnewid").val(validid);
1787 // similarly with the listid field
1788 validid = $("#gnewlistid").val().replace(/(\s|\W)/g, "_");
1789 $("#gnewlistid").val(validid);
1790 // similarly with the backuplistid field
1791 validid = $("#gnewbackuplistid").val().replace(/(\s|\W)/g, "_");
1792 $("#gnewbackuplistid").val(validid);
1795 // submit the form to add a new field to a specific group
1796 $("#formaction").val("addgroup");
1797 mySubmit();
1800 /******************************************************************
1801 // actually delete an entire group from the database
1802 var DeleteGroup = function(btnObj) {
1803 var parts = $(btnObj).attr("id");
1804 var groupname = parts.replace(/^\d+/, "");
1805 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+"'?")) {
1806 // submit the form to add a new field to a specific group
1807 $("#formaction").val("deletegroup");
1808 $("#deletegroupname").val(parts);
1809 $("#theform").submit();
1812 ******************************************************************/
1814 // just hide the new field DIV
1815 var CancelNewGroup = function(btnObj) {
1816 // hide the field details DIV
1817 $('#groupdetail').css('visibility', 'hidden');
1818 $('#groupdetail').css('display', 'none');
1819 // reset the new group values to a default
1820 $('#groupdetail > #newgroupname').val("");
1821 $('#groupdetail > #newgroupparent').val("");
1822 $("#save").attr("disabled", false);
1825 // display the 'new field' DIV
1826 var MoveGroup = function(btnObj) {
1827 if (!myChangeCheck()) return;
1828 var btnid = $(btnObj).attr("id");
1829 var parts = btnid.split("~");
1830 var groupid = parts[0];
1831 var direction = parts[1];
1832 // submit the form to change group order
1833 $("#formaction").val("movegroup");
1834 $("#movegroupname").val(groupid);
1835 $("#movedirection").val(direction);
1836 mySubmit();
1839 // show the rename group DIV
1840 var RenameGroup = function(btnObj) {
1841 if (!myChangeCheck()) return;
1842 $("#save").attr("disabled", true);
1843 $('#renamegroupdetail').css('visibility', 'visible');
1844 $('#renamegroupdetail').css('display', 'block');
1845 $(btnObj).parent().append($("#renamegroupdetail"));
1846 var parts = $(btnObj).attr("id").split("~");
1847 $('#renameoldgroupname').val(parts[0]); // this is actually the existing group ID
1848 $('#renamegroupname').val(parts[1]); // the textual name of just this group
1849 var i = parts[0].length;
1850 $('[name=renamegroupparent]').val(i > 0 ? parts[0].substr(0, i-1) : ''); // parent ID
1853 // save the new group to the form
1854 var SaveRenameGroup = function(btnObj) {
1855 // the group name field can only have letters, numbers, spaces and underscores
1856 // AND it cannot start with a number
1857 if ($("#renamegroupname").val().match(/^\d+/)) {
1858 alert("<?php xl('Group names cannot start with numbers.', 'e'); ?>");
1859 return false;
1861 var validname = $("#renamegroupname").val().replace(/[^A-za-z0-9 ]/g, "_"); // match any non-word characters and replace them
1862 $("#renamegroupname").val(validname);
1864 // submit the form to add a new field to a specific group
1865 $("#formaction").val("renamegroup");
1866 mySubmit();
1869 // just hide the new field DIV
1870 var CancelRenameGroup = function(btnObj) {
1871 // hide the field details DIV
1872 $('#renamegroupdetail').css('visibility', 'hidden');
1873 $('#renamegroupdetail').css('display', 'none');
1874 // reset the rename group values to a default
1875 $('#renameoldgroupname').val("");
1876 $('#renamegroupname').val("");
1877 $('#renamegroupparent').val("");
1880 /****************************************************/
1881 /************ Field functions ***********************/
1882 /****************************************************/
1884 // display the 'new field' DIV
1885 var AddField = function(btnObj) {
1886 if (!myChangeCheck()) return;
1887 $("#save").attr("disabled", true);
1888 // update the fieldgroup value to be the groupid
1889 var btnid = $(btnObj).attr("id");
1890 var parts = btnid.split("~");
1891 var groupid = parts[1];
1892 $('#fielddetail > #newfieldgroupid').attr('value', groupid);
1893 // show the field details DIV
1894 $('#fielddetail').css('visibility', 'visible');
1895 $('#fielddetail').css('display', 'block');
1896 $(btnObj).parent().append($("#fielddetail"));
1897 // Assign a sensible default sequence number.
1898 $('#newseq').val(getNextSeq(groupid));
1901 var DeleteFields = function(btnObj) {
1902 if (!myChangeCheck()) return;
1903 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'); ?>")) {
1904 var delim = "";
1905 $(".selectfield").each(function(i) {
1906 // build a list of selected field names to be moved
1907 if ($(this).prop("checked")) {
1908 var parts = this.id.split("~");
1909 var currval = $("#selectedfields").val();
1910 $("#selectedfields").val(currval+delim+parts[1]);
1911 delim = " ";
1914 // submit the form to delete the field(s)
1915 $("#formaction").val("deletefields");
1916 mySubmit();
1920 // save the new field to the form
1921 var SaveNewField = function(btnObj) {
1922 // check the new field values for correct formatting
1924 // seq must be numeric and <= 9999
1925 if (! IsNumeric($("#newseq").val(), 0, 9999)) {
1926 alert("<?php xl('Order must be a number between 1 and 9999', 'e'); ?>");
1927 return false;
1929 // length must be numeric and less than 999
1930 if (! IsNumeric($("#newlengthWidth").val(), 0, 999)) {
1931 alert("<?php xl('Size must be a number between 1 and 999', 'e'); ?>");
1932 return false;
1934 // titlecols must be numeric and less than 100
1935 if (! IsNumeric($("#newtitlecols").val(), 0, 999)) {
1936 alert("<?php xl('LabelCols must be a number between 1 and 999', 'e'); ?>");
1937 return false;
1939 // datacols must be numeric and less than 100
1940 if (! IsNumeric($("#newdatacols").val(), 0, 999)) {
1941 alert("<?php xl('DataCols must be a number between 1 and 999', 'e'); ?>");
1942 return false;
1944 // the id field can only have letters, numbers and underscores
1945 var validid = $("#newid").val().replace(/(\s|\W)/g, "_"); // match any non-word characters and replace them
1946 $("#newid").val(validid);
1947 // similarly with the listid field
1948 validid = $("#newlistid").val().replace(/(\s|\W)/g, "_");
1949 $("#newlistid").val(validid);
1950 // similarly with the backuplistid field
1951 validid = $("#newbackuplistid").val().replace(/(\s|\W)/g, "_");
1952 $("#newbackuplistid").val(validid);
1954 // submit the form to add a new field to a specific group
1955 $("#formaction").val("addfield");
1956 mySubmit();
1959 // just hide the new field DIV
1960 var CancelNewField = function(btnObj) {
1961 // hide the field details DIV
1962 $('#fielddetail').css('visibility', 'hidden');
1963 $('#fielddetail').css('display', 'none');
1964 // reset the new field values to a default
1965 ResetNewFieldValues();
1966 $("#save").attr("disabled", false);
1969 // show the popup choice of lists
1970 var ShowLists = function(btnObj) {
1971 window.open('../patient_file/encounter/find_code_dynamic.php?what=lists',
1972 'lists', 'width=700,height=600,scrollbars=yes');
1973 selectedfield = btnObj;
1976 // show the popup choice of groups
1977 var ShowGroups = function(btnObj) {
1978 if (!myChangeCheck()) return;
1979 window.open('../patient_file/encounter/find_code_dynamic.php?what=groups&layout_id=<?php echo addslashes($layout_id); ?>',
1980 'groups', 'width=700,height=600,scrollbars=yes');
1983 // Show context DD for NationNotes
1984 var ChangeList = function(btnObj){
1985 if(btnObj==34){
1986 $('#newlistid').hide();
1987 $('#contextName').show();
1989 else{
1990 $('#newlistid').show();
1991 $('#contextName').hide();
1994 var ChangeListg = function(btnObj){
1995 if(btnObj==34){
1996 $('#gnewlistid').hide();
1997 $('#gcontextName').show();
1999 else{
2000 $('#gnewlistid').show();
2001 $('#gcontextName').hide();
2005 // Initialize list item selectors and value field visibilities in skip conditions.
2006 var f = document.forms[0];
2007 for (var lino = 1; f['fld[' + lino + '][id]']; ++lino) {
2008 for (var seq = 0; f['fld[' + lino + '][condition_itemid][' + seq + ']']; ++seq) {
2009 setListItemOptions(lino, seq, true);
2011 actionChanged(lino);
2014 // Support for beforeunload handler.
2015 $('tbody input, tbody select, tbody textarea').not('.selectfield').change(function() {
2016 somethingChanged = true;
2018 window.addEventListener("beforeunload", function (e) {
2019 if (somethingChanged && !top.timed_out) {
2020 var msg = "<?php echo xls('You have unsaved changes.'); ?>";
2021 e.returnValue = msg; // Gecko, Trident, Chrome 34+
2022 return msg; // Gecko, WebKit, Chrome <34
2026 }); /* Ready Done */
2028 function NationNotesContext(lineitem,val){
2029 if(val==34){
2030 document.getElementById("fld["+lineitem+"][contextName]").style.display='';
2031 document.getElementById("fld["+lineitem+"][list_id]").style.display='none';
2032 document.getElementById("fld["+lineitem+"][list_id]").value='';
2034 else{
2035 document.getElementById("fld["+lineitem+"][list_id]").style.display='';
2036 document.getElementById("fld["+lineitem+"][contextName]").style.display='none';
2037 document.getElementById("fld["+lineitem+"][list_id]").value='';
2041 function SetList(listid) {
2042 $(selectedfield).val(listid);
2045 //////////////////////////////////////////////////////////////////////
2046 // The following supports the field ID selection pop-up.
2047 //////////////////////////////////////////////////////////////////////
2049 var fieldselectfield;
2051 function elemFromPart(part) {
2052 var ename = fieldselectfield.name;
2053 // ename is like one of the following:
2054 // fld[$fld_line_no][id]
2055 // gnewid
2056 // newid
2057 // and "part" is what we substitute for the "id" part.
2058 var i = ename.lastIndexOf('id');
2059 ename = ename.substr(0, i) + part + ename.substr(i+2);
2060 return document.forms[0][ename];
2063 function FieldIDClicked(elem) {
2064 <?php if (substr($layout_id, 0, 3) == 'LBF') { ?>
2065 fieldselectfield = elem;
2066 var srcval = elemFromPart('source').value;
2067 // If the field ID is for the local form, allow direct entry.
2068 if (srcval == 'F') return;
2069 // Otherwise pop up the selection window.
2070 window.open('../patient_file/encounter/find_code_dynamic.php?what=fields&source='
2071 + srcval, 'fields', 'width=700,height=600,scrollbars=yes');
2072 <?php } ?>
2075 function SetField(field_id, title, data_type, uor, fld_length, max_length,
2076 list_id, titlecols, datacols, edit_options, description, fld_rows)
2078 fieldselectfield.value = field_id;
2079 elemFromPart('title' ).value = title;
2080 elemFromPart('datatype' ).value = data_type;
2081 elemFromPart('uor' ).value = uor;
2082 elemFromPart('lengthWidth' ).value = fld_length;
2083 elemFromPart('maxSize' ).value = max_length;
2084 elemFromPart('list_id' ).value = list_id;
2085 elemFromPart('titlecols' ).value = titlecols;
2086 elemFromPart('datacols' ).value = datacols;
2087 elemFromPart('edit_options').value = edit_options;
2088 elemFromPart('desc' ).value = description;
2089 elemFromPart('lengthHeight').value = fld_rows;
2092 //////////////////////////////////////////////////////////////////////
2093 // End code for field ID selection pop-up.
2094 //////////////////////////////////////////////////////////////////////
2096 /* this is called after the user chooses a new group from the popup window
2097 * it will submit the page so the selected fields can be moved into
2098 * the target group
2100 function MoveFields(targetgroup) {
2101 $("#targetgroup").val(targetgroup);
2102 var delim = "";
2103 $(".selectfield").each(function(i) {
2104 // build a list of selected field names to be moved
2105 if ($(this).prop("checked")) {
2106 var parts = this.id.split("~");
2107 var currval = $("#selectedfields").val();
2108 $("#selectedfields").val(currval+delim+parts[1]);
2109 delim = " ";
2112 $("#formaction").val("movefields");
2113 mySubmit();
2116 // set the new-field values to a default state
2117 function ResetNewFieldValues () {
2118 $("#newseq").val("");
2119 $("#newsource").val("");
2120 $("#newid").val("");
2121 $("#newtitle").val("");
2122 $("#newuor").val(1);
2123 $("#newlengthWidth").val("");
2124 $("#newlengthHeight").val("");
2125 $("#newmaxSize").val("");
2126 $("#newdatatype").val("");
2127 $("#newlistid").val("");
2128 $("#newbackuplistid").val("");
2129 $("#newtitlecols").val("");
2130 $("#newdatacols").val("");
2131 $("#newedit_options").val("");
2132 $("#newdefault").val("");
2133 $("#newdesc").val("");
2136 // is value an integer and between min and max
2137 function IsNumeric(value, min, max) {
2138 if (value == "" || value == null) return false;
2139 if (! IsN(value) ||
2140 parseInt(value) < min ||
2141 parseInt(value) > max)
2142 return false;
2144 return true;
2147 /****************************************************/
2148 /****************************************************/
2149 /****************************************************/
2151 // tell if num is an Integer
2152 function IsN(num) { return !/\D/.test(num); }
2154 </script>
2156 </html>