$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, ), ), ); }