' . 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 . '
' . 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;
$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 = '