'select', // Type * 'name' => 'Search By', // Displayed title for item * 'id' => 'searchby', // Item id and name * 'width' => '120px', // (Optional) Item width * 'size' => '15', // (Optional) Maximum number of items to show in the menu (default 15) * 'value' => $vars['searchby'], // (Optional) Current value(-s) for item * 'values' => array('mac' => 'MAC Address', * 'ip' => 'IP Address')); // Array with option items * - array for 'multiselect' item type (array keys same as above) * $search[] = array('type' => 'multiselect', * 'name' => 'Priorities', * 'id' => 'priority', * 'width' => '150px', * 'subtext' => TRUE, // (Optional) Display items value right of the item name * 'encode' => FALSE, // (Optional) Use var_encode for values, use when values contains commas or empty string * 'value' => $vars['priority'], * 'values' => $priorities); * - array for 'text' or 'input' item type * $search[] = array('type' => 'text', * 'name' => 'Address', * 'id' => 'address', * 'width' => '120px', * 'placeholder' => FALSE, // (Optional) Display item name as pleseholder or left relatively input * 'value' => $vars['address']); * - array for 'datetime' item type * $search[] = array('type' => 'datetime', * 'id' => 'timestamp', * 'presets' => TRUE, // (optional) Show select field with timerange presets * 'min' => dbFetchCell('SELECT MIN(`timestamp`) FROM `syslog`'), // (optional) Minimum allowed date/time * 'max' => dbFetchCell('SELECT MAX(`timestamp`) FROM `syslog`'), // (optional) Maximum allowed date/time * 'from' => $vars['timestamp_from'], // (optional) Current 'from' value * 'to' => $vars['timestamp_to']); // (optional) Current 'to' value * - array for 'sort' item pseudo type * $search[] = array('type' => 'sort', * 'value' => $vars['sort'], * 'values' => $sorts); * - array for 'newline' item pseudo type * $search[] = array('type' => 'newline', * 'hr' => FALSE); // (optional) show or not horizontal line * print_search($search, 'Title here', 'search', url); * * @param array $data * @param string|null $title * @param string $button * @param string|null $url * * @return void */ function print_search($data, $title = NULL, $button = 'search', $url = NULL) { // Cache permissions to session var permissions_cache_session(); //r($_SESSION['cache']); $submit_by_key = FALSE; $string_items = ''; foreach ($data as $item) { if ($url && isset($item['id'])) { // Remove old vars from url $url = preg_replace('/' . $item['id'] . '=[^\/]+\/?/', '', $url); } if ($item['type'] === 'sort') { $sort = $item; continue; } if (isset($item['submit_by_key']) && $item['submit_by_key']) { $submit_by_key = TRUE; } $string_items .= generate_form_element($item); } $form_id = 'search-' . random_string('4'); if ($submit_by_key) { $action = ''; if ($url) { $action .= 'this.form.prop(\'action\', form_to_path(\'' . $form_id . '\'));'; } register_html_resource('script', '$(function(){$(\'form#' . $form_id . '\').each(function(){$(this).find(\'input\').keypress(function(e){if(e.which==10||e.which==13){' . $action . 'this.form.submit();}});});});'); } // Form header $string = PHP_EOL . '' . PHP_EOL; $string .= '
' . PHP_EOL; $string .= '
' . PHP_EOL; $string .= '' . PHP_EOL . PHP_EOL; // Print search form echo($string); } /** * Calculate and store default grid sizes for form rows based on the given data. * * @param array $data Input data containing form row and element information */ function form_grid_calculate(&$data) { // Calculate grid sizes for rows foreach ($data['row'] as $k => $row) { $row_count = safe_count($row); // Default (auto) grid size for elements $row_grid = (int)(12 / $row_count); $grid_count = 0; // Count for custom passed grid sizes foreach ($row as $id => $element) { if (isset($element['div_class']) && preg_match('/col-(?:lg|md|sm)-(\d+)/', $element['div_class'], $matches)) { // Class with col size passed $grid_count += (int)$matches[1]; } elseif (isset($element['grid'])) { // Grid size passed if ($element['grid'] > 0 && $element['grid'] <= 12) { $grid_count += (int)$element['grid']; } else { // Incorrect size unset($row[$k]['grid']); } } } $row_grid = 12 - $grid_count; // Free grid size after custom grid $row_grid = (int)($row_grid / $row_count); // Default (auto) grid size for elements if ($grid_count > 2 && $row_grid < 1) { $row_grid = 1; } // minimum 1 for auto if custom grid passed elseif ($row_grid < 2) { $row_grid = 2; } // minimum 2 for auto $data['grid'][$k] = $row_grid; // Store default grid size for row } } /** * Helper function for print_form() to gen initial form options. * * @param array $data * @param array $form_options * @return array */ function form_init($data, &$form_options = []) { $form_id = $data['id'] ?? 'form-' . random_string(); $form_class = str_starts_with($data['type'], 'horizontal') ? 'form form-horizontal' : 'form form-inline'; // default for rows and simple $form_style = $data['style'] ?? 'margin-bottom: 0px;'; $form_style = ' style="' . $form_style . '"'; $base_class = array_key_exists('class', $data) ? $data['class'] : OBS_CLASS_BOX; $base_space = $data['space'] ?: '5px'; // Cache permissions to session var permissions_cache_session(); if ($data['submit_json']) { register_html_resource('js', 'js/jquery.serializejson.min.js'); //register_html_resource('script', '$(\'form#'.$form_id.'\').serializeJSON({checkboxUncheckedValue: 0});'); //$data['onsubmit'] = 'processForm()'; register_html_resource('script', '$("form#' . $form_id . '").submit(processForm);'); } elseif ($data['submit_by_key']) { $action = ''; if ($data['url']) { $action .= 'this.form.prop("action", form_to_path("' . $form_id . '"));'; } register_html_resource('script', ' $(document).ready(function() { $("form#' . $form_id . '").on("keypress", "input", function(e) { if (e.which === 10 || e.which === 13) { ' . $action . ' this.form.submit(); } }); }); '); } $form_options = [ 'form_id' => $form_id, 'form_class' => $form_class, 'form_style' => $form_style, 'base_class' => $base_class, 'base_space' => $base_space ]; return $form_options; } /** * Helper function for print_form() to generate start/end div blocks. * * @param array $data * @param array $form_options * @return array */ function form_div($data, &$form_options) { if ($data['type'] === 'horizontal-rows') { $form_options['base_space'] = $data['space'] ?: '10px'; $header = ''; if (isset($data['title'])) { // FIXME. Need better header $header .= '

' . escape_html($data['title']) . '

' . PHP_EOL; } $form_options['div_begin'] = $header; $form_options['div_end'] = ''; return $form_options; } if (!in_array($data['type'], [ 'rows', 'horizontal' ])) { // Simple form, without any divs, sees example in html/pages/user_edit.inc.php $form_options['div_begin'] = ''; $form_options['div_end'] = ''; return $form_options; } if (empty($form_options['base_class'])) { // Clean class // Example in html/pages.logon.inc.php $form_options['div_begin'] = PHP_EOL; $form_options['div_end'] = PHP_EOL; return $form_options; } if (str_contains_array($form_options['base_class'], [ 'widget', 'box' ])) { $base_space = $data['space'] ?: '10px'; $padding = $data['type'] === 'horizontal' ? 'padding-top: ' : 'padding: '; $box_args = [ 'id' => 'box-' . $form_options['form_id'], 'header-border' => TRUE, 'body-style' => $padding . $base_space . ' !important;' ]; if (isset($data['title'])) { $box_args['title'] = $data['title']; } $form_options['div_begin'] = generate_box_open($box_args); $form_options['div_end'] = generate_box_close(); return $form_options; } // Old box box-solid style (or any custom style) $div_begin = '
' . PHP_EOL; if (isset($data['title'])) { $div_begin .= '
'; $div_begin .= get_icon($data['icon']); $div_begin .= ' ' . escape_html($data['title']) . '
' . PHP_EOL; } $form_options['div_begin'] = $div_begin; $form_options['div_end'] = '
' . PHP_EOL; return $form_options; } /** * Helper function for print_form() to generate rows form. * * @param array $data * @param array $form_options * @param array $used_vars * @return string */ function form_rows($data, $form_options, &$used_vars = []) { $row_style = ''; $string_elements = ''; form_grid_calculate($data); foreach ($data['row'] as $k => $row) { $row_class = 'row'; if (isset($data['row_options'][$k]) && $data['row_options'][$k]['class']) { $row_class .= ' ' . $data['row_options'][$k]['class']; } $string_elements .= '
' . PHP_EOL; foreach ($row as $id => $element) { $used_vars[] = $id; $element['id'] = $id; // Default class with default row grid size or passed from options $grid = $element['grid'] ?? $data['grid'][$k]; $div_class = 'col-lg-' . $grid . ' col-md-' . $grid . ' col-sm-' . $grid; // By default, xs grid always 12 if (isset($element['grid_xs']) && $element['grid_xs'] > 0 && $element['grid_xs'] <= 12) { $div_class .= ' col-xs-' . $element['grid_xs']; } if (empty($element['div_class'])) { $element['div_class'] = $div_class; } elseif (isset($element['grid']) && !preg_match('/col-(?:lg|md|sm|xs)-(\d+)/', $element['div_class'])) { // Combine if passed both: grid size and div_class (and class not has col-* grid elements) $element['div_class'] = $div_class . ' ' . $element['div_class']; } if ($element['right']) { $element['div_class'] .= ' col-lg-push-0 col-md-push-0 col-sm-push-0'; } if ($id === 'search') { // Add form_id here, for generate onclick action in submit button if ($data['url']) { $element['form_id'] = $form_options['form_id']; } } else { // all other cases add form_id $element['form_id'] = $form_options['form_id']; } $string_elements .= '
' . PHP_EOL; // Add space between rows $row_style = 'style="margin-top: ' . $form_options['base_space'] . ';"'; } return $string_elements; } /** * Helper function for print_form() to generate horizontal (and horizontal-rows) form. * * @param array $data * @param array $form_options * @param array $used_vars * @return string */ function form_horizontal($data, $form_options, &$used_vars = []) { $horizontal_rows = str_ends_with($data['type'], 'rows'); $row_control_style = !$horizontal_rows ? 'style="margin-bottom: ' . $form_options['base_space'] . ';"' : ''; $fieldset = []; foreach ($data['row'] as $k => $row) { $first_key = key($row); $row_group = $k; $row_elements = ''; $row_label = ''; $row_control_group = FALSE; $i = 0; foreach ($row as $id => $element) { $used_vars[] = $id; $element['id'] = $id; if ($element['fieldset']) { $row_group = $element['fieldset']; // Add this element to group } // Additional element options for horizontal specific form $div_style = ''; $div_class = ''; switch ($element['type']) { case 'hidden': break; case 'submit': $div_class = 'form-actions'; break; case 'text': case 'input': case 'password': case 'textarea': default: $row_control_group = TRUE; // In horizontal, first element name always placed at left if (!isset($element['placeholder'])) { $element['placeholder'] = TRUE; } // offset == FALSE disable label width and align class control-label if (!isset($element['offset'])) { if (isset($data['fieldset'][$element['fieldset']]['offset'])) { // Copy from fieldset $element['offset'] = $data['fieldset'][$element['fieldset']]['offset']; } elseif (($element['type'] === 'raw' || $element['type'] === 'html') && !isset($element['name']) && $first_key === $id) { // When raw/html element first, disable offset $element['offset'] = FALSE; } else { // Default $element['offset'] = TRUE; } } if ($i < 1) { // Add label for first element in row if ($element['name']) { $row_label = ' ' . $element['name'] . '' . PHP_EOL; } $row_control_id = $element['id'] . '_div'; if ($element['type'] === 'datetime') { $element['name'] = ''; } } // nextrow class element to new line (after label) $div_class = $element['offset'] ? 'controls' : 'nextrow'; break; } if (!isset($element['div_class'])) { $element['div_class'] = $div_class; } if ($element['div_class'] === 'form-actions') { // Remove margins only for form-actions elements $div_style = 'margin: 0px;'; } //if ($element['right']) //{ // $element['div_class'] .= ' pull-right'; //} if (isset($element['div_style'])) { $div_style .= ' ' . $element['div_style']; } if ($id === 'search') { // Add form_id here, for generate onclick action in submitted button if ($data['url']) { $element['form_id'] = $form_options['form_id']; } } else { // all other cases add form_id $element['form_id'] = $form_options['form_id']; } $row_elements .= generate_form_element($element); $i++; } if ($element['div_class']) { // no additional divs if empty div class (hidden element, for example) $row_begin = $row_label . PHP_EOL . '
' . PHP_EOL . $row_elements . '
' . PHP_EOL; } else { $row_label = str_replace(' class="control-label"', '', $row_label); $row_elements = $row_label . PHP_EOL . $row_elements; } if ($row_control_group) { $fieldset[$row_group] .= '
' . PHP_EOL; $fieldset[$row_group] .= $row_elements; $fieldset[$row_group] .= '
' . PHP_EOL; } else { // Do not add a control group for submit/hidden $fieldset[$row_group] .= $row_elements; } //$row_style = 'style="margin-top: '.$base_space.';"'; // Add space between rows } if ($horizontal_rows) { form_horizontal_rows_fieldset($data, $form_options, $fieldset); } else { form_horizontal_fieldset($data, $form_options, $fieldset); } // Final combining elements return implode('', $fieldset); } /** * Helper function for form_horizontal() to generate fieldset. * * @param array $data * @param array $form_options * @param array $fieldset * @return array */ function form_horizontal_fieldset($data, $form_options, &$fieldset = []) { foreach ($data['fieldset'] as $row_group => $entry) { if (isset($fieldset[$row_group])) { if (!is_array($entry)) { $entry = [ 'title' => $entry ]; } $fieldset_begin = ''; $fieldset_end = ''; // Additional div class if set if (isset($entry['class'])) { $fieldset_begin = '
' . PHP_EOL . $fieldset_begin; $fieldset_end .= '
' . PHP_EOL; } $row_elements = $fieldset_begin . '
'; if (!empty($entry['title'])) { // fieldset title $row_elements .= '

' . escape_html($entry['title']) . '

'; } $row_elements .= PHP_EOL . $fieldset[$row_group] . '
' . PHP_EOL; $fieldset[$row_group] = $row_elements . $fieldset_end; } } return $fieldset; } /** * Helper function for form_horizontal() * to generate fieldset specific for horizontal-rows (and print_form_box() function). * * @param array $data * @param array $form_options * @param array $fieldset * @return array */ function form_horizontal_rows_fieldset($data, &$form_options, &$fieldset = []) { $div_begin = '
' . PHP_EOL; $div_end = '
' . PHP_EOL; $divs = []; $fieldset_tooltip = ''; foreach ($data['fieldset'] as $group => $entry) { if (isset($fieldset[$group])) { if (!is_array($entry)) { $entry = ['title' => $entry]; } // Custom style if (!isset($entry['style'])) { $entry['style'] = 'padding-bottom: 0px !important;'; // Remove last additional padding space } // Combine fieldsets into common rows if ($entry['div']) { $divs[$entry['div']][] = $group; } else { $divs['row'][] = $group; } $box_args = [ 'header-border' => TRUE, 'padding' => TRUE, 'id' => $group ]; if (isset($entry['style'])) { $box_args['body-style'] = $entry['style']; } if (isset($entry['title'])) { $box_args['title'] = $entry['title']; if ($entry['icon']) { // $box_args['icon'] => $entry['icon']; } } if (isset($entry['tooltip'])) { $box_args['header-controls'] = ['controls' => ['tooltip' => ['icon' => 'icon-info text-primary', 'anchor' => TRUE, //'url' => '#', 'class' => 'tooltip-from-element', 'data' => 'data-tooltip-id="tooltip-' . $group . '"']]]; $fieldset_tooltip .= '' . PHP_EOL; } if (isset($entry['tooltip'])) { $box_args['style'] = $entry['style']; } $fieldset_begin = generate_box_open($box_args); $fieldset_end = generate_box_close(); // Additional div class if set if (isset($entry['class'])) { $fieldset_begin = '
' . PHP_EOL . $fieldset_begin; $fieldset_end .= '
' . PHP_EOL; } $row_elements = $fieldset_begin . '
'; $row_elements .= PHP_EOL . $fieldset[$group] . '
' . PHP_EOL; $fieldset[$group] = $row_elements . $fieldset_end; } } // Combine fieldsets into common rows foreach ($divs as $entry) { $row_elements = $div_begin; foreach ($entry as $i => $group) { $row_elements .= $fieldset[$group]; if ($i > 0) { // unset all fieldsets except first one for replace later unset($fieldset[$group]); } } $row_elements .= $div_end; // now replace first fieldset in a group $fieldset[array_shift($entry)] = $row_elements; } // Replace div end $form_options['div_end'] = $fieldset_tooltip; return $fieldset; } /** * Helper function for print_form() to generate simple form. * * @param array $data * @param array $form_options * @param array $used_vars * @return string */ function form_simple($data, $form_options, &$used_vars) { $string_elements = ''; foreach ($data['row'] as $k => $row) { foreach ($row as $id => $element) { $used_vars[] = $id; $element['id'] = $id; if ($id === 'search') { // Add form_id here, for generate onclick action in submit button if ($data['url']) { $element['form_id'] = $form_options['form_id']; } } else { // all other cases add form_id $element['form_id'] = $form_options['form_id']; } $string_elements .= generate_form_element($element); } $string_elements .= PHP_EOL; } return $string_elements; } /** * Helper function for print_form() to finalize generation of form. * * @param array $data * @param array $form_options * @param array $used_vars * @return string */ function form_final($data, $form_options, &$used_vars) { // Always clean pagination from form action url $used_vars[] = 'pageno'; $used_vars[] = 'pagination'; $used_vars[] = 'pagesize'; // Remove old vars from url if ($data['url']) { foreach ($used_vars as $var) { $data['url'] = preg_replace('/' . $var . '=[^\/]+\/?/', '', $data['url']); } } // Form header if (isset($data['right']) && $data['right']) { $form_options['form_class'] .= ' pull-right'; } // auto add some common html attribs $form_attribs = [ 'class' => $form_options['form_class'] ]; foreach (['onchange', 'oninput', 'onclick', 'ondblclick', 'onfocus', 'onsubmit'] as $attrib) { if (isset($data[$attrib])) { $form_attribs[$attrib] = $data[$attrib]; } } $string = PHP_EOL . '' . PHP_EOL; $string .= $form_options['div_begin']; $string .= '
' . PHP_EOL; if ($data['brand']) { $string .= ' ' . escape_html($data['brand']) . '' . PHP_EOL; } if ($data['help']) { $string .= ' ' . $data['help'] . '' . PHP_EOL; } // Form elements $string .= $form_options['form_elements']; // Form footer $string .= '
' . PHP_EOL; $string .= $form_options['div_end']; $string .= '' . PHP_EOL; return $string; } /** * Pretty form generator * * Form options: * id - form id, default is auto generated * type - rows (multiple elements with small amount of rows), horizontal (mostly single element per row), simple (raw form without any grid/divs) * brand - only for rows, adds "other" form title (I think not work and obsolete) * title - displayed form title (only for rows and horizontal) * icon - adds icon to title * class - adds div with class (default box box-solid) in horizontal * space - adds style for base div in rows type and horizontal with box box-solid class (padding: xx) and horizontal type with box class (padding-top: xx) * style - adds style for base form element, default (margin-bottom:0;) * url - form action url, if url set and submit element with id "search" used (or submit_by_key), than form send params as GET query * submit_by_key - send form query by press enter key in text/input forms * fieldset - horizontal specific, array with fieldset names and descriptions, in form element should be add fieldset option with same key name * * Element options see in generate_form_element() description * * @param array $data Form options and form elements * @param bool $return If used and set to TRUE, print_form() will return form html instead of outputting it. * * @return NULL */ function print_form($data, $return = FALSE) { // Just return if safety requirements are not fulfilled if (isset($data['userlevel']) && $data['userlevel'] > $_SESSION['userlevel']) { return; } // Return if the user doesn't have write permissions to the relevant entity if (isset($data['entity_write_permit']) && !is_entity_write_permitted($data['entity_write_permit']['entity_id'], $data['entity_write_permit']['entity_type'])) { return; } // Time our form filling. $form_start = microtime(TRUE); form_init($data, $form_options); form_div($data, $form_options); $used_vars = []; // Form elements if ($data['type'] === 'rows') { // Rows form, see example in html/pages/devices.inc.php $string_elements = form_rows($data, $form_options, $used_vars); } elseif (str_starts_with($data['type'], 'horizontal')) { // Horizontal form, see example in html/pages/user_edit.inc.php $string_elements = form_horizontal($data, $form_options, $used_vars); } else { // Simple form, without any divs, sees example in html/pages/user_edit.inc.php $string_elements = form_simple($data, $form_options, $used_vars); } // Add CSRF Token if (isset($_SESSION['requesttoken']) && !in_array('requesttoken', $used_vars)) { $string_elements .= generate_form_element([ 'type' => 'hidden', 'id' => 'requesttoken', 'value' => $_SESSION['requesttoken'] ]) . PHP_EOL; $used_vars[] = 'requesttoken'; } //r($form_options); $form_options['form_elements'] = $string_elements; $form = form_final($data, $form_options, $used_vars); // Save generation time for profiling $GLOBALS['form_time'] += elapsed_time($form_start); if ($return) { // Return form as string return $form; } // Print form echo($form); } /** * Print box specific form (with type horizontal-rows). * * @param array $data * @param bool $return * @return string|NULL */ function print_form_box($data, $return = FALSE) { $data['type'] = 'horizontal-rows'; return print_form($data, $return); } /** * Return generated form. * * @param array $data * @return string|NULL */ function generate_form($data) { return print_form($data, TRUE); } /** * Generates form elements. * The main use for print_search() and print_form(), see examples of these functions. * * Common options (can be in any(mostly) element type): * (string) id - element identificator * (array) attribs - any custom element attrib (where key is attrib name, value - attrib value) * (bool) offset - for horizontal forms enable (default) or disable element offset (shift to the right on 180px) * Options tree: * textarea -\ * (string)id, (string)name, (bool)readonly, (bool)disabled, (string)width, (string)class, * (int)rows, (int)cols, * (string)value, (bool,string)placeholder, (bool)ajax, (array)ajax_vars * text, input, password -\ * (string)id, (string)name, (bool)readonly, (bool)disabled, (string)width, (string)class, * (string)value, (bool,string)placeholder, (bool)ajax, (array)ajax_vars, * (bool)show_password * hidden -\ * (string)id, (string)value * select, multiselect -\ * (string)id, (string)name, (bool)readonly, (bool)disabled, (string)onchange, (string)width, * (string)title, (int)size, (bool)right, (bool)live-search, (bool)encode, (bool)subtext * (string)value, (array)values, (string)icon, * values items can be arrays, ie: * value => array('name' => string, 'group' => string, 'icon' => string, 'class' => string, 'style' => string) * datetime -\ * (string)id, (string)name, (bool)readonly, (bool)disabled, * (string|FALSE)from, (string|FALSE)to, (bool)presets, (string)min, (string)max * (string)value (use it for single input) * checkbox, switch, toggle -\ * (string)id, (string)name, (bool)readonly, (bool)disabled, (string)onchange, * [switch only]: (bool)revert, (int)width, (string)size, (string)off-color, (string)on-color, (string)off-text, (string)on-text * [toggle only]: (string)view, (string)size, (string)palette, (string)group, (string)label, * (string)icon-check, (string)label-check, (string)icon-uncheck, (string)label-uncheck * (string)value, (string)placeholder, (string)title * submit -\ * (string)id, (string)name, (bool)readonly, (bool)disabled, * (string)class, (bool)right, (string)tooltip, * (string)value, (string)form_id, (string)icon * html, raw -\ * (string)id, (bool)offset, * (string)html, (string)value * newline -\ * (string)id, * (bool)hr * * @param array $item Options for a current form element * @param string $type Type of form element, also can pass as $item['type'] * * @return string Generated form element */ function generate_form_element($item, $type = '') { // Check a community edition if (isset($item['community']) && !$item['community'] && OBSERVIUM_EDITION === 'community') { return ''; } // Check and initialize 'readonly' and 'disabled' $item['readonly'] = $item['readonly'] ?? FALSE; $item['disabled'] = $item['disabled'] ?? FALSE; $value_isset = isset($item['value']); if (!$value_isset) { $item['value'] = ''; } $item['value_isset'] = $value_isset; if (is_array($item['value'])) { // Passed from URI comma values always converted to array, re-implode it $item['value_escaped'] = escape_html(implode(',', $item['value'])); } else { $item['value_escaped'] = escape_html($item['value']); } if (!isset($item['type'])) { $item['type'] = $type; } if (isset($item['attribs']) && is_array($item['attribs'])) { // Custom html attributes process_html_attribs($item['attribs']); } // auto add some common html attribs foreach ([ 'onchange', 'oninput', 'onclick', 'ondblclick', 'onfocus', 'onsubmit' ] as $attrib) { if (isset($item[$attrib])) { $item['attribs'][$attrib] = $item[$attrib]; } } switch ($item['type']) { case 'hidden': return generate_element_hidden($item); case 'password': case 'textarea': case 'text': case 'input': return generate_element_input($item); case 'switch': // bootstrap-switch replaced with bootstrap-toggle case 'switch-ng': return generate_element_switch($item); case 'toggle': return generate_element_toggle($item); case 'checkbox': return generate_element_checkbox($item); case 'datetime': return generate_element_datetime($item); case 'tags': // Tags mostly same as multiselect, but used separate options and Bootstrap Tags Input JS return generate_element_tags($item); case 'multiselect': unset($item['icon']); // For now not used icons in multiselect case 'select': return generate_element_select($item); case 'button': case 'submit': return generate_element_button($item); case 'raw': case 'html': // Just add custom (raw) html element return generate_element_html($item); case 'newline': // Deprecated $string = '
'; $string .= ($item['hr'] ? '
' : '
'); $string .= '
' . PHP_EOL; return $string; } return ''; } function generate_element_hidden($item) { if ($item['readonly'] || $item['disabled']) { // If item readonly or disabled, just skip item return ''; } return ' ' . PHP_EOL; } function generate_element_html($item) { // Just add custom (raw) html element if (isset($item['html'])) { return $item['html']; } $string = '' . $item['value'] . ''; return $string; } function generate_element_input($item) { $item_class = ''; $value_hidden = FALSE; if ($item['type'] !== 'textarea') { $item_begin = ' 7)) { $item['value_escaped'] = '••••••••'; $value_hidden = TRUE; } // add icon for show/hide password if ($item['show_password']) { $item_begin .= ' data-toggle="password" '; register_html_resource('js', 'bootstrap-show-password.min.js'); $GLOBALS['cache_html']['javascript'][] = "$('[data-toggle=\"password\"]').password();"; } //elseif (!$value_hidden && $autocomplete_off) {} } // Disable Autocomplete if required if ($autocomplete_off) { $browser = detect_browser(); //r($browser); // Autofill off is not simple! //https://developer.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Turning_off_form_autocompletion#The_autocomplete_attribute_and_login_fields //https://www.chromium.org/developers/design-documents/form-styles-that-chromium-understands //https://stackoverflow.com/questions/41945535/html-disable-password-manager if ($item['type'] === 'password' && !$value_hidden) { $autocomplete_value = 'new-password'; $item_begin = '' . '' . '' . $item_begin; } else { $autocomplete_value = 'off'; } $item_begin .= ' autocomplete="' . $autocomplete_value . '" '; if ($browser['browser'] === 'Safari') { // Safari issue: https://stackoverflow.com/questions/22661977/disabling-safari-autofill-on-usernames-and-passwords //$item_begin .= ' autocomplete="off" readonly onfocus="if (this.hasAttribute(\'readonly\')) {this.removeAttribute(\'readonly\'); this.blur(); this.focus();}" '; //$item_begin .= ' autocomplete="false" '; // This disables safari autocomplete button register_html_resource('style', <<