ChecklistapiChecklistForm.php 6.53 KB
Newer Older
1 2 3 4 5 6 7 8 9
<?php

/**
 * @file
 * Contains \Drupal\checklistapi\Form\ChecklistapiChecklistForm.
 */

namespace Drupal\checklistapi\Form;

10
use Drupal\Component\Utility\Xss;
11
use Drupal\Core\Form\FormInterface;
12
use Drupal\Core\Form\FormStateInterface;
13
use Drupal\Core\Render\Element;
14
use Drupal\Core\Url;
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30

/**
 * Provides a checklist form.
 */
class ChecklistapiChecklistForm implements FormInterface {

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'checklistapi_checklist_form';
  }

  /**
   * {@inheritdoc}
   */
31
  public function buildForm(array $form, FormStateInterface $form_state, $checklist_id = NULL) {
32 33
    $form['#checklist'] = $checklist = checklistapi_checklist_load($checklist_id);
    $user_has_edit_access = $checklist->userHasAccess('edit');
34
    $renderer = \Drupal::service('renderer');
35 36

    // Progress bar.
37
    $progress_bar = [
38
      '#theme' => 'checklistapi_progress_bar',
39
      '#message' => ($checklist->hasSavedProgress()) ? t('Last updated @date by !user', [
40 41
        '@date' => $checklist->getLastUpdatedDate(),
        '!user' => $checklist->getLastUpdatedUser(),
42
      ]) : '',
43 44 45
      '#number_complete' => $checklist->getNumberCompleted(),
      '#number_of_items' => $checklist->getNumberOfItems(),
      '#percent_complete' => (int) round($checklist->getPercentComplete()),
46 47
    ];
    $form['progress_bar'] = [
48
      '#type' => 'markup',
49
      '#markup' => $renderer->render($progress_bar),
50
    ];
51 52

    // Compact mode.
53
    if (checklistapi_compact_mode_is_on()) {
54
      $form['#attributes']['class'] = ['compact-mode'];
55
    }
56 57
    $compact_link = ['#markup' => '<div class="compact-link"></div>'];
    $form['compact_mode_link'] = [
58
      '#markup' => $renderer->render($compact_link),
59
    ];
60 61

    // General properties.
62 63 64 65
    $form['checklistapi'] = [
      '#attached' => [
        'library' => ['checklistapi/checklistapi'],
      ],
66 67
      '#tree' => TRUE,
      '#type' => 'vertical_tabs',
68
    ];
69 70 71 72 73 74

    // Loop through groups.
    $num_autochecked_items = 0;
    $groups = $checklist->items;
    foreach (Element::children($groups) as $group_key) {
      $group = &$groups[$group_key];
75
      $form[$group_key] = [
76
        '#title' => Xss::filter($group['#title']),
77 78
        '#type' => 'details',
        '#group' => 'checklistapi',
79
      ];
80
      if (!empty($group['#description'])) {
81
        $form[$group_key]['#description'] = Xss::filterAdmin($group['#description']);
82 83 84 85 86 87 88
      }

      // Loop through items.
      foreach (Element::children($group) as $item_key) {
        $item = &$group[$item_key];
        $saved_item = !empty($checklist->savedProgress[$item_key]) ? $checklist->savedProgress[$item_key] : 0;
        // Build title.
89
        $title = Xss::filter($item['#title']);
90 91
        if ($saved_item) {
          // Append completion details.
92
          $user = [
93 94
            '#theme' => 'username',
            '#account' => user_load($saved_item['#uid']),
95
          ];
96 97
          $title .= t(
            '<span class="completion-details"> - Completed @time by !user</a>',
98
            [
99
              '@time' => format_date($saved_item['#completed'], 'short'),
100
              '!user' => \Drupal::service('renderer')->render($user),
101
            ]
102 103 104 105 106 107 108 109 110 111 112 113 114
          );
        }
        // Set default value.
        $default_value = FALSE;
        if ($saved_item) {
          $default_value = TRUE;
        }
        elseif (!empty($item['#default_value'])) {
          if ($default_value = $item['#default_value']) {
            $num_autochecked_items++;
          }
        }
        // Get description.
115
        $description = (isset($item['#description'])) ? '<p>' . Xss::filterAdmin($item['#description']) . '</p>' : '';
116
        // Append links.
117
        $links = [];
118 119
        foreach (Element::children($item) as $link_key) {
          $link = &$item[$link_key];
120
          $links[] = \Drupal::l($link['#text'], $link['#url']);
121 122 123 124 125
        }
        if (count($links)) {
          $description .= '<div class="links">' . implode(' | ', $links) . '</div>';
        }
        // Compile the list item.
126 127
        $form[$group_key][$item_key] = [
          '#attributes' => ['class' => ['checklistapi-item']],
128
          '#default_value' => $default_value,
129
          '#description' => Xss::filterAdmin($description),
130
          '#disabled' => !($user_has_edit_access),
131
          '#title' => Xss::filterAdmin($title),
132 133
          '#type' => 'checkbox',
          '#group' => $group_key,
134 135
          '#parents' => ['checklistapi', $group_key, $item_key],
        ];
136 137 138 139
      }
    }

    // Actions.
140
    $form['actions'] = [
141 142 143
      '#access' => $user_has_edit_access,
      '#type' => 'actions',
      '#weight' => 100,
144
      'save' => [
145 146 147
        '#button_type' => 'primary',
        '#type' => 'submit',
        '#value' => t('Save'),
148 149
      ],
      'clear' => [
150 151
        '#access' => $checklist->hasSavedProgress(),
        '#button_type' => 'danger',
152 153
        '#attributes' => ['class' => ['clear-saved-progress']],
        '#submit' => [[$this, 'clear']],
154 155
        '#type' => 'submit',
        '#value' => t('Clear saved progress'),
156 157
      ],
    ];
158 159 160 161 162

    // Alert the user of autochecked items. Only set the message on GET requests
    // to prevent it from reappearing after saving the form. (Testing the
    // request method may not be the "correct" way to accomplish this.)
    if ($num_autochecked_items && $_SERVER['REQUEST_METHOD'] == 'GET') {
163
      $args = [
164 165
        '%checklist' => $checklist->title,
        '@num' => $num_autochecked_items,
166
      ];
167 168 169 170 171 172 173 174 175 176 177 178 179
      $message = \Drupal::translation()->formatPlural(
        $num_autochecked_items,
        t('%checklist found 1 unchecked item that was already completed and checked it for you. Save the form to record the change.', $args),
        t('%checklist found @num unchecked items that were already completed and checked them for you. Save the form to record the changes.', $args)
      );
      drupal_set_message($message, 'status');
    }
    return $form;
  }

  /**
   * {@inheritdoc}
   */
180
  public function validateForm(array &$form, FormStateInterface $form_state) {}
181 182 183 184

  /**
   * {@inheritdoc}
   */
185 186 187
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $values = $form_state->getValue('checklistapi');
    $form['#checklist']->saveProgress($values);
188 189 190 191 192 193 194
  }

  /**
   * Form submission handler for the 'clear' action.
   *
   * @param array $form
   *   An associative array containing the structure of the form.
195 196
   * @param \Drupal\Core\Form\FormStateInterface $form_state
   *   The current state of the form.
197
   */
198 199
  public function clear(array &$form, FormStateInterface $form_state) {
    $form_state->setRedirect($form['#checklist']->getRouteName() . '.clear');
200 201 202
  }

}