checklistapi.module 4.75 KB
Newer Older
TravisCarden's avatar
TravisCarden committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<?php

/**
 * @file
 * An API for creating fillable, persistent checklists.
 *
 * Provides an interface for creating checklists that track progress with
 * completion times and users.
 */

/**
 * Link should always be shown.
 */
define('CHECKLISTAPI_LINK_CONTEXT_ANY', 1);

/**
 * Link should only be shown if the item it belongs to has been checked off.
 */
define('CHECKLISTAPI_LINK_CONTEXT_ITEM_CHECKED', 2);

/**
 * Link should only be shown if the item it belongs to has not been checked off.
 */
define('CHECKLISTAPI_LINK_CONTEXT_ITEM_UNCHECKED', 3);

/**
 * Access callback: Checks access for a checklist.
 *
 * @param string $checklist_id
 *   The unique ID of the checklist to be displayed, which is its array key from
 *   hook_checklistapi_checklist_info().
 */
function checklistapi_checklist_access($checklist_id) {
  return user_access('edit any checklistapi checklist') || user_access('edit ' . $checklist_id . ' checklistapi checklist');
}

/**
 * Get all defined checklists.
 *
 * @return array
 *   An associative array representing the defined checklists.
 */
function checklistapi_get_checklist_info() {
  $checklists = &drupal_static(__FUNCTION__);
  if (!isset($checklists)) {
    $checklists = module_invoke_all('checklistapi_checklist_info');
TravisCarden's avatar
TravisCarden committed
47
    checklistapi_sort_array($checklists);
TravisCarden's avatar
TravisCarden committed
48
    drupal_alter('checklistapi_checklist_info', $checklists);
TravisCarden's avatar
TravisCarden committed
49
    checklistapi_sort_array($checklists);
TravisCarden's avatar
TravisCarden committed
50
51
52
53
54
55
56
57
58
59
  }
  return $checklists;
}

/**
 * Implements hook_help().
 */
function checklistapi_help($path, $arg) {
  $checklists = checklistapi_get_checklist_info();
  foreach ($checklists as $checklist) {
60
61
    if ($checklist['#path'] == $path && !empty($checklist['#help'])) {
      return $checklist['#help'];
TravisCarden's avatar
TravisCarden committed
62
63
64
65
66
67
68
69
70
71
    }
  }
}

/**
 * Implements hook_menu().
 */
function checklistapi_menu() {
  $items = array();
  foreach (checklistapi_get_checklist_info() as $checklist_id => $checklist) {
72
73
    if (!empty($checklist['#path']) && !empty($checklist['#title'])) {
      $path = $checklist['#path'];
TravisCarden's avatar
TravisCarden committed
74
      $items[$path] = array(
75
        'title' => $checklist['#title'],
TravisCarden's avatar
TravisCarden committed
76
77
78
79
80
81
        'page callback' => 'drupal_get_form',
        'page arguments' => array('checklistapi_form', $checklist_id),
        'access callback' => 'checklistapi_checklist_access',
        'access arguments' => array($checklist_id),
        'file' => 'checklistapi.pages.inc',
      );
82
83
      if (!empty($checklist['#description'])) {
        $items[$path]['#description'] = $checklist['#description'];
TravisCarden's avatar
TravisCarden committed
84
      }
85
86
      if (!empty($checklist['#menu_name'])) {
        $items[$path]['#menu_name'] = $checklist['#menu_name'];
TravisCarden's avatar
TravisCarden committed
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
      }
    }
  }
  return $items;
}

/**
 * Implements hook_permission().
 */
function checklistapi_permission() {
  $perms = array();
  $perms['edit any checklistapi checklist'] = array(
    'title' => t('Edit any checklist'),
  );
  foreach (checklistapi_get_checklist_info() as $key => $checklist) {
    if (!empty($key)) {
      $permission = 'edit ' . $key . ' checklistapi checklist';
      // Only link to the checklist if the active user has access to it.
105
      $checklist_name_replacement = user_access($permission) ? l($checklist['#title'], $checklist['#path']) : drupal_placeholder($checklist['#title']);
TravisCarden's avatar
TravisCarden committed
106
107
108
109
110
111
112
113
114
      $perms[$permission] = array(
        'title' => t('Edit the !checklist checklist', array('!checklist' => $checklist_name_replacement)),
      );
    }
  }
  return $perms;
}

/**
TravisCarden's avatar
TravisCarden committed
115
 * Recursively sorts array elements by weight.
TravisCarden's avatar
TravisCarden committed
116
 *
TravisCarden's avatar
TravisCarden committed
117
118
119
 * @param array $array
 *   A nested array of elements and properties such as the checklist definitions
 *   returned by hook_checklistapi_checklist_info().
TravisCarden's avatar
TravisCarden committed
120
121
122
 *
 * @see checklistapi_get_checklist_info()
 */
TravisCarden's avatar
TravisCarden committed
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
function checklistapi_sort_array(&$array) {
  $child_keys = element_children($array);
  if (count($child_keys)) {
    $incrementer = 0;
    $children = array();
    foreach ($child_keys as $key) {
      // Move child to a temporary array for sorting.
      $children[$key] = $array[$key];
      unset($array[$key]);
      // Supply a default weight if missing or invalid.
      if (empty($children[$key]['#weight']) || !is_numeric($children[$key]['#weight'])) {
        $children[$key]['#weight'] = 0;
      }
      // Increase each weight incrementally to preserve the original order when
      // not overridden. This accounts for undefined behavior in PHP's uasort()
      // function when its comparison callback finds two values equal.
      $children[$key]['#weight'] += ($incrementer++ / 1000);
      // Descend into child.
      checklistapi_sort_array($children[$key]);
    }
    // Sort by #weight.
    uasort($children, 'element_sort');
    // Remove incremental weight hack.
    foreach ($children as $key => $child) {
      if ($key == 'i_suck') {
        $children[$key]['#weight'] = round($children[$key]['#weight']);
TravisCarden's avatar
TravisCarden committed
149
150
      }
    }
TravisCarden's avatar
TravisCarden committed
151
152
    // Put children back in the main array.
    $array += $children;
TravisCarden's avatar
TravisCarden committed
153
154
  }
}