Example #1
0
/**
 * Generates form elements. The main use for print_search() and print_form(), see examples of this functions.
 *
 * 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 -\
 *     (string)id, (string)name, (bool)readonly, (bool)disabled, (string)onchange,
 *     (bool)revert, (int)width, (string)size, (string)off-color, (string)on-color, (string)off-text, (string)on-text
 *     (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,
 *     (string)html
 * newline -\
 *     (string)id,
 *     (bool)hr
 *
 * @param array $item Options for current form element
 * @param string $type Type of form element, also can passed as $item['type']
 * @return string Generated form element
 */
function generate_form_element($item, $type = '')
{
    $value_isset = isset($item['value']);
    if (!$value_isset) {
        $item['value'] = '';
    }
    if (!isset($item['type'])) {
        $item['type'] = $type;
    }
    $string = '';
    $element_tooltip = '';
    switch ($item['type']) {
        case 'hidden':
            if (!$item['readonly'] && !$item['disabled']) {
                $string .= '    <input type="' . $item['type'] . '" name="' . $item['id'] . '" id="' . $item['id'] . '" value="' . $item['value'] . '" />' . PHP_EOL;
            }
            break;
        case 'password':
        case 'textarea':
        case 'text':
        case 'input':
            if ($item['type'] != 'textarea') {
                $item_begin = '    <input type="' . $item['type'] . '" ';
                // password specific options
                if ($item['type'] == 'password') {
                    // disable autocomplete for passwords
                    $item_begin .= ' autocomplete="off" ';
                    // mask password field for disabled/readonly by bullet
                    if (strlen($item['value']) && ($item['disabled'] || $item['readonly'])) {
                        if (!($item['show_password'] && $_SESSION['userlevel'] > 7)) {
                            $item['value'] = '&#8226;&#8226;&#8226;&#8226;&#8226;&#8226;&#8226;&#8226;';
                        }
                    }
                    // 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();";
                    }
                }
                $item_end = ' value="' . $item['value'] . '" />';
                $item_class = 'input';
            } else {
                $item_begin = '    <textarea ';
                // textarea specific options
                if (is_numeric($item['rows'])) {
                    $item_begin .= 'rows="' . $item['rows'] . '" ';
                }
                if (is_numeric($item['cols'])) {
                    $item_begin .= 'cols="' . $item['cols'] . '" ';
                }
                $item_end = '>' . $item['value'] . '</textarea>';
                $item_class = 'form-control';
            }
            if ($item['disabled']) {
                $item_end = ' disabled="1"' . $item_end;
            } else {
                if ($item['readonly']) {
                    $item_end = ' readonly="1"' . $item_end;
                }
            }
            if (isset($item['placeholder']) && $item['placeholder'] !== FALSE) {
                if ($item['placeholder'] === TRUE) {
                    $item['placeholder'] = $item['name'];
                }
                $string .= PHP_EOL;
                $string .= $item_begin . 'placeholder="' . $item['placeholder'] . '" ';
                $item['placeholder'] = TRUE;
                // Set to true for check at end
            } else {
                $string .= '  <div class="input-prepend">' . PHP_EOL;
                if (!$item['name']) {
                    $item['name'] = '<i class="icon-list"></i>';
                }
                $string .= '    <span class="add-on">' . $item['name'] . '</span>' . PHP_EOL;
                $string .= $item_begin;
            }
            if ($item['class']) {
                $item_class .= ' ' . $item['class'];
            }
            $string .= isset($item['width']) ? 'style="width:' . $item['width'] . '" ' : '';
            $string .= 'name="' . $item['id'] . '" id="' . $item['id'] . '" class="' . $item_class;
            if ($item['ajax'] === TRUE && is_array($item['ajax_vars'])) {
                $ajax_vars = array();
                if (!isset($item['ajax_vars']['field'])) {
                    // If query field not specified use item id as field
                    $item['ajax_vars']['field'] = $item['id'];
                }
                foreach ($item['ajax_vars'] as $k => $v) {
                    $ajax_vars[] = urlencode($k) . '=' . var_encode($v);
                }
                $string .= ' ajax-typeahead" autocomplete="off" data-link="/ajax/input.php?' . implode('&amp;', $ajax_vars);
                // Register scripts/css
                register_html_resource('js', 'typeahead.bundle.min.js');
                register_html_resource('css', 'typeaheadjs.css');
                // Ajax autocomplete for input
                // <input type='text' class='ajax-typeahead' data-link='your-json-link' />
                $item_id = $item['id'];
                $script = <<<SCRIPT
  var element_{$item_id} = \$('#{$item_id}.ajax-typeahead');
  var entries_{$item_id} = new Bloodhound({
    datumTokenizer: Bloodhound.tokenizers.obj.whitespace('value'),
    queryTokenizer: Bloodhound.tokenizers.whitespace,
    remote: {
      url: element_{$item_id}.data('link') + '&query=%QUERY',
      wildcard: '%QUERY',
      filter: function(json) {
        return json.options;
      }
    }
  });
  element_{$item_id}.typeahead({
      hint: false,
      highlight: true,
      minLength: 1
    },
    {
      name: 'options',
      limit: 16,
      source: entries_{$item_id}
    }
  );
SCRIPT;
                register_html_resource('script', $script);
            }
            $string .= '" ' . $item_end . PHP_EOL;
            $string .= $item['placeholder'] ? PHP_EOL : '  </div>' . PHP_EOL;
            // End 'text' & 'input'
            break;
        case 'switch':
            // switch specific options
            if ($item['revert']) {
                $item_switch = ' data-toggle="switch-revert"';
            } else {
                $item_switch = ' data-toggle="switch"';
            }
            if ($item['size']) {
                $item_switch .= ' data-size="' . $item['size'] . '"';
            }
            if ($item['on-color']) {
                $item_switch .= ' data-on-color="' . $item['on-color'] . '"';
            }
            if ($item['off-color']) {
                $item_switch .= ' data-off-color="' . $item['off-color'] . '"';
            }
            if ($item['on-text']) {
                $item_switch .= ' data-on-text="' . $item['on-text'] . '"';
            }
            if ($item['off-text']) {
                $item_switch .= ' data-off-text="' . $item['off-text'] . '"';
            }
            if (is_numeric($item['width']) && $item['width'] > 10) {
                $item_switch .= ' data-handle-width="' . intval($item['width'] / 2) . '"';
            }
        case 'checkbox':
            $string = '    <input type="checkbox" ';
            $string .= ' name="' . $item['id'] . '" id="' . $item['id'] . '" ' . $item_switch;
            if ($item['title']) {
                $string .= ' data-rel="tooltip" data-tooltip="' . escape_html($item['title']) . '"';
            }
            if ($item['value'] == '1' || $item['value'] === 'on' || $item['value'] === 'yes' || $item['value'] === TRUE) {
                $string .= ' checked';
            }
            if ($item['disabled']) {
                $string .= ' disabled="1"';
            } else {
                if ($item['readonly']) {
                    $string .= ' readonly="1" onclick="return false"';
                } else {
                    if ($item['onchange']) {
                        $string .= ' onchange="' . $item['onchange'] . '"';
                    }
                }
            }
            $string .= ' value="1" />';
            if (is_string($item['placeholder'])) {
                // add placeholder text at right of the element
                $string .= '      <span class="help-inline" style="margin-top: 4px;">' . $item['placeholder'] . '</span>' . PHP_EOL;
            }
            // End 'switch' & 'checkbox'
            break;
        case 'datetime':
            register_html_resource('js', 'bootstrap-datetimepicker.min.js');
            // Enable DateTime JS
            $id_from = $item['id'] . '_from';
            $id_to = $item['id'] . '_to';
            if ($value_isset && !$item['from'] && !$item['to']) {
                // Single datetime input
                $item['from'] = $item['value'];
                $item['to'] = FALSE;
                $item['presets'] = FALSE;
                $id_from = $item['id'];
                $name_from = $item['name'];
            } else {
                $name_from = 'From';
            }
            // Presets
            if ($item['from'] === FALSE || $item['to'] === FALSE) {
                $item['presets'] = FALSE;
            }
            if (is_numeric($item['from'])) {
                $item['from'] = strftime("%F %T", $item['from']);
            }
            if (is_numeric($item['to'])) {
                $item['to'] = strftime("%F %T", $item['to']);
            }
            if ($item['presets']) {
                $presets = array('sixhours' => 'Last 6 hours', 'today' => 'Today', 'yesterday' => 'Yesterday', 'tweek' => 'This week', 'lweek' => 'Last week', 'tmonth' => 'This month', 'lmonth' => 'Last month', 'tquarter' => 'This quarter', 'lquarter' => 'Last quarter', 'tyear' => 'This year', 'lyear' => 'Last year');
                // Recursive call
                $preset_item = array('id' => $item['id'] . '_preset', 'type' => 'select', 'name' => 'Date presets', 'width' => '110px', 'values' => $presets);
                $string .= generate_form_element($preset_item) . PHP_EOL;
            }
            // Date/Time input fields
            if ($item['from'] !== FALSE) {
                $string .= '  <div id="' . $id_from . '_div" class="input-prepend" style="margin-bottom: 0;">' . PHP_EOL;
                $string .= '    <span class="add-on btn"><i data-time-icon="icon-time" data-date-icon="icon-calendar"></i> ' . $name_from . '</span>' . PHP_EOL;
                //$string .= '    <input type="text" class="input-medium" data-format="yyyy-MM-dd hh:mm:ss" ';
                $string .= '    <input type="text" data-format="yyyy-MM-dd hh:mm:ss" ';
                $string .= isset($item['width']) ? 'style="width:' . escape_html($item['width']) . '" ' : 'style="width: 130px;" ';
                if ($item['disabled']) {
                    $string .= 'disabled="1" ';
                } else {
                    if ($item['readonly']) {
                        $item['disabled'] = TRUE;
                        // for js
                        $string .= 'readonly="1" ';
                    }
                }
                $string .= 'name="' . $id_from . '" id="' . $id_from . '" value="' . escape_html($item['from']) . '"/>' . PHP_EOL;
                $string .= '  </div>' . PHP_EOL;
            }
            if ($item['to'] !== FALSE) {
                $string .= '  <div id="' . $id_to . '_div" class="input-prepend" style="margin-bottom: 0;">' . PHP_EOL;
                $string .= '    <span class="add-on btn"><i data-time-icon="icon-time" data-date-icon="icon-calendar"></i> To</span>' . PHP_EOL;
                //$string .= '    <input type="text" class="input-medium" data-format="yyyy-MM-dd hh:mm:ss" ';
                $string .= '    <input type="text" data-format="yyyy-MM-dd hh:mm:ss" ';
                $string .= isset($item['width']) ? 'style="width:' . escape_html($item['width']) . '" ' : 'style="width: 140px;" ';
                $string .= 'name="' . $id_to . '" id="' . $id_to . '" value="' . escape_html($item['to']) . '"/>' . PHP_EOL;
                $string .= '  </div>' . PHP_EOL;
            }
            // JS SCRIPT
            $min = '-Infinity';
            $max = 'Infinity';
            $pattern = '/^(\\d{4})-(\\d{2})-(\\d{2}) ([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/';
            if (!empty($item['min'])) {
                if (preg_match($pattern, $item['min'], $matches)) {
                    $matches[2] = $matches[2] - 1;
                    array_shift($matches);
                    $min = 'new Date(' . implode(',', $matches) . ')';
                } else {
                    if ($item['min'] == 'now' || $item['min'] == 'current') {
                        $min = 'new Date()';
                    }
                }
            }
            if (!empty($item['max'])) {
                if (preg_match($pattern, $item['max'], $matches)) {
                    $matches[2] = $matches[2] - 1;
                    array_shift($matches);
                    $max = 'new Date(' . implode(',', $matches) . ')';
                } else {
                    if ($item['max'] == 'now' || $item['max'] == 'current') {
                        $max = 'new Date()';
                    }
                }
            }
            $script = '
      var startDate = ' . $min . ';
      var endDate   = ' . $max . ';
      $(document).ready(function() {
        $(\'[id=' . $id_from . '_div]\').datetimepicker({
          //pickSeconds: false,
          weekStart: 1,
          startDate: startDate,
          endDate: endDate
        });';
            if ($item['disabled']) {
                $script .= '
        $(\'[id=' . $id_from . '_div]\').datetimepicker(\'disable\');';
            }
            if ($item['to'] !== FALSE) {
                $script .= '
        $(\'[id=' . $id_to . '_div]\').datetimepicker({
          //pickSeconds: false,
          weekStart: 1,
          startDate: startDate,
          endDate: endDate
        });';
            }
            $script .= '
      });' . PHP_EOL;
            if ($item['presets']) {
                $script .= '
      $(\'select[id=' . $item['id'] . '_preset]\').change(function() {
        var input_from = $(\'input#' . $id_from . '\');
        var input_to   = $(\'input#' . $id_to . '\');
        switch ($(this).val()) {' . PHP_EOL;
                foreach ($presets as $k => $v) {
                    $preset = datetime_preset($k);
                    $script .= "          case '{$k}':\n";
                    $script .= "            input_from.val('" . $preset['from'] . "');\n";
                    $script .= "            input_to.val('" . $preset['to'] . "');\n";
                    $script .= "            break;\n";
                }
                $script .= '
          default:
            input_from.val("");
            input_to.val("");
            break;
        }
      });';
            }
            register_html_resource('script', $script);
            // End 'datetime'
            break;
        case 'tags':
            // Tags mostly same as multiselect, but used separate options and Bootstrap Tags Input JS
            register_html_resource('js', 'bootstrap-tagsinput.min.js');
            // Enable Tags Input JS
            //register_html_resource('js',  'bootstrap-tagsinput.js');      // Enable Tags Input JS
            register_html_resource('css', 'bootstrap-tagsinput.css');
            // Enable Tags Input CSS
            // defaults
            $delimiter = empty($item['delimiter']) ? ',' : $item['delimiter'];
            $script_begin = '';
            $script_options = array('trimValue' => 'true', 'tagClass' => 'function(item) {return "label label-default";}');
            //register_html_resource('script', '$("input[data-role=tagsinput], select[multiple][data-role=tagsinput]").tagsinput({trimValue: true, tagClass: function(item) {return "label label-default";} });');
            $string .= '    <select multiple data-toggle="tagsinput" name="' . $item['id'] . '[]" ' . $title;
            $string .= 'id="' . $item['id'] . '" ';
            if ($item['title']) {
                $string .= 'title="' . $item['title'] . '" ';
            } else {
                if (isset($item['name'])) {
                    $string .= 'title="' . $item['name'] . '" ';
                }
            }
            if (isset($item['placeholder']) && $item['placeholder'] !== FALSE) {
                if ($item['placeholder'] === TRUE) {
                    $item['placeholder'] = $item['name'];
                }
                //$string .= PHP_EOL;
                $string .= ' placeholder="' . $item['placeholder'] . '"';
                //$item['placeholder'] = TRUE; // Set to true for check at end
            }
            if ($item['disabled']) {
                $string .= ' disabled="1"';
            } else {
                if ($item['readonly']) {
                    $string .= ' disabled="1" readonly="1"';
                    // Bootstrap Tags Input not support readonly attribute, currently use disable
                }
            }
            if ($item['onchange']) {
                $string .= ' onchange="' . $item['onchange'] . '"';
            }
            $string .= '>' . PHP_EOL . '      ';
            // end <select>
            // Process values
            if (!is_array($item['value'])) {
                //$item['value'] = explode($delimiter, $item['value']);
                $item['value'] = array($item['value']);
            }
            //$item['value'] = array('test', 'hello');
            $suggest = array();
            foreach ($item['value'] as $entry) {
                $value = (string) $entry;
                if ($value == '[there is no data]' || $value === '') {
                    continue;
                }
                $suggest[] = $value;
                $string .= '<option value="' . $value . '"';
                $string .= '>' . escape_html($value) . '</option> ';
            }
            $string .= PHP_EOL . '    </select>' . PHP_EOL;
            // Generate typeahead from values
            $suggest = array_merge($suggest, (array) $item['values']);
            if (count($suggest)) {
                $option = '[{ hint: false, highlight: true, minLength: 1 },
                    { name: "suggest", limit: 16, source: suggest_' . $item['id'] . ' }]';
                $script_begin .= 'var suggest_' . $item['id'] . ' = new Bloodhound({ matchAnyQueryToken: true, queryTokenizer: Bloodhound.tokenizers.nonword, datumTokenizer: Bloodhound.tokenizers.nonword,
        local: [';
                $values = array();
                foreach (array_unique($suggest) as $k => $entry) {
                    if (is_array($entry)) {
                        $value = (string) $k;
                    } else {
                        $value = (string) $entry;
                    }
                    $values[] = "'" . str_replace("'", "\\'", $value) . "'";
                }
                $script_begin .= implode(',', $values);
                $script_begin .= ']});' . PHP_EOL;
                $script_options['typeaheadjs'] = $option;
                // Register scripts/css
                //register_html_resource('js', 'typeahead.bundle.js');
                register_html_resource('js', 'typeahead.bundle.min.js');
                register_html_resource('css', 'typeaheadjs.css');
            }
            if (count($script_options)) {
                $script = $script_begin;
                $script .= "\$('#" . $item['id'] . "').tagsinput({" . PHP_EOL;
                foreach ($script_options as $key => &$option) {
                    $option = '  ' . $key . ': ' . $option;
                }
                $script .= implode(',' . PHP_EOL, $script_options) . PHP_EOL;
                $script .= "});";
                register_html_resource('script', $script);
            }
            // End 'tags'
            break;
        case 'multiselect':
            unset($item['icon']);
            // For now not used icons in multiselect
        // For now not used icons in multiselect
        case 'select':
            $count_values = count($item['values']);
            if (empty($item['values'])) {
                $item['values'] = array(0 => '[there is no data]');
                $item['subtext'] = FALSE;
            }
            if ($item['type'] == 'multiselect') {
                $string .= '    <select multiple name="' . $item['id'] . '[]" ' . $title;
                // Enable Select/Deselect all (if select values count more than 4)
                if ($count_values > 4) {
                    $string .= ' data-actions-box="true" ';
                }
            } else {
                $string .= '    <select name="' . $item['id'] . '" ';
            }
            $string .= 'id="' . $item['id'] . '" ';
            if ($item['title']) {
                $string .= 'title="' . $item['title'] . '" ';
            } else {
                if (isset($item['name'])) {
                    $string .= 'title="' . $item['name'] . '" ';
                }
            }
            $data_width = $item['width'] ? ' data-width="' . $item['width'] . '"' : ' data-width="auto"';
            $data_size = is_numeric($item['size']) ? ' data-size="' . $item['size'] . '"' : ' data-size="15"';
            $string .= 'class="selectpicker show-tick';
            if ($item['right']) {
                $string .= ' pull-right';
            }
            $string .= '" data-selected-text-format="count>2"';
            if ($item['data-style']) {
                $string .= ' data-style="' . $item['data-style'] . '"';
            }
            // Enable Live search in values list (if select values count more than 12)
            if ($count_values > 12 && $item['live-search'] !== FALSE) {
                $string .= ' data-live-search="true"';
            }
            if ($item['disabled']) {
                $string .= ' disabled="1"';
            } else {
                if ($item['readonly']) {
                    $string .= ' disabled="1" readonly="1"';
                    // Bootstrap select not support readonly attribute, currently use disable
                }
            }
            if ($item['onchange']) {
                $string .= ' onchange="' . $item['onchange'] . '"';
            }
            $string .= $data_width . $data_size . '>' . PHP_EOL . '      ';
            // end <select>
            if (!is_array($item['value'])) {
                $item['value'] = array($item['value']);
            }
            // Prepare values for optgroups
            $values = array();
            $optgroup = array();
            foreach ($item['values'] as $k => $entry) {
                $k = (string) $k;
                $value = $item['encode'] ? var_encode($k) : $k;
                // Use base64+serialize encoding
                // Default group is '' (empty string), for allow to use 0 as group name!
                $group = '';
                if (!is_array($entry)) {
                    $entry = array('name' => $entry);
                } else {
                    if (isset($entry['group'])) {
                        $group = $entry['group'];
                    }
                }
                if ($item['subtext'] && !isset($entry['subtext'])) {
                    $entry['subtext'] = $k;
                }
                // Icons and empty name fix
                if ($item['icon'] && $item['value'] === array('')) {
                    // Only one main icon
                    $entry['icon'] = $item['icon'];
                    // Set value icon as global icon
                    unset($item['icon']);
                }
                if (in_array($k, $item['value'])) {
                    if (!($k === '' && $entry['name'] === '')) {
                        if ($item['icon']) {
                            $entry['icon'] = $item['icon'];
                            // Set value icon as global icon
                        }
                        // Element selected
                        $entry['selected'] = TRUE;
                    }
                } else {
                    if ($entry['name'] == '[there is no data]') {
                        $entry['disabled'] = TRUE;
                    }
                }
                if (strlen($entry['name']) == 0 && $k !== '') {
                    $entry['name'] = $k;
                }
                // if name still empty set it as value
                $values[$group][$value] = $entry;
            }
            // Generate optgroups for values
            foreach ($values as $group => $entries) {
                $optgroup[$group] = '';
                foreach ($entries as $value => $entry) {
                    $optgroup[$group] .= '<option value="' . $value . '"';
                    if (isset($entry['subtext']) && strlen($entry['subtext'])) {
                        $optgroup[$group] .= ' data-subtext="' . $entry['subtext'] . '"';
                    }
                    if ($entry['name'] == '[there is no data]') {
                        $optgroup[$group] .= ' disabled="1"';
                    }
                    if (isset($entry['class']) && $entry['class']) {
                        $optgroup[$group] .= ' class="' . $entry['class'] . '"';
                    } else {
                        if (isset($entry['style']) && $entry['style']) {
                            $optgroup[$group] .= ' style="' . $entry['style'] . '"';
                        } else {
                            if (isset($entry['color']) && $entry['color']) {
                                $optgroup[$group] .= ' style="color:' . $entry['color'] . ' !important;"';
                                //$optgroup[$group] .= ' data-content="<span style=\'color: ' . $entry['color'] . '\'>' . $entry['name'] . '</span>"';
                            }
                        }
                    }
                    // Icons
                    if (isset($entry['icon']) && $entry['icon']) {
                        $optgroup[$group] .= ' data-icon="' . $entry['icon'] . '"';
                    }
                    // Disabled, Selected
                    if (isset($entry['disabled']) && $entry['disabled']) {
                        $optgroup[$group] .= ' disabled="1"';
                    } else {
                        if (isset($entry['selected']) && $entry['selected']) {
                            $optgroup[$group] .= ' selected';
                        }
                    }
                    $optgroup[$group] .= '>' . escape_html($entry['name']) . '</option> ';
                }
            }
            // If item groups passed, use order passed from it
            $optgroups = array_keys($optgroup);
            if (isset($item['groups'])) {
                $groups = array_intersect((array) $item['groups'], $optgroups);
                $optgroups = array_diff($optgroups, $groups);
                $optgroups = array_merge($groups, $optgroups);
            }
            if (count($optgroups) === 1) {
                // Single optgroup, do not use optgroup tags
                $string .= array_shift($optgroup);
            } else {
                // Multiple optgroups implode
                foreach ($optgroups as $group) {
                    $entry = $optgroup[$group];
                    $label = $group !== '' ? ' label="' . $group . '"' : '';
                    $string .= '<optgroup' . $label . '>' . PHP_EOL;
                    $string .= $entry;
                    $string .= '</optgroup>' . PHP_EOL;
                }
            }
            $string .= PHP_EOL . '    </select>' . PHP_EOL;
            // End 'select' & 'multiselect'
            break;
        case 'submit':
            $button_type = 'submit';
            $button_onclick = '';
            $button_class = 'btn';
            if (!empty($item['class'])) {
                if (!preg_match('/btn-(default|primary|success|info|warning|danger)/', $item['class'])) {
                    // Add default class if custom class hot have it
                    $button_class .= ' btn-default';
                }
                $button_class .= ' ' . $item['class'];
            } else {
                $button_class .= ' btn-default';
            }
            if ($item['right']) {
                $button_class .= ' pull-right';
            }
            if ($item['form_id'] && $item['id'] == 'search') {
                // Note, used script form_to_path() stored in js/observium.js
                $button_type = 'button';
                $button_onclick = " onclick=\"form_to_path('" . $item['form_id'] . "');\"";
            }
            $button_disabled = $item['disabled'] || $item['readonly'];
            if ($button_disabled) {
                $button_class .= ' disabled';
            }
            $string .= '      <button id="' . $item['id'] . '" name="' . $item['id'] . '" type="' . $button_type . '"';
            // Add tooltip data
            if ($item['tooltip']) {
                $button_class .= ' tooltip-from-element';
                $string .= ' data-tooltip-id="tooltip-' . $item['id'] . '"';
                $element_tooltip .= '<div id="tooltip-' . $item['id'] . '" style="display: none;">' . $item['tooltip'] . '</div>' . PHP_EOL;
            }
            //$string .= ' class="'.$button_class.' text-nowrap" style="line-height: 20px;"'.$button_onclick;
            $string .= ' class="' . $button_class . ' text-nowrap"' . $button_onclick;
            if ($button_disabled) {
                $string .= ' disabled="1"';
            }
            if ($item['value']) {
                $string .= ' value="' . $item['value'] . '"';
            }
            $string .= '>';
            switch ($item['id']) {
                // Note. 'update' - use POST request, all other - use GET with generate url from js.
                case 'update':
                    $button_icon = 'icon-refresh';
                    $button_name = 'Update';
                    break;
                default:
                    $button_icon = 'icon-search';
                    $button_name = 'Search';
            }
            $nbsp = 0;
            if (array_key_exists('icon', $item)) {
                $button_icon = trim($item['icon']);
            }
            if (strlen($button_icon)) {
                $string .= '<i class="' . $button_icon . '"></i>';
                $nbsp++;
            }
            if (array_key_exists('name', $item)) {
                $button_name = trim($item['name']);
            }
            if (strlen($button_name)) {
                $nbsp++;
            }
            if ($nbsp == 2) {
                $string .= '&nbsp;';
            }
            $string .= $button_name . '</button>' . PHP_EOL;
            // End 'submit'
            break;
        case 'raw':
        case 'html':
            // Just add custom (raw) html element
            if (isset($item['html'])) {
                $string .= $item['html'];
            } else {
                $string .= '<span';
                if (isset($item['class'])) {
                    $string .= ' class="' . $item['class'] . '"';
                }
                $string .= '>' . $item['value'] . '</span>';
            }
            break;
        case 'newline':
            // Deprecated
            $string .= '<div class="clearfix" id="' . $item['id'] . '">';
            $string .= $item['hr'] ? '<hr />' : '<hr style="border-width: 0px;" />';
            $string .= '</div>' . PHP_EOL;
            // End 'newline'
            break;
    }
    return $string . $element_tooltip;
}
function get_form_element($item, $type = '')
{
    if (!isset($item['value'])) {
        $item['value'] = '';
    }
    if (!isset($item['type'])) {
        $item['value'] = $type;
    }
    $string = '';
    switch ($item['type']) {
        case 'text':
        case 'input':
            $string .= '  <div class="input-prepend">' . PHP_EOL;
            if (!$item['name']) {
                $item['name'] = '<i class="icon-list"></i>';
            }
            $string .= '    <span class="add-on">' . $item['name'] . '</span>' . PHP_EOL;
            $string .= '    <input type="' . $item['type'] . '" ';
            $string .= isset($item['width']) ? 'style="width:' . $item['width'] . '" ' : '';
            $string .= 'name="' . $item['id'] . '" id="' . $item['id'] . '" class="input" value="' . $item['value'] . '"/>' . PHP_EOL;
            $string .= '  </div>' . PHP_EOL;
            // End 'text' & 'input'
            break;
        case 'newline':
            $string .= '<div class="clearfix" id="' . $item['id'] . '"><hr /></div>' . PHP_EOL;
            // End 'newline'
            break;
        case 'datetime':
            $id_from = $item['id'] . '_from';
            $id_to = $item['id'] . '_to';
            // Presets
            if ($item['from'] === FALSE || $item['to'] === FALSE) {
                $item['presets'] = FALSE;
            }
            if ($item['presets']) {
                $presets = array('sixhours' => 'Last 6 hours', 'today' => 'Today', 'yesterday' => 'Yesterday', 'tweek' => 'This week', 'lweek' => 'Last week', 'tmonth' => 'This month', 'lmonth' => 'Last month', 'tyear' => 'This year', 'lyear' => 'Last year');
                $string .= '    <select id="' . $item['id'] . '" class="selectpicker show-tick" data-size="false" data-width="auto">' . PHP_EOL . '      ';
                $string .= '<option value="" selected>Date/Time presets</option>';
                foreach ($presets as $k => $v) {
                    $string .= '<option value="' . $k . '">' . $v . '</option> ';
                }
                $string .= PHP_EOL . '    </select>' . PHP_EOL;
            }
            // Date/Time input fields
            if ($item['from'] !== FALSE) {
                $string .= '  <div class="input-prepend" id="' . $id_from . '">' . PHP_EOL;
                $string .= '    <span class="add-on btn"><i data-time-icon="icon-time" data-date-icon="icon-calendar"></i> From</span>' . PHP_EOL;
                $string .= '    <input type="text" class="input-medium" data-format="yyyy-MM-dd hh:mm:ss" ';
                $string .= 'name="' . $id_from . '" id="' . $id_from . '" value="' . $item['from'] . '"/>' . PHP_EOL;
                $string .= '  </div>' . PHP_EOL;
            }
            if ($item['to'] !== FALSE) {
                $string .= '  <div class="input-prepend" id="' . $id_to . '">' . PHP_EOL;
                $string .= '    <span class="add-on btn"><i data-time-icon="icon-time" data-date-icon="icon-calendar"></i> To</span>' . PHP_EOL;
                $string .= '    <input type="text" class="input-medium" data-format="yyyy-MM-dd hh:mm:ss" ';
                $string .= 'name="' . $id_to . '" id="' . $id_to . '" value="' . $item['to'] . '"/>' . PHP_EOL;
                $string .= '  </div>' . PHP_EOL;
            }
            // JS
            $min = '-Infinity';
            $max = 'Infinity';
            $pattern = '/^(\\d{4})-(\\d{2})-(\\d{2}) ([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/';
            if (!empty($item['min'])) {
                if (preg_match($pattern, $item['min'], $matches)) {
                    $matches[2] = $matches[2] - 1;
                    array_shift($matches);
                    $min = 'new Date(' . implode(',', $matches) . ')';
                }
            }
            if (!empty($item['max'])) {
                if (preg_match($pattern, $item['max'], $matches)) {
                    $matches[2] = $matches[2] - 1;
                    array_shift($matches);
                    $max = 'new Date(' . implode(',', $matches) . ')';
                }
            }
            $string .= '
    <script type="text/javascript">
      var startDate = ' . $min . ';
      var endDate   = ' . $max . ';
      $(document).ready(function() {
	$(\'#' . $id_from . '\').datetimepicker({
          //pickSeconds: false,
          weekStart: 1,
          startDate: startDate,
          endDate: endDate
        });
	$(\'#' . $id_to . '\').datetimepicker({
          //pickSeconds: false,
          weekStart: 1,
          startDate: startDate,
          endDate: endDate
        });
      });' . PHP_EOL;
            if ($item['presets']) {
                $string .= '
      $(\'select#' . $item['id'] . '\').change(function() {
        var input_from = $(\'input#' . $id_from . '\');
        var input_to   = $(\'input#' . $id_to . '\');
        switch ($(this).val()) {' . PHP_EOL;
                foreach ($presets as $k => $v) {
                    $preset = datetime_preset($k);
                    $string .= "          case '{$k}':\n";
                    $string .= "            input_from.val('" . $preset['from'] . "');\n";
                    $string .= "            input_to.val('" . $preset['to'] . "');\n";
                    $string .= "            break;\n";
                }
                $string .= '
          default:
            input_from.val("");
            input_to.val("");
            break;
        }
      });' . PHP_EOL;
            }
            $string .= '</script>' . PHP_EOL;
            // End 'datetime'
            break;
        case 'select':
        case 'multiselect':
            if (empty($item['values'])) {
                $item['values'] = array(0 => '[there is no data]');
            }
            if ($item['type'] == 'multiselect') {
                $title = isset($item['name']) ? 'title="' . $item['name'] . '" ' : '';
                $string .= '    <select multiple name="' . $item['id'] . '[]" ' . $title;
            } else {
                $string .= '    <select name="' . $item['id'] . '" ';
                if ($item['name'] && !isset($item['values'][''])) {
                    $item['values'] = array('' => $item['name']) + $item['values'];
                }
            }
            $string .= 'id="' . $item['id'] . '" ';
            $data_width = $item['width'] ? ' data-width="' . $item['width'] . '"' : ' data-width="auto"';
            $data_size = is_numeric($item['size']) ? ' data-size="' . $item['size'] . '"' : ' data-size="15"';
            $string .= 'class="selectpicker show-tick" data-selected-text-format="count>1"';
            $string .= $data_width . $data_size . '>' . PHP_EOL . '      ';
            if (!is_array($item['value'])) {
                $item['value'] = array($item['value']);
            }
            foreach ($item['values'] as $k => $v) {
                $k = (string) $k;
                $data_subtext = $item['subtext'] ? ' data-subtext="(' . $k . ')"' : '';
                $string .= '<option value="' . $k . '"' . $data_subtext;
                $string .= $k !== '' && in_array($k, $item['value']) ? ' selected>' : '>';
                $string .= $v . '</option> ';
            }
            $string .= PHP_EOL . '    </select>' . PHP_EOL;
            // End 'select' & 'multiselect'
            break;
    }
    return $string;
}
Example #3
0
function get_form_element($item, $type = '')
{
    if (!isset($item['value'])) {
        $item['value'] = '';
    }
    if (!isset($item['type'])) {
        $item['type'] = $type;
    }
    $string = '';
    switch ($item['type']) {
        case 'text':
        case 'input':
            if ($item['placeholder']) {
                $string .= PHP_EOL;
                $string .= '    <input type="' . $item['type'] . '" placeholder="' . $item['name'] . '" ';
            } else {
                $string .= '  <div class="input-prepend">' . PHP_EOL;
                if (!$item['name']) {
                    $item['name'] = '<i class="icon-list"></i>';
                }
                $string .= '    <span class="add-on">' . $item['name'] . '</span>' . PHP_EOL;
                $string .= '    <input type="' . $item['type'] . '" ';
            }
            $string .= isset($item['width']) ? 'style="width:' . $item['width'] . '" ' : '';
            $string .= 'name="' . $item['id'] . '" id="' . $item['id'] . '" class="input" value="' . $item['value'] . '"/>' . PHP_EOL;
            $string .= $item['placeholder'] ? PHP_EOL : '  </div>' . PHP_EOL;
            // End 'text' & 'input'
            break;
        case 'datetime':
            $id_from = $item['id'] . '_from';
            $id_to = $item['id'] . '_to';
            // Presets
            if ($item['from'] === FALSE || $item['to'] === FALSE) {
                $item['presets'] = FALSE;
            }
            if ($item['presets']) {
                $presets = array('sixhours' => 'Last 6 hours', 'today' => 'Today', 'yesterday' => 'Yesterday', 'tweek' => 'This week', 'lweek' => 'Last week', 'tmonth' => 'This month', 'lmonth' => 'Last month', 'tyear' => 'This year', 'lyear' => 'Last year');
                $string .= '    <select id="' . $item['id'] . '" class="selectpicker show-tick" data-size="false" data-width="auto">' . PHP_EOL . '      ';
                $string .= '<option value="" selected>Date/Time presets</option>';
                foreach ($presets as $k => $v) {
                    $string .= '<option value="' . $k . '">' . $v . '</option> ';
                }
                $string .= PHP_EOL . '    </select>' . PHP_EOL;
            }
            // Date/Time input fields
            if ($item['from'] !== FALSE) {
                $string .= '  <div class="input-prepend" id="' . $id_from . '">' . PHP_EOL;
                $string .= '    <span class="add-on btn"><i data-time-icon="icon-time" data-date-icon="icon-calendar"></i> From</span>' . PHP_EOL;
                $string .= '    <input type="text" class="input-medium" data-format="yyyy-MM-dd hh:mm:ss" ';
                $string .= 'name="' . $id_from . '" id="' . $id_from . '" value="' . $item['from'] . '"/>' . PHP_EOL;
                $string .= '  </div>' . PHP_EOL;
            }
            if ($item['to'] !== FALSE) {
                $string .= '  <div class="input-prepend" id="' . $id_to . '">' . PHP_EOL;
                $string .= '    <span class="add-on btn"><i data-time-icon="icon-time" data-date-icon="icon-calendar"></i> To</span>' . PHP_EOL;
                $string .= '    <input type="text" class="input-medium" data-format="yyyy-MM-dd hh:mm:ss" ';
                $string .= 'name="' . $id_to . '" id="' . $id_to . '" value="' . $item['to'] . '"/>' . PHP_EOL;
                $string .= '  </div>' . PHP_EOL;
            }
            // JS
            $min = '-Infinity';
            $max = 'Infinity';
            $pattern = '/^(\\d{4})-(\\d{2})-(\\d{2}) ([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/';
            if (!empty($item['min'])) {
                if (preg_match($pattern, $item['min'], $matches)) {
                    $matches[2] = $matches[2] - 1;
                    array_shift($matches);
                    $min = 'new Date(' . implode(',', $matches) . ')';
                }
            }
            if (!empty($item['max'])) {
                if (preg_match($pattern, $item['max'], $matches)) {
                    $matches[2] = $matches[2] - 1;
                    array_shift($matches);
                    $max = 'new Date(' . implode(',', $matches) . ')';
                }
            }
            $string .= '
    <script type="text/javascript">
      var startDate = ' . $min . ';
      var endDate   = ' . $max . ';
      $(document).ready(function() {
        $(\'#' . $id_from . '\').datetimepicker({
          //pickSeconds: false,
          weekStart: 1,
          startDate: startDate,
          endDate: endDate
        });
        $(\'#' . $id_to . '\').datetimepicker({
          //pickSeconds: false,
          weekStart: 1,
          startDate: startDate,
          endDate: endDate
        });
      });' . PHP_EOL;
            if ($item['presets']) {
                $string .= '
      $(\'select#' . $item['id'] . '\').change(function() {
        var input_from = $(\'input#' . $id_from . '\');
        var input_to   = $(\'input#' . $id_to . '\');
        switch ($(this).val()) {' . PHP_EOL;
                foreach ($presets as $k => $v) {
                    $preset = datetime_preset($k);
                    $string .= "          case '{$k}':\n";
                    $string .= "            input_from.val('" . $preset['from'] . "');\n";
                    $string .= "            input_to.val('" . $preset['to'] . "');\n";
                    $string .= "            break;\n";
                }
                $string .= '
          default:
            input_from.val("");
            input_to.val("");
            break;
        }
      });' . PHP_EOL;
            }
            $string .= '</script>' . PHP_EOL;
            // End 'datetime'
            break;
        case 'multiselect':
            unset($item['icon']);
            // For now not used icons in multiselect
        // For now not used icons in multiselect
        case 'select':
            if (empty($item['values'])) {
                $item['values'] = array(0 => '[there is no data]');
            }
            if ($item['type'] == 'multiselect') {
                $title = isset($item['name']) ? 'title="' . $item['name'] . '" ' : '';
                $string .= '    <select multiple name="' . $item['id'] . '[]" ' . $title;
            } else {
                $string .= '    <select name="' . $item['id'] . '" ';
                if ($item['name'] && !isset($item['values'][''])) {
                    $item['values'] = array('' => $item['name']) + $item['values'];
                }
            }
            $string .= 'id="' . $item['id'] . '" ';
            $data_width = $item['width'] ? ' data-width="' . $item['width'] . '"' : ' data-width="auto"';
            $data_size = is_numeric($item['size']) ? ' data-size="' . $item['size'] . '"' : ' data-size="15"';
            $string .= 'class="selectpicker show-tick';
            if ($item['right']) {
                $string .= ' pull-right';
            }
            $string .= '" data-selected-text-format="count>2"';
            $string .= $data_width . $data_size . '>' . PHP_EOL . '      ';
            if (!is_array($item['value'])) {
                $item['value'] = array($item['value']);
            }
            foreach ($item['values'] as $k => $name) {
                $k = (string) $k;
                $value = $item['json'] ? base64_encode(json_encode(array($k))) : $k;
                // Use base64+json encoding
                $subtext = $item['subtext'] ? ' data-subtext="(' . $k . ')"' : '';
                $string .= '<option value="' . $value . '"' . $subtext;
                if ($name == '[there is no data]') {
                    $string .= ' disabled';
                }
                if ($item['icon'] && $item['value'] === array('')) {
                    $string .= ' data-icon="' . $item['icon'] . '"';
                    unset($item['icon']);
                }
                if ($k !== '' && in_array($k, $item['value'])) {
                    if ($item['icon']) {
                        $string .= ' data-icon="' . $item['icon'] . '"';
                    }
                    $string .= ' selected';
                }
                $string .= '>' . $name . '</option> ';
            }
            $string .= PHP_EOL . '    </select>' . PHP_EOL;
            // End 'select' & 'multiselect'
            break;
        case 'submit':
            $button_type = 'submit';
            $button_onclick = '';
            $button_class = $item['right'] ? 'btn pull-right' : 'btn';
            if ($item['form_id'] && $item['id'] == 'search') {
                // Note, used script form_to_path() stored in js/observium.js
                $button_type = 'button';
                $button_onclick = " onclick=\"form_to_path('" . $item['form_id'] . "');\"";
            }
            $string .= '      <button type="' . $button_type . '" class="' . $button_class . '" style="line-height: 20px;"' . $button_onclick . '>';
            switch ($item['id']) {
                // Note. 'update' - use POST request, all other - use GET with generate url from js.
                case 'update':
                    $button_icon = 'icon-refresh';
                    $button_name = 'Update';
                    break;
                default:
                    $button_icon = 'icon-search';
                    $button_name = 'Search';
            }
            if ($item['icon']) {
                $button_icon = $item['icon'];
            }
            if ($item['name']) {
                $button_name = $item['name'];
            }
            $string .= '<i class="' . $button_icon . '"></i> ' . $button_name . '</button>' . PHP_EOL;
            // End 'submit'
            break;
        case 'newline':
            // Deprecated
            $string .= '<div class="clearfix" id="' . $item['id'] . '">';
            $string .= $item['hr'] ? '<hr />' : '<hr style="border-width: 0px;" />';
            $string .= '</div>' . PHP_EOL;
            // End 'newline'
            break;
    }
    return $string;
}
/**
 * Generate search form
 *
 * generates a search form.
 * types allowed: select, multiselect, text (or input), datetime, newline
 * 
 * Example of use:
 *  - array for 'select' item type
 *  $search[] = array('type'    => '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
 *                    'value'   => $vars['priority'],
 *                    'values'  => $priorities);
 *  - array for 'text' or 'input' item type
 *  $search[] = array('type'  => 'text',
 *                    'name'  => 'Address',
 *                    'id'    => 'address',
 *                    'width' => '120px',
 *                    '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 'newline' item pseudo type
 *  $search[] = array('type' => 'newline')
 *  print_search_simple($search, 'Title here');
 *
 * @param array $data, string $title
 * @return none
 *
 */
function print_search_simple($data, $title = '', $button = 'search')
{
    // Form header
    $string = PHP_EOL . '<!-- START search form -->' . PHP_EOL;
    $string .= '<form method="POST" action="" class="form form-inline">' . PHP_EOL;
    $string .= '<div class="navbar">' . PHP_EOL;
    $string .= '<div class="navbar-inner">';
    $string .= '<div class="container">';
    if ($title) {
        $string .= '  <a class="brand">' . $title . '</a>' . PHP_EOL;
    }
    $string .= '<div class="nav" style="margin: 5px 0 5px 0;">';
    // Main
    foreach ($data as $item) {
        if (!isset($item['value'])) {
            $item['value'] = '';
        }
        switch ($item['type']) {
            case 'text':
            case 'input':
                $string .= '  <div class="input-prepend">' . PHP_EOL;
                if (!$item['name']) {
                    $item['name'] = '<i class="icon-list"></i>';
                }
                $string .= '    <span class="add-on">' . $item['name'] . '</span>' . PHP_EOL;
                $string .= '    <input type="' . $item['type'] . '" ';
                $string .= isset($item['width']) ? 'style="width:' . $item['width'] . '" ' : '';
                $string .= 'name="' . $item['id'] . '" id="' . $item['id'] . '" class="input" value="' . $item['value'] . '"/>' . PHP_EOL;
                $string .= '  </div>' . PHP_EOL;
                // End 'text' & 'input'
                break;
            case 'newline':
                $string .= '<div class="clearfix" id="' . $item['id'] . '"><hr /></div>' . PHP_EOL;
                // End 'newline'
                break;
            case 'datetime':
                $id_from = $item['id'] . '_from';
                $id_to = $item['id'] . '_to';
                // Presets
                if ($item['presets']) {
                    $presets = array('sixhours' => 'Last 6 hours', 'today' => 'Today', 'yesterday' => 'Yesterday', 'tweek' => 'This week', 'lweek' => 'Last week', 'tmonth' => 'This month', 'lmonth' => 'Last month', 'tyear' => 'This year', 'lyear' => 'Last year');
                    $string .= '    <select id="' . $item['id'] . '" class="selectpicker show-tick" data-size="false" data-width="auto">' . PHP_EOL . '      ';
                    $string .= '<option value="" selected>Date/Time presets</option>';
                    foreach ($presets as $k => $v) {
                        $string .= '<option value="' . $k . '">' . $v . '</option> ';
                    }
                    $string .= PHP_EOL . '    </select>' . PHP_EOL;
                }
                // Date/Time input fields
                $string .= '  <div class="input-prepend" id="' . $id_from . '">' . PHP_EOL;
                $string .= '    <span class="add-on btn"><i data-time-icon="icon-time" data-date-icon="icon-calendar"></i> From</span>' . PHP_EOL;
                $string .= '    <input type="text" class="input-medium" data-format="yyyy-MM-dd hh:mm:ss" ';
                $string .= 'name="' . $id_from . '" id="' . $id_from . '" value="' . $item['from'] . '"/>' . PHP_EOL;
                $string .= '  </div>' . PHP_EOL;
                $string .= '  <div class="input-prepend" id="' . $id_to . '">' . PHP_EOL;
                $string .= '    <span class="add-on btn"><i data-time-icon="icon-time" data-date-icon="icon-calendar"></i> To</span>' . PHP_EOL;
                $string .= '    <input type="text" class="input-medium" data-format="yyyy-MM-dd hh:mm:ss" ';
                $string .= 'name="' . $id_to . '" id="' . $id_to . '" value="' . $item['to'] . '"/>' . PHP_EOL;
                $string .= '  </div>' . PHP_EOL;
                // JS
                $min = '-Infinity';
                $max = 'Infinity';
                $pattern = '/^(\\d{4})-(\\d{2})-(\\d{2}) ([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/';
                if (!empty($item['min'])) {
                    if (preg_match($pattern, $item['min'], $matches)) {
                        $matches[2] = $matches[2] - 1;
                        array_shift($matches);
                        $min = 'new Date(' . implode(',', $matches) . ')';
                    }
                }
                if (!empty($item['max'])) {
                    if (preg_match($pattern, $item['max'], $matches)) {
                        $matches[2] = $matches[2] - 1;
                        array_shift($matches);
                        $max = 'new Date(' . implode(',', $matches) . ')';
                    }
                }
                $string .= '
    <script type="text/javascript">
      var startDate = ' . $min . ';
      var endDate   = ' . $max . ';
      $(document).ready(function() {
	$(\'#' . $id_from . '\').datetimepicker({
          //pickSeconds: false,
          weekStart: 1,
          startDate: startDate,
          endDate: endDate
        });
	$(\'#' . $id_to . '\').datetimepicker({
          //pickSeconds: false,
          weekStart: 1,
          startDate: startDate,
          endDate: endDate
        });
      });' . PHP_EOL;
                if ($item['presets']) {
                    $string .= '
      $(\'select#' . $item['id'] . '\').change(function() {
        var input_from = $(\'input#' . $id_from . '\');
        var input_to   = $(\'input#' . $id_to . '\');
        switch ($(this).val()) {' . PHP_EOL;
                    foreach ($presets as $k => $v) {
                        $preset = datetime_preset($k);
                        $string .= "          case '{$k}':\n";
                        $string .= "            input_from.val('" . $preset['from'] . "');\n";
                        $string .= "            input_to.val('" . $preset['to'] . "');\n";
                        $string .= "            break;\n";
                    }
                    $string .= '
          default:
            input_from.val("");
            input_to.val("");
            break;
        }
      });' . PHP_EOL;
                }
                $string .= '</script>' . PHP_EOL;
                // End 'datetime'
                break;
            case 'select':
            case 'multiselect':
                if ($item['type'] == 'multiselect') {
                    $title = isset($item['name']) ? 'title="' . $item['name'] . '" ' : '';
                    $string .= '    <select multiple name="' . $item['id'] . '[]" ' . $title;
                } else {
                    $string .= '    <select name="' . $item['id'] . '" ';
                    if ($item['name'] && !isset($item['values'][''])) {
                        $item['values'] = array('' => $item['name']) + $item['values'];
                    }
                }
                $string .= 'id="' . $item['id'] . '" ';
                $data_width = $item['width'] ? ' data-width="' . $item['width'] . '"' : ' data-width="auto"';
                $data_size = is_numeric($item['size']) ? ' data-size="' . $item['size'] . '"' : ' data-size="15"';
                $string .= 'class="selectpicker show-tick" data-selected-text-format="count>1"';
                $string .= $data_width . $data_size . '>' . PHP_EOL . '      ';
                if (!is_array($item['value'])) {
                    $item['value'] = array($item['value']);
                }
                foreach ($item['values'] as $k => $v) {
                    $k = (string) $k;
                    $data_subtext = $item['subtext'] ? ' data-subtext="(' . $k . ')"' : '';
                    $string .= '<option value="' . $k . '"' . $data_subtext;
                    $string .= in_array($k, $item['value']) ? ' selected>' : '>';
                    $string .= $v . '</option> ';
                }
                $string .= PHP_EOL . '    </select>' . PHP_EOL;
                // End 'select' & 'multiselect'
                break;
        }
    }
    $string .= '</div>';
    // Form footer
    $string .= '    <ul class="nav pull-right"><li>' . PHP_EOL;
    $string .= '      <input type="hidden" name="pageno" value="1">' . PHP_EOL;
    switch ($button) {
        case 'update':
            $string .= '      <button type="submit" class="btn"><i class="icon-refresh"></i> Update</button>' . PHP_EOL;
            break;
        default:
            $string .= '      <button type="submit" class="btn"><i class="icon-search"></i> Search</button>' . PHP_EOL;
    }
    $string .= '    </li></ul>' . PHP_EOL;
    $string .= '</div></div></div></form>' . PHP_EOL;
    $string .= '<!-- END search form -->' . PHP_EOL . PHP_EOL;
    // Print search form
    echo $string;
}