123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 |
- <?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 checklist.
- *
- * @param string $id
- * The checklist ID.
- * @param string $operation
- * The operation to test access for. Possible 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') {
- $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'];
- if (isset($access[$operation])) {
- return $access[$operation];
- }
- else {
- throw new Exception(t('No such operation "@operation"', array(
- '@operation' => $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' => ' ',
- 'number_complete' => 0,
- 'number_of_items' => 0,
- 'percent_complete' => 0,
- ),
- ),
- );
- }
|