summaryrefslogtreecommitdiff
path: root/kolab.org/www/drupal-7.18/sites/all/modules/checklistapi/checklistapi.module
blob: c229177a58c1557e425663f4f8c1a025f625473a (plain)
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
<?php

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

/**
 * Access callback: Checks the current user's access to a given checklist.
 *
 * @param string $id
 *   The checklist ID.
 * @param string $operation
 *   (optional) The operation to test access for. Accepted values are "view",
 *   "edit", and "any". Defaults to "any".
 *
 * @return bool
 *   Returns TRUE if the current user has access to perform a given operation on
 *   the specified checklist, or FALSE if not.
 */
function checklistapi_checklist_access($id, $operation = 'any') {
  $all_operations = array('view', 'edit', 'any');
  if (!in_array($operation, $all_operations)) {
    throw new Exception(t('No such operation "@operation"', array(
      '@operation' => $operation,
    )));
  }

  $access['view'] = user_access('view any checklistapi checklist') || user_access('view ' . $id . ' checklistapi checklist');
  $access['edit'] = user_access('edit any checklistapi checklist') || user_access('edit ' . $id . ' checklistapi checklist');
  $access['any'] = $access['view'] || $access['edit'];
  return $access[$operation];
}

/**
 * Loads a checklist object.
 *
 * @param string $id
 *   The checklist ID.
 *
 * @return ChecklistapiChecklist|false
 *   A fully-loaded checklist object, or FALSE if the checklist is not found.
 */
function checklistapi_checklist_load($id) {
  $definition = checklistapi_get_checklist_info($id);
  return ($definition) ? new ChecklistapiChecklist($definition) : FALSE;
}

/**
 * Gets checklist definitions.
 *
 * @param string $id
 *   (optional) A checklist ID. Defaults to NULL.
 *
 * @return array|false
 *   The definition of the specified checklist, or FALSE if no such checklist
 *   exists, or an array of all checklist definitions if none is specified.
 */
function checklistapi_get_checklist_info($id = NULL) {
  $definitions = &drupal_static(__FUNCTION__);
  if (!isset($definitions)) {
    // Get definitions.
    $definitions = module_invoke_all('checklistapi_checklist_info');
    $definitions = checklistapi_sort_array($definitions);
    // Let other modules alter them.
    drupal_alter('checklistapi_checklist_info', $definitions);
    $definitions = checklistapi_sort_array($definitions);
    // Inject checklist IDs.
    foreach ($definitions as $key => $value) {
      $definitions[$key] = array('#id' => $key) + $definitions[$key];
    }
  }
  if (!empty($id)) {
    return (!empty($definitions[$id])) ? $definitions[$id] : FALSE;
  }
  return $definitions;
}

/**
 * Implements hook_help().
 */
function checklistapi_help($path, $arg) {
  foreach (checklistapi_get_checklist_info() as $definition) {
    if ($definition['#path'] == $path && !empty($definition['#help'])) {
      return $definition['#help'];
    }
  }
}

/**
 * Implements hook_init().
 */
function checklistapi_init() {
  // Disable page caching on all Checklist API module paths.
  $module_paths = array_keys(checklistapi_menu());
  if (in_array(current_path(), $module_paths)) {
    drupal_page_is_cacheable(FALSE);
  }
}

/**
 * Implements hook_menu().
 */
function checklistapi_menu() {
  $items = array();

  // Checklists report.
  $items['admin/reports/checklistapi'] = array(
    'title' => 'Checklists',
    'page callback' => 'checklistapi_report_form',
    'access arguments' => array('view checklistapi checklists report'),
    'description' => 'Get an overview of your installed checklists with progress details.',
    'file' => 'checklistapi.admin.inc',
  );

  // Individual checklists.
  foreach (checklistapi_get_checklist_info() as $id => $definition) {
    if (empty($definition['#path']) || empty($definition['#title'])) {
      continue;
    }

    // View/edit checklist.
    $items[$definition['#path']] = array(
      'title' => $definition['#title'],
      'description' => (!empty($definition['#description'])) ? $definition['#description'] : '',
      'page callback' => 'drupal_get_form',
      'page arguments' => array('checklistapi_checklist_form', $id),
      'access callback' => 'checklistapi_checklist_access',
      'access arguments' => array($id),
      'file' => 'checklistapi.pages.inc',
    );
    if (!empty($definition['#menu_name'])) {
      $items[$definition['#path']]['menu_name'] = $definition['#menu_name'];
    }

    // Clear saved progress.
    $items[$definition['#path'] . '/clear'] = array(
      'title' => 'Clear',
      'page callback' => 'drupal_get_form',
      'page arguments' => array('checklistapi_checklist_clear_confirm', $id),
      'access callback' => 'checklistapi_checklist_access',
      'access arguments' => array($id, 'edit'),
      'file' => 'checklistapi.pages.inc',
      'type' => MENU_CALLBACK,
    );

    // Toggle compact mode.
    $items[$definition['#path'] . '/compact'] = array(
      'title' => 'Compact mode',
      'page callback' => 'checklistapi_compact_page',
      'access callback' => 'checklistapi_checklist_access',
      'access arguments' => array($id),
      'file' => 'checklistapi.pages.inc',
      'type' => MENU_CALLBACK,
    );
  }

  return $items;
}

/**
 * Implements hook_permission().
 */
function checklistapi_permission() {
  $perms = array();

  // Universal permissions.
  $perms['view checklistapi checklists report'] = array(
    'title' => t(
      'View the !name report',
      array('!name' => (user_access('view checklistapi checklists report')) ? l(t('Checklists'), 'admin/reports/checklistapi') : drupal_placeholder('Checklists'))
    ),
  );
  $perms['view any checklistapi checklist'] = array(
    'title' => t('View any checklist'),
    'description' => $view_checklist_perm_description = t('Read-only access: View list items and saved progress.'),
  );
  $perms['edit any checklistapi checklist'] = array(
    'title' => t('Edit any checklist'),
    'description' => $edit_checklist_perm_description = t('Check and uncheck list items and save changes, or clear saved progress.'),
  );

  // Per checklist permissions.
  foreach (checklistapi_get_checklist_info() as $id => $definition) {
    if (empty($id)) {
      continue;
    }
    $perms['view ' . $id . ' checklistapi checklist'] = array(
      'title' => t(
        'View the !name checklist',
        array('!name' => (checklistapi_checklist_access($id)) ? l($definition['#title'], $definition['#path']) : drupal_placeholder($definition['#title']))
      ),
      'description' => $view_checklist_perm_description,
    );
    $perms['edit ' . $id . ' checklistapi checklist'] = array(
      'title' => t(
        'Edit the !name checklist',
        array('!name' => (checklistapi_checklist_access($id)) ? l($definition['#title'], $definition['#path']) : drupal_placeholder($definition['#title']))
      ),
      'description' => $edit_checklist_perm_description,
    );
  }

  return $perms;
}

/**
 * Recursively sorts array elements by #weight.
 *
 * @param array $array
 *   A nested array of elements and properties, such as the checklist
 *   definitions returned by hook_checklistapi_checklist_info().
 *
 * @return array
 *   The input array sorted recursively by #weight.
 *
 * @see checklistapi_get_checklist_info()
 */
function checklistapi_sort_array(array $array) {
  $child_keys = element_children($array);

  if (!count($child_keys)) {
    // No children to sort.
    return $array;
  }

  $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.
    $children[$key] = checklistapi_sort_array($children[$key]);
  }
  // Sort by weight.
  uasort($children, 'element_sort');
  // Remove incremental weight hack.
  foreach ($children as $key => $child) {
    $children[$key]['#weight'] = floor($children[$key]['#weight']);
  }
  // Put children back in the main array.
  $array += $children;

  return $array;
}

/**
 * Converts a string to lowerCamel case, suitably for a class property name.
 *
 * @param string $string
 *   The input string.
 *
 * @return string
 *   The input string converted to camelCase.
 */
function checklistapi_strtolowercamel($string) {
  $string = str_replace('_', ' ', $string);
  $string = ucwords($string);
  $string = str_replace(' ', '', $string);
  // Lowercase first character. lcfirst($string) would be nicer, but let's not
  // create a dependency on PHP 5.3 just for that.
  $string[0] = strtolower($string[0]);
  return $string;
}

/**
 * Implements hook_theme().
 */
function checklistapi_theme() {
  return array(
    'checklistapi_compact_link' => array(
      'file' => 'checklistapi.pages.inc',
    ),
    'checklistapi_progress_bar' => array(
      'path' => drupal_get_path('module', 'checklistapi') . '/templates',
      'template' => 'checklistapi-progress-bar',
      'variables' => array(
        'message' => '&nbsp;',
        'number_complete' => 0,
        'number_of_items' => 0,
        'percent_complete' => 0,
      ),
    ),
  );
}