You are here

public static function LogFilter::viewerForm in Log Filter 7

Defines log viewer form and GUI.

Parameters

array $form:

array &$form_state:

Return value

array

1 call to LogFilter::viewerForm()
log_filter_form in ./log_filter.module
Defines log viewer form and GUI.

File

./LogFilter.inc, line 132
Drupal Log Filter module

Class

LogFilter
@file Drupal Log Filter module

Code

public static function viewerForm($form, &$form_state) {
  $path = drupal_get_path('module', 'log_filter');

  //  Get Judy.
  drupal_add_library('judy', 'judy');

  //  Get jQuery UI dialog.
  drupal_add_library('system', 'ui.dialog');

  //  Get jQuery UI datepicker.
  drupal_add_library('system', 'ui.datepicker');

  //  Get jQuery UI autocomplete for username.
  drupal_add_library('system', 'ui.autocomplete');

  //  Have to include own datepicker localisation, because it doesnt seem to exist in neither core nor the Date Popup module.
  drupal_add_js($path . '/js/jquery_ui_datepicker_i18n/jquery.ui.datepicker-' . $GLOBALS['language']->language . '.min.js', array(
    'type' => 'file',
    'group' => JS_DEFAULT,
    'preprocess' => FALSE,
    'every_page' => FALSE,
  ));

  // Use the module's default css.
  if ($use_module_css = variable_get('log_filter_cssdefault', TRUE)) {
    drupal_add_css($path . '/css/log_filter' . '.min' . '.css', array(
      'type' => 'file',
      'group' => CSS_DEFAULT,
      'preprocess' => FALSE,
      'every_page' => FALSE,
    ));
  }

  // Add table header script.
  drupal_add_js('misc/tableheader.js');
  drupal_add_js($path . '/js/log_filter' . '.min' . '.js', array(
    'type' => 'file',
    'group' => JS_DEFAULT,
    'preprocess' => FALSE,
    'every_page' => FALSE,
  ));
  try {
    $allow_filter_edit = user_access('log_filter edit filters');

    //  Get submitted vars from session, and remove them (for later form build and submission).
    $formSubmitted = $session = $settings = $submitted = $messages = NULL;
    if (module_exists('state')) {
      if (($session = State::sessionGet('module', 'log_filter')) && array_key_exists('submitted', $session)) {
        State::sessionRemove('module', 'log_filter', 'submitted');
        State::sessionRemove('module', 'log_filter', 'messages');
      }
    }
    else {
      drupal_session_start();
      if (!empty($_SESSION['module']) && !empty($_SESSION['module']['log_filter'])) {
        $session = $_SESSION['module']['log_filter'];
        unset($_SESSION['module']['log_filter']['submitted']);
        unset($_SESSION['module']['log_filter']['messages']);
      }
    }
    if ($session) {
      if (array_key_exists('settings', $session)) {
        $settings =& $session['settings'];
      }
      if (array_key_exists('submitted', $session)) {
        $formSubmitted = TRUE;
        $submitted =& $session['submitted'];
      }
      if (array_key_exists('messages', $session)) {
        $messages =& $session['messages'];
      }
    }

    //  Get current filter name from url, if any.
    $filter_name = $submitted ? $submitted['filter']['name'] : (($le = strlen($v = arg(self::FILTER_NAME_ARG))) && $le <= 32 && $v != 'log_filter' && $v != 'default' && $v != 'adhoc' && preg_match('/^[a-z_][a-z\\d_]+$/', $v) ? $v : '');
    $require_admin = $submitted ? $submitted['filter']['require_admin'] : FALSE;
    $user_admin_permission = user_access('log_filter administer');

    //  Get mode: default | adhoc | stored (create|edit|delete_filter aren't allowed at form build).
    $mode = $submitted ? $submitted['mode'] : ($filter_name ? 'stored' : 'default');

    //  Stored mode may degrade to default.
    if ($mode == 'stored') {
      $success = TRUE;
      if (!$filter_name) {
        throw new Exception('Filter name[' . $filter_name . '] cannot be empty in mode[stored].');
      }
      if (!($stored_filter = self::_readFilter($filter_name))) {
        $success = FALSE;
        if (!$formSubmitted) {

          // Don't put these errors twice.
          if ($stored_filter === FALSE) {
            drupal_set_message(t('The filter \'!name\' doesn\'t exist.', array(
              '!name' => $filter_name,
            )), 'warning');
          }
          else {
            drupal_set_message(t('You\'re not allowed to use the filter named \'!name\'.', array(
              '!name' => $filter_name,
            )), 'warning');
          }
        }
        $mode = 'default';
      }
      if ($success) {
        $filter = array(
          'origin' => '',
          'description' => $stored_filter['description'],
          'require_admin' => $require_admin = $stored_filter['require_admin'],
        );
        $fields_conditions =& self::$_fields['conditions'];
        $conditions = array();
        foreach ($fields_conditions as $name) {
          switch ($name) {
            case 'time_range':
            case 'time_from':
            case 'time_to':
            case 'role':
              $conditions[$name] = ($v = $stored_filter[$name]) > 0 ? $v : '';
            case 'uid':
              $conditions[$name] = ($v = $stored_filter[$name]) > 0 || $v === '0' || $v === 0 ? $v : '';
              break;
            case 'severity':
              if (!strlen($v = $stored_filter['severity'])) {

                // Deliberately not drupal_...().
                $v = array(
                  '-1',
                );
              }
              else {
                $v = str_replace(',0,', ',zero,', ',' . $v . ',');
                $v = explode(',', substr($v, 1, strlen($v) - 1));

                // Deliberately not drupal_...().
              }
              $conditions['severity'] = $v;
              break;
            case 'type_wildcard':
              $conditions['type_wildcard'] = !$stored_filter['type'] ? TRUE : FALSE;
              break;
            case 'type':
              $conditions['type'] = ($v = $stored_filter['type']) ? explode(',', $v) : array();
              break;
            case 'time_from_proxy':
            case 'time_to_proxy':

              //  Set by frontend, if non-empty time_from/time_to
              $conditions[$name] = '';
              break;
            default:
              $conditions[$name] = $stored_filter[$name];
          }
        }
        unset($fields_conditions);
        $order_by = array();
        if ($v = $stored_filter['order_by']) {
          $le = count($arr = explode(',', $v));
          for ($i = 0; $i < $le; $i++) {
            $v = explode(':', $arr[$i]);
            $order_by[] = array(
              $v[0],
              $v[1] == 'DESC',
            );
          }
        }
        $title = $filter_name . (($v = $filter['description']) ? '<span> - ' . $v . '</span>' : '');
      }
      else {
        $mode = 'default';
        $filter_name = 'default';
      }
      unset($stored_filter);
    }

    //  Do other modes.
    switch ($mode) {
      case 'default':
        $filter = array(
          'origin' => '',
          'description' => '',
          'require_admin' => FALSE,
        );
        $fields_conditions =& self::$_fields['conditions'];
        $conditions = array();
        foreach ($fields_conditions as $name) {
          switch ($name) {
            case 'severity':
              $conditions[$name] = array(
                '-1',
              );
              break;
            case 'type_wildcard':
              $conditions[$name] = TRUE;
              break;
            case 'type':
              $conditions[$name] = array();
              break;
            default:
              $conditions[$name] = '';
          }
        }
        unset($fields_conditions);
        $order_by = array(
          array(
            'time',
            TRUE,
          ),
        );
        $title = t('Default');
        break;
      case 'adhoc':
        $filter =& $submitted['filter'];
        $conditions =& $submitted['conditions'];
        if (!$conditions['severity']) {
          $conditions['severity'] = array(
            '-1',
          );
        }
        $order_by =& $submitted['order_by'];
        $title = t('Ad hoc') . (($v = $filter['origin']) ? '<span> - ' . t('based on !origin', array(
          '!origin' => $v,
        )) . '</span>' : '');
        break;
      case 'stored':

        //  Done earlier.
        break;
      case 'create':
      case 'edit':
      case 'delete_filter':
        throw new Exception('Mode[' . $mode . '] not allowed at form build.', self::$_errorCodes['algo']);
        break;
      default:
        throw new Exception('Unsupported mode[' . $mode . '].', self::$_errorCodes['algo']);
    }

    //  Prepare some fields.
    //  Type (frontend: type_some).
    if ($options_type = db_select('watchdog')
      ->fields('watchdog', array(
      'type',
    ))
      ->distinct()
      ->execute()
      ->fetchCol()) {
      sort($options_type);
      foreach ($options_type as &$v) {
        $v = str_replace(array(
          "\r",
          "\n",
          ',',
        ), ' ', $v);
      }
      unset($v);

      // Clear reference.
      $options_type = array_combine($options_type, $options_type);

      //  The filter may contain types that do not exist currently.
      $prepend_types = array();
      if ($conditions['type']) {
        foreach ($conditions['type'] as $v) {
          if ($v) {
            if (isset($options_type[$v])) {
              unset($options_type[$v]);
            }
            $prepend_types[$v] = $v;
          }
        }
        if ($prepend_types) {
          $options_type = array_merge($prepend_types, $options_type);
        }
      }
    }
    elseif ($conditions['type']) {
      $options_type = $conditions['type'];
    }
    else {

      // Make sure that there's always at least a single option.
      $options_type = array(
        'php' => 'php',
      );
    }

    //  Severity.
    $options_severity = array(
      '-1' => t('Any'),
      'zero' => t('emergency'),
      '1' => t('alert'),
      '2' => t('critical'),
      '3' => t('error'),
      '4' => t('warning'),
      '5' => t('notice'),
      '6' => t('info'),
      '7' => t('debug'),
    );

    //  Role.
    $options_role = user_roles();
    foreach ($options_role as &$v) {
      $v = t($v);
    }
    unset($v);

    // Clear reference.
    $options_role = array(
      '' => t('Any'),
    ) + $options_role;

    // Union operator (+) doesnt re-index numerical keys like array_merge() does.
    //  Order by.
    $options_order_by = array(
      '' => '',
      'time' => t('Time'),
      'severity' => t('Severity'),
      'type' => t('Type'),
      'role' => t('User role'),
      'uid' => t('User ID'),
      'hostname' => t('Visitor\'s hostname'),
      'location' => t('Location'),
      'referer' => t('Referrer'),
    );
    $length_order_by = count($order_by);

    //  Only own filters.
    $value_only_own = $settings && array_key_exists('only_own', $settings) ? $settings['only_own'] : FALSE;

    //  Filter selector.
    $uid = $GLOBALS['user']->uid;
    if ($options_filters = self::_listFilters(!$value_only_own ? NULL : array(
      $uid,
    ), array(
      'name',
    ), array(
      array(
        'name',
      ),
    ), $uid)) {
      $js_filters = '["' . join('","', $options_filters) . '"]';
      $options_filters = array_merge(array(
        '' => t('Default'),
      ), array_combine($options_filters, $options_filters));
    }
    else {
      $js_filters = '[]';
      $options_filters = array(
        '' => t('Default'),
      );
    }

    //  Get current theme.
    $theme = $GLOBALS['theme'];

    //  Build form.
    $form['#attributes'] = array(
      'autocomplete' => 'off',
    );
    $form['log_filter_filter_edit'] = array(
      '#type' => 'fieldset',
      '#title' => t('Filter') . ': <span id="log_filter_title_display">' . $title . '</span>',
      '#collapsible' => TRUE,
      '#collapsed' => FALSE,
      'frontend_init' => array(
        '#type' => 'markup',
        '#markup' => '<script type="text/javascript"> LogFilter.init(' . (int) $use_module_css . ', "' . $theme . '"); </script>',
      ),
      //  Control vars.
      'log_filter_mode' => array(
        '#type' => 'hidden',
        '#default_value' => $mode,
      ),
      'log_filter_name' => array(
        '#type' => 'hidden',
        '#default_value' => $filter_name,
      ),
      'log_filter_origin' => array(
        '#type' => 'hidden',
        '#default_value' => $filter['origin'],
      ),
      //  Conditions.
      //  Time.
      'log_filter_time_range' => array(
        // (3 open)
        '#type' => 'textfield',
        '#title' => t('Preceding hours'),
        '#default_value' => $conditions['time_range'] ? $conditions['time_range'] : '',
        '#size' => 2,
        '#prefix' => '<div id="log_filter_criteria"><div class="filter-conditions"><div class="form-item log-filter-time">' . '<label>' . t('Time') . '</label>',
      ),
      'log_filter_time_from_proxy' => array(
        '#type' => 'textfield',
        '#title' => t('From') . '<span>?</span>',
        '#default_value' => '',
        // Frontend sets it, if non-empty time_from.
        '#size' => 10,
        '#prefix' => '<div class="log-filter-time-or">' . t('or') . '</div>',
      ),
      'log_filter_time_from' => array(
        '#type' => 'hidden',
        '#default_value' => $conditions['time_from'],
      ),
      'log_filter_time_to_proxy' => array(
        '#type' => 'textfield',
        '#title' => t('To'),
        '#default_value' => '',
        // Frontend sets it, if non-empty time_to.
        '#size' => 10,
      ),
      'log_filter_time_to' => array(
        // End: log-filter-time (2 open).
        '#type' => 'hidden',
        '#default_value' => $conditions['time_to'],
        '#suffix' => '</div>',
      ),
      //  Severity.
      'log_filter_severity' => array(
        '#type' => 'checkboxes',
        '#title' => t('Severity'),
        '#multiple' => TRUE,
        '#options' => $options_severity,
        '#default_value' => $conditions['severity'],
      ),
      //  Type.
      'log_filter_type_wildcard' => array(
        // (3 open).
        '#type' => 'checkbox',
        '#title' => t('Any'),
        '#default_value' => $conditions['type_wildcard'],
        '#prefix' => '<div class="form-item log-filter-type">' . '<label>' . t('Type') . '</label>',
      ),
      'log_filter_type_proxy' => array(
        '#type' => 'checkboxes',
        '#options' => $options_type,
        '#default_value' => array(),
        '#prefix' => '<div class="log-filter-type-container">',
      ),
      'log_filter_type' => array(
        // End: log-filter-type (2 open).
        '#type' => 'textarea',
        '#default_value' => join("\n", $conditions['type']),
        '#resizable' => FALSE,
        '#suffix' => '</div></div>',
      ),
      //  Various.
      'log_filter_role' => array(
        // (4 open).
        '#type' => 'select',
        '#title' => t('User role'),
        '#options' => $options_role,
        '#default_value' => $conditions['role'],
        '#prefix' => '<div class="form-item log-filter-various"><div class="log-filter-user">',
      ),
      'log_filter_uid' => array(
        '#type' => 'textfield',
        '#title' => t('ID'),
        '#default_value' => $conditions['uid'],
        '#size' => 11,
      ),
      'log_filter_username' => array(
        // End: log-filter-user (3 open).
        '#type' => 'textfield',
        '#title' => t('Name'),
        '#default_value' => $conditions['uid'],
        '#size' => 20,
        // Can't use Drupal Form API autocomplete, because we need to pass value to the uid field upon selection.
        '#attributes' => array(
          'class' => array(
            'form-autocomplete',
          ),
        ),
        '#suffix' => '</div>',
      ),
      'log_filter_hostname' => array(
        '#type' => 'textfield',
        '#title' => t('Visitor\'s hostname') . '<span title="' . t('Use * to display in event list, without filtering') . '">?</span>',
        '#default_value' => $conditions['hostname'],
        '#size' => 64,
      ),
      'log_filter_location' => array(
        '#type' => 'textfield',
        '#title' => t('Location') . '<span title="' . t('Use * to display in event list, without filtering') . '">?</span>',
        '#default_value' => $conditions['location'],
        '#size' => 64,
      ),
      'log_filter_referer' => array(
        // End: filter-conditions, (1 open).
        '#type' => 'textfield',
        '#title' => t('Referrer') . '<span title="' . t('Use \'none\' for empty referrer.!nlUse * to display in event list, without filtering.', array(
          '!nl' => "\n",
        )) . '">?</span>',
        '#default_value' => $conditions['referer'],
        '#size' => 64,
        '#suffix' => '</div></div>',
      ),
      //  Order by.
      'log_filter_orderby_1' => array(
        // (2 open)
        '#type' => 'select',
        '#options' => $options_order_by,
        '#default_value' => $length_order_by ? array(
          $order_by[0][0],
        ) : array(),
        '#prefix' => '<div class="filter-orderby"><label>' . t('Order by') . '</label>',
      ),
      'log_filter_descending_1' => array(
        '#type' => 'checkbox',
        '#default_value' => $length_order_by ? $order_by[0][1] : FALSE,
        '#attributes' => array(
          'title' => t('Descending'),
        ),
      ),
      'log_filter_orderby_2' => array(
        '#type' => 'select',
        '#options' => $options_order_by,
        '#default_value' => $length_order_by > 1 ? array(
          $order_by[1][0],
        ) : array(),
      ),
      'log_filter_descending_2' => array(
        '#type' => 'checkbox',
        '#default_value' => $length_order_by > 1 ? $order_by[1][1] : FALSE,
        '#attributes' => array(
          'title' => t('Descending'),
        ),
      ),
      'log_filter_orderby_3' => array(
        '#type' => 'select',
        '#options' => $options_order_by,
        '#default_value' => $length_order_by > 2 ? array(
          $order_by[2][0],
        ) : array(),
      ),
      'log_filter_descending_3' => array(
        '#type' => 'checkbox',
        '#default_value' => $length_order_by > 2 ? $order_by[2][1] : FALSE,
        '#attributes' => array(
          'title' => t('Descending'),
        ),
      ),
      'log_filter_reset' => array(
        // End: log-filter-reset, filter-orderby, log_filter_criteria (0 open).
        '#type' => 'button',
        '#name' => 'log_filter_reset',
        '#value' => t('Reset'),
        '#button_type' => 'button',
        // Doesnt work; still type:submit.
        '#attributes' => array(
          'type' => 'button',
          // Doesnt work; still type:submit.
          'class' => array(
            'form-submit',
            'edit-reset',
          ),
        ),
        '#prefix' => '<div class="log-filter-reset">',
        '#suffix' => '</div></div></div>',
      ),
      //  Filters.
      array(
        '#type' => 'markup',
        '#markup' => '<div id="log_filter_filters"><div id="log_filter_box_filter"><div id="log_filter_filters_cell_0">',
      ),
      'log_filter_filter' => array(
        // (2 open)
        '#type' => 'select',
        '#title' => t('Filter'),
        '#options' => $options_filters,
        '#default_value' => $filter_name,
      ),
      'log_filter_only_own' => array(
        '#access' => $allow_filter_edit,
        '#type' => 'checkbox',
        '#title' => t('List my filters only'),
        '#default_value' => $value_only_own,
      ),
      array(
        '#type' => 'markup',
        '#markup' => '</div>' . '<div id="log_filter_filters_cell_1">',
      ),
      'log_filter_name_suggest' => array(
        '#access' => $allow_filter_edit,
        '#type' => 'textfield',
        '#title' => t('Name'),
        '#default_value' => '',
        // Only used frontend.
        '#size' => 32,
        '#attributes' => array(
          'maxlength' => 32,
        ),
      ),
      'log_filter_require_admin' => array(
        '#access' => $allow_filter_edit && $user_admin_permission,
        '#type' => 'checkbox',
        '#title' => t('Restrict access') . '<span title="' . ($title = t('Require the \'Administer log filtering\' permission.')) . '">?</span>',
        '#default_value' => $require_admin,
        '#attributes' => array(
          'title' => $title,
        ),
      ),
      array(
        // End: log_filter_filters_cell_1
        '#type' => 'markup',
        '#markup' => '</div>',
      ),
      'log_filter_description' => array(
        '#access' => $allow_filter_edit,
        '#type' => 'textarea',
        '#title' => t('Description'),
        '#default_value' => $filter['description'],
        '#rows' => 3,
        '#cols' => 32,
        '#resizable' => FALSE,
      ),
      array(
        // (3 open)
        '#type' => 'markup',
        '#markup' => '<div class="log-filter-edit-create">',
      ),
      'log_filter_edit' => array(
        '#access' => $allow_filter_edit,
        '#type' => 'button',
        '#name' => 'log_filter_edit',
        '#value' => t('Edit'),
        '#button_type' => 'button',
        // Doesnt work; still type:submit.
        '#attributes' => array(
          'type' => 'button',
          // Doesnt work; still type:submit.
          'class' => array(
            'form-submit',
          ),
          'style' => 'display:none;',
        ),
      ),
      'log_filter_create' => array(
        // (2 open)
        '#access' => $allow_filter_edit,
        '#type' => 'button',
        '#name' => 'log_filter_create',
        '#value' => t('Save as...'),
        '#button_type' => 'button',
        // Doesnt work; still type:submit.
        '#attributes' => array(
          'type' => 'button',
          // Doesnt work; still type:submit.
          'class' => array(
            'form-submit',
          ),
          'style' => 'display:none;',
        ),
      ),
      array(
        '#type' => 'markup',
        '#markup' => '</div>' . '<div class="log-filter-cancel-save' . (strpos(strtolower(PHP_OS), 'win') === 0 ? ' log-filter-reversed-button-sequence' : '') . '">',
      ),
      'log_filter_cancel' => array(
        // (3 open)
        '#access' => $allow_filter_edit,
        '#type' => 'button',
        '#name' => 'log_filter_cancel',
        '#value' => t('Cancel'),
        '#button_type' => 'button',
        // Doesnt work; still type:submit.
        '#attributes' => array(
          'type' => 'button',
          // Doesnt work; still type:submit.
          'class' => array(
            'form-submit',
            'edit-cancel',
          ),
          'style' => 'display:none;',
        ),
      ),
      'log_filter_save' => array(
        '#access' => $allow_filter_edit,
        '#type' => 'button',
        '#name' => 'log_filter_save',
        '#value' => t('Save'),
        '#button_type' => 'button',
        // Doesnt work; still type:submit.
        '#attributes' => array(
          'type' => 'button',
          // Doesnt work; still type:submit.
          'class' => array(
            'form-submit',
          ),
          'style' => 'display:none;',
        ),
      ),
      array(
        '#type' => 'markup',
        '#markup' => '</div>' . '<div class="log-filter-delete">',
      ),
      'log_filter_delete' => array(
        '#access' => $allow_filter_edit,
        '#type' => 'button',
        '#name' => 'log_filter_delete',
        '#value' => t('Delete filter'),
        '#button_type' => 'button',
        // Doesnt work; still type:submit.
        '#attributes' => array(
          'type' => 'button',
          // Doesnt work; still type:submit.
          'class' => array(
            'form-submit',
            'edit-delete',
          ),
          'style' => 'display:none;',
        ),
      ),
      array(
        '#type' => 'markup',
        '#markup' => '</div>' . '</div>',
      ),
      array(
        '#access' => $allow_delete_logs = user_access('log_filter remove logs'),
        '#type' => 'markup',
        '#markup' => '<div id="log_filter_box_delete_logs">',
      ),
      array(
        '#access' => !$allow_delete_logs,
        '#type' => 'markup',
        '#markup' => '<div id="log_filter_box_delete_logs" class="log-filter-delete-logs-none">&nbsp;',
      ),
      array(
        // (2 open)
        '#access' => $allow_delete_logs,
        '#type' => 'button',
        '#name' => 'log_filter_delete_logs_button',
        '#value' => t('Delete logs'),
        '#button_type' => 'button',
        // Doesnt work; still type:submit.
        '#attributes' => array(
          'type' => 'button',
          // Doesnt work; still type:submit.
          'class' => array(
            'form-submit',
            'edit-delete',
          ),
          'style' => 'display:none;',
        ),
      ),
      array(
        '#access' => $allow_delete_logs,
        '#type' => 'textfield',
        '#name' => 'log_filter_delete_logs_max',
        '#title' => t('Max.'),
        '#default_value' => $settings && array_key_exists('delete_logs_max', $settings) ? $settings['delete_logs_max'] : '',
        '#attributes' => array(
          'maxlength' => 11,
        ),
      ),
      array(
        '#type' => 'markup',
        '#markup' => '</div>' . '</div>',
      ),
    );
    $form['log_filter_list_controls'] = array(
      'frontend_setup' => array(
        '#type' => 'markup',
        '#markup' => '<script type="text/javascript">
(function($) {
  if(!$) {
    return;
  }
  $(document).bind("ready", function() {
    var elm;
    // t() ruins this, because of some hocus pocus.
    $("div.form-item-log-filter-time-from-proxy label").get(0).setAttribute("title", "' . t('Date format: YYYY-MM-DD!newlineTime formats: N, NN, NNNN, NNNNNN, NN:NN, NN:NN:NN') . '".replace(/\\!newline/, "\\n"));
    // Go.
    LogFilter.setup(
      ' . $js_filters . ',
      ' . ($messages ? json_encode($messages) : 'null') . '
    );
  } );
})(jQuery);
</script>
',
      ),
      'log_filter_update_list' => array(
        '#type' => 'button',
        '#name' => 'log_filter_update_list',
        '#value' => t('Update list'),
        '#button_type' => 'button',
        // Doesnt work; still type:submit.
        '#attributes' => array(
          'class' => array(
            'form-submit',
          ),
          'title' => t('[CTR + U / CMD + U]'),
        ),
        '#prefix' => '<div class="log-filter-button log-filter-update-list">',
        '#suffix' => '</div>',
      ),
      'log_filter_pager_controls' => array(
        '#type' => 'markup',
        '#markup' => '<div class="log-filter-pager-controls">' . '<div id="log_filter_pager_first" class="log-filter-pager-button log-filter-pager-button-disabled" title="' . t('First') . '">&#x25c4;&#x25c4;</div>' . '<div id="log_filter_pager_previous" class="log-filter-pager-button log-filter-pager-button-disabled" title="' . t('Previous') . '">&#x25c4;</div>' . '<div id="log_filter_pager_current" title="' . t('Update list') . '">&nbsp;</div>' . '<div id="log_filter_pager_progress" class="ajax-progress"><div class="throbber"></div>' . t('Loading...') . '</div>' . '<div id="log_filter_pager_next" class="log-filter-pager-button log-filter-pager-button-disabled" title="' . t('Next') . '">&#x25ba;</div>' . '<div id="log_filter_pager_last" class="log-filter-pager-button log-filter-pager-button-disabled" title="' . t('Last') . '">&#x25ba;&#x25ba;</div>' . '</div>',
      ),
      'log_filter_pager_range' => array(
        '#type' => 'textfield',
        '#title' => t('Logs per page'),
        '#default_value' => $settings && array_key_exists('pager_range', $settings) && $settings['pager_range'] > 0 ? $settings['pager_range'] : variable_get('log_filter_pgrng', self::PAGE_RANGE_DEFAULT),
        '#size' => 4,
      ),
      'log_filter_translate' => array(
        '#type' => 'checkbox',
        '#title' => t('Translate messages') . '<span title="' . ($title = t('Translating messages is heavy performance-wise.')) . '">?</span>',
        '#default_value' => $settings && array_key_exists('translate', $settings) ? $settings['translate'] : variable_get('log_filter_trnslt', 0),
        '#attributes' => array(
          'title' => $title,
        ),
      ),
      'actions' => array(
        '#type' => 'actions',
        'submit' => array(
          '#type' => 'submit',
          '#value' => t('Update list'),
          '#attributes' => array(
            'style' => 'display:none;',
          ),
        ),
      ),
      '#prefix' => '<div id="log_filter_list_controls">',
      '#suffix' => '</div>',
    );
    $logList = '';
    for ($i = 97; $i < 97 + 26; $i++) {

      //$logList .= '<div class="' . str_repeat(chr($i), 3) . '">' . str_repeat(chr($i), 3) . '</div>';
    }
    $form['log_filter_log_list'] = array(
      '#type' => 'markup',
      '#markup' => '<div id="log_filter_log_list" class="scrollable">' . $logList . '</div>',
    );

    //  Add our submit form;
    $form['#submit'][] = '_log_filter_form_submit';
    return $form;
  } catch (Exception $xc) {
    self::_errorHandler($xc);
    drupal_set_message($xc
      ->getMessage(), 'error');
    return array();
  }
}