diff --git a/modules/block.skinr.inc b/modules/block.skinr.inc index dae94d0..91600c6 100644 --- a/modules/block.skinr.inc +++ b/modules/block.skinr.inc @@ -1,51 +1,24 @@ 'block_skinr_preprocess_hook_callback', - 'title' => t('block settings'), - 'collapsed' => FALSE, - ); - $data['block']['preprocess']['block'] = array( - 'index_handler' => 'block_skinr_preprocess_index_handler', - ); - $data['block']['contextual_links']['block'] = array( - 'contextual_links_handler' => 'block_skinr_contextual_links', - ); - - return $data; + return array('block'); } /** - * Skinr preprocess hook callback. - * - * @param &$form - * Passes in the $form parameter from hook_form_alter(). - * @param $form_state - * Passes in the $form_state parameter from hook_form_alter(). - * - * @return - * An array of preprocess hooks we wish to use. + * Implements hook_skinr_theme_hooks(). */ -function block_skinr_preprocess_hook_callback(&$form, $form_state) { - $preprocess_hooks = array(); - - if (empty($form['module']['#value']) && !empty($form['skinr']['element']['#value'])) { - list($module, $delta) = explode('__', $form['skinr']['element']['#value'], 2); +function block_skinr_theme_hooks($module, $element) { + $theme_hooks = array(); + if ($module == 'block') { + list($module, $delta) = explode('__', $element, 2); $result = db_select('block', 'b') ->fields('b') ->distinct() @@ -54,55 +27,21 @@ function block_skinr_preprocess_hook_callback(&$form, $form_state) { ->range(0, 1) ->execute(); foreach ($result as $block) { - $preprocess_hooks[] = 'block__'. $block->module; + $theme_hooks[] = 'block__'. $block->module; } + $theme_hooks[] = 'block'; } - else { - $preprocess_hooks[] = 'block__'. $form['module']['#value']; - } - $preprocess_hooks[] = 'block'; - - return $preprocess_hooks; -} -/** - * Skinr preprocess index handler. - * - * @param &$variables - * Passes in the $variables parameter from module_preprocess(). - * - * @return - * The index where we can find our values in Skinr's data structure. If an - * array is returned, it will loop through each index in Skinr's data - * structure and merge the returned classes. - */ -function block_skinr_preprocess_index_handler(&$variables) { - return array($variables['block']->module . '__' . $variables['block']->delta); + return $theme_hooks; } /** - * Skinr contextual links handler. - * - * @param &$variables - * Passes in the $variables parameter from skinr_preprocess(). - * - * @return - * An array. Each value is an array that forms the function arguments for - * menu_contextual_links(). For example: - * @code - * array( - * 'admin/appearance/skinr/edit', array('system', 'navigation')), - * ) - * @endcode + * Implements hook_skinr_elements(). */ -function block_skinr_contextual_links(&$variables) { - $links = array(); - $links['skinr-block'] = array( - 'admin/appearance/skinr/edit/nojs', array('block', $variables['block']->module . '__' . $variables['block']->delta), - ); - return $links; +function block_skinr_elements($variables, $hook) { + $elements = array(); + if ($hook == 'block') { + $elements['block'] = array($variables['block']->module . '__' . $variables['block']->delta); + } + return $elements; } - -/** - * @} - */ diff --git a/modules/comment.skinr.inc b/modules/comment.skinr.inc index 2ed6a3f..3be6475 100644 --- a/modules/comment.skinr.inc +++ b/modules/comment.skinr.inc @@ -1,137 +1,39 @@ 'comment_skinr_preprocess_hook_callback', - 'title' => t('comment settings'), - 'skinr_weight' => 2, - 'collapsed' => FALSE, - ); - $data['comment']['preprocess']['comment_wrapper'] = array( - 'index_handler' => 'comment_skinr_preprocess_index_handler', - ); - $data['comment']['contextual_links']['comment_wrapper'] = array( - 'contextual_links_handler' => 'comment_skinr_contextual_links', - ); - - return $data; -} - -/** - * Skinr form index handler. - * - * @param $op - * What kind of action is being performed. Possible values: - * - 'form': the form elements for Skinr are being inserted in a form. - * - 'submit': the form has been submitted. - * @param &$form - * - For 'form', passes in the $form parameter from hook_form_alter(). - * - For 'submit', passes in the $form parameter from hook_form_submit(). - * @param $form_state - * - For 'form', passes in the $form_state parameter from hook_form_alter(). - * - For 'submit', passes in the $form_state parameter from hook_form_submit(). - * - * @return - * The index where we can find our values in Skinr's data structure. - */ -function comment_skinr_form_index_handler($op, &$form, &$form_state) { - switch ($op) { - case 'form': - return $form['#node_type']->type; - - case 'submit': - // Clear old variable before we set a new one if the node type has changed - if ($form_state['values']['old_type'] != $form_state['values']['type']) { - foreach ($form_state['values']['skinr_settings']['comment_group'] as $theme_name => $theme_data) { - $skinr = new stdClass(); - $skinr->theme = $theme_name; - $skinr->module = 'comment'; - $skinr->element = $form_state['values']['old_type']; - $skinr->skins = array(); - - skinr_skin_save($skinr); - } - } - return $form_state['values']['type']; - } + return array('comment'); } /** - * Skinr preprocess hook callback. - * - * @param &$form - * Passes in the $form parameter from hook_form_alter(). - * @param $form_state - * Passes in the $form_state parameter from hook_form_alter(). - * - * @return - * An array of preprocess hooks we wish to use. + * Implements hook_skinr_theme_hooks(). */ -function comment_skinr_preprocess_hook_callback(&$form, $form_state) { - $preprocess_hooks = array(); +function comment_skinr_theme_hooks($module, $element) { + $theme_hooks = array(); - if (!isset($form['#node_type']->type) && !empty($form['skinr']['element']['#value'])) { - $preprocess_hooks[] = 'comment_wrapper__' . $form['skinr']['element']['#value']; - } - else { - $preprocess_hooks[] = 'comment_wrapper__' . $form['#node_type']->type; + if ($module == 'comment') { + $theme_hooks = array( + 'comment_wrapper__' . $element, + 'comment_wrapper', + ); } - $preprocess_hooks[] = 'comment_wrapper'; - return $preprocess_hooks; -} - -/** - * Skinr preprocess index handler. - * - * @param &$variables - * Passes in the $variables parameter from skinr_preprocess(). - * - * @return - * The index where we can find our values in Skinr's data structure. If an - * array is returned, it will loop through each index in Skinr's data - * structure and merge the returned classes. - */ -function comment_skinr_preprocess_index_handler(&$variables) { - return array($variables['node']->type); + return $theme_hooks; } /** - * Skinr contextual links handler. - * - * @param &$variables - * Passes in the $variables parameter from skinr_preprocess(). - * - * @return - * An array. Each value is an array that forms the function arguments for - * menu_contextual_links(). For example: - * @code - * array( - * 'admin/appearance/skinr/edit', array('system', 'navigation')), - * ) - * @endcode + * Implements hook_skinr_elements(). */ -function comment_skinr_contextual_links(&$variables) { - $links = array(); - $links['skinr-comment'] = array( - 'admin/appearance/skinr/edit/nojs', array('comment', $variables['node']->type), - ); - return $links; +function comment_skinr_elements($variables, $hook) { + $elements = array(); + if ($hook == 'comment_wrapper') { + $elements['comment'] = array($variables['node']->type); + } + return $elements; } - -/** - * @} - */ diff --git a/modules/node.skinr.inc b/modules/node.skinr.inc index b0d5c32..f2a646d 100644 --- a/modules/node.skinr.inc +++ b/modules/node.skinr.inc @@ -1,135 +1,39 @@ 'node_skinr_preprocess_hook_callback', - 'title' => t('node settings'), - 'collapsed' => FALSE, - ); - $data['node']['preprocess']['node'] = array( - 'index_handler' => 'node_skinr_preprocess_index_handler', - ); - $data['node']['contextual_links']['node'] = array( - 'contextual_links_handler' => 'node_skinr_contextual_links', - ); - - return $data; -} - -/** - * Skinr form index handler. - * - * @param $op - * What kind of action is being performed. Possible values: - * - 'form': the form elements for Skinr are being inserted in a form. - * - 'submit': the form has been submitted. - * @param &$form - * - For 'form', passes in the $form parameter from hook_form_alter(). - * - For 'submit', passes in the $form parameter from hook_form_submit(). - * @param $form_state - * - For 'form', passes in the $form_state parameter from hook_form_alter(). - * - For 'submit', passes in the $form_state parameter from hook_form_submit(). - * - * @return - * The index where we can find our values in Skinr's data structure. - */ -function node_skinr_form_index_handler($op, &$form, $form_state) { - switch ($op) { - case 'form': - return $form['#node_type']->type; - - case 'submit': - // Clear old variable before we set a new one if the node type has changed. - if ($form_state['values']['old_type'] != $form_state['values']['type']) { - foreach ($form_state['values']['skinr_settings']['node_group'] as $theme_name => $theme_data) { - $skinr = new stdClass(); - $skinr->theme = $theme_name; - $skinr->module = 'node'; - $skinr->element = $form_state['values']['old_type']; - $skinr->skins = array(); - - skinr_skin_save($skinr); - } - } - return $form_state['values']['type']; - } + return array('node'); } /** - * Skinr preprocess hook callback. - * - * @param &$form - * Passes in the $form parameter from hook_form_alter(). - * @param $form_state - * Passes in the $form_state parameter from hook_form_alter(). - * - * @return - * An array of preprocess hooks we wish to use. + * Implements hook_skinr_theme_hooks(). */ -function node_skinr_preprocess_hook_callback(&$form, $form_state) { - $preprocess_hooks = array(); +function node_skinr_theme_hooks($module, $element) { + $theme_hooks = array(); - if (!isset($form['#node_type']->type) && !empty($form['skinr']['element']['#value'])) { - $preprocess_hooks[] = 'node__' . $form['skinr']['element']['#value']; - } - else { - $preprocess_hooks[] = 'node__' . $form['#node_type']->type; + if ($module == 'node') { + $theme_hooks = array( + 'node__' . $element, + 'node', + ); } - $preprocess_hooks[] = 'node'; - return $preprocess_hooks; -} - -/** - * Skinr preprocess index handler. - * - * @param &$variables - * Passes in the $variables parameter from module_preprocess(). - * - * @return - * The index where we can find our values in Skinr's data structure. If an - * array is returned, it will loop through each index in Skinr's data - * structure and merge the returned classes. - */ -function node_skinr_preprocess_index_handler(&$variables) { - return array($variables['node']->type); + return $theme_hooks; } /** - * Skinr contextual links handler. - * - * @param &$variables - * Passes in the $variables parameter from skinr_preprocess(). - * @return - * An array. Each value is an array that forms the function arguments for - * menu_contextual_links(). For example: - * @code - * array( - * 'admin/appearance/skinr/edit', array('system', 'navigation')), - * ) - * @endcode + * Implements hook_skinr_elements(). */ -function node_skinr_contextual_links(&$variables) { - $links = array(); - $links['skinr-node'] = array( - 'admin/appearance/skinr/edit/nojs', array('node', $variables['node']->type), - ); - return $links; +function node_skinr_elements($variables, $hook) { + $elements = array(); + if ($hook == 'node') { + $elements['node'] = array($variables['node']->type); + } + return $elements; } - -/** - * @} - */ diff --git a/modules/views.skinr.inc b/modules/views.skinr.inc index ea34136..cf2bd5c 100644 --- a/modules/views.skinr.inc +++ b/modules/views.skinr.inc @@ -2,92 +2,58 @@ /** * @file - * Provide skinr handling for views.module - */ - -/** - * @defgroup skinr_views_module views.module handlers - * - * @{ + * Implements Skinr hooks for views.module. */ /** * Implements hook_skinr_config_info(). */ function views_skinr_config_info() { - $data['views']['form']['skinr_ui_form'] = array( - 'preprocess_hook_callback' => 'views_skinr_preprocess_hook_callback', - 'title' => t('views style settings'), - 'collapsed' => FALSE, - ); - $data['views']['preprocess']['views_view'] = array( - 'index_handler' => 'views_skinr_preprocess_index_handler', - ); - $data['views']['contextual_links']['page'] = array( - 'contextual_links_handler' => 'views_skinr_contextual_links', - ); - - return $data; + return array('views'); } /** - * Skinr form preprocess hook callback. - * - * @param &$form - * Passes in the $form parameter from hook_form_alter(). - * @param $form_state - * Passes in the $form_state parameter from hook_form_alter(). - * - * @return - * An array of preprocess hooks we wish to use. + * Implements hook_skinr_theme_hooks(). */ -function views_skinr_preprocess_hook_callback(&$form, $form_state) { - $preprocess_hooks = array('views_view'); +function views_skinr_theme_hooks($module, $element) { + $theme_hooks = array(); - if (!empty($form_state['view']) && !empty($form_state['view']->name)) { - $view = $form_state['view']; - } - elseif(isset($form['skinr']['element']['#value'])) { - list($element_info['view'], $element_info['display']) = explode('__', $form['skinr']['element']['#value'], 2); - if ($view = views_get_view($element_info['view'])) { - $view->execute_display($element_info['display']); - } - } + if ($module == 'views') { + list($name, $display_id) = explode('__', $element, 2); + if ($view = views_get_view($name)) { + $view->execute_display($display_id); - if (!empty($view)) { - $display = $view->display[$view->current_display]; + $display = $view->display[$view->current_display]; - // Create list of suggested templates. - $preprocess_hooks = views_theme_functions('views_view', $view, $display); - // Fetch additional style based suggested templates. - $additional_hooks = views_theme_functions($display->display_plugin, $view, $display); + // Create list of suggested templates. + $theme_hooks = views_theme_functions('views_view', $view, $display); - $preprocess_hooks = array_merge($additional_hooks, $preprocess_hooks); + // @todo Determine whether below code is still relevant. + /* + // Fetch additional style based suggested templates. + $additional_hooks = views_theme_functions($display->display_plugin, $view, $display); + $theme_hooks = array_merge($additional_hooks, $theme_hooks); + */ + } + else { + $theme_hooks[] = 'views_view'; + } } - return $preprocess_hooks; + return $theme_hooks; } /** - * Skinr preprocess index handler. + * Implements hook_skinr_elements(). */ -function views_skinr_preprocess_index_handler(&$variables) { - return array($variables['view']->name .'__'. $variables['view']->current_display); -} - -/** - * Skinr contextual links handler. - */ -function views_skinr_contextual_links(&$variables) { - $links = array(); - if (!empty($variables['page']['#views_contextual_links_info'])) { - $links['skinr-views'] = array( - 'admin/appearance/skinr/edit/nojs', array('views', $variables['page']['#views_contextual_links_info']['views_ui']['view_name'] . '__' . $variables['page']['#views_contextual_links_info']['views_ui']['view_display_id']), - ); +function views_skinr_elements($variables, $hook, $op) { + $elements = array(); + if ($op == 'preprocess' && $hook == 'views_view') { + $elements['views'] = array($variables['view']->name . '__' . $variables['view']->current_display); } - return $links; + elseif ($op == 'contextual_links' && $hook == 'page' && isset($variables['page']['#views_contextual_links_info'])) { + // Contextual links for views are on 'page' hook, not 'views_view'. + $elements['views'] = array($variables['page']['#views_contextual_links_info']['views_ui']['view_name'] . '__' . $variables['page']['#views_contextual_links_info']['views_ui']['view_display_id']); + } + return $elements; } - -/** - * @} - */ diff --git a/skinr.api.php b/skinr.api.php index 47ccbf2..9a98a98 100644 --- a/skinr.api.php +++ b/skinr.api.php @@ -26,69 +26,83 @@ * This must either be in the same directory as the .module file or in a subdirectory * named 'includes'. * - * The configuration info is keyed by the MODULENAME. In the case of $data['block'] - * 'block' is the name of the module. - * - * There are two section to the configuration array: - * - When you specify a "form", Skinr will insert its skins selector into the form - * with the specified form_id. Example: $data[MODULENAME]['form'][FORM_ID] = ... - * You can specify multiple forms that Skinr should add its skins selector to. A - * good example where this would be needed is blocks where you have a different - * form_id for adding a new block than when editing an existing block. - * - When you specify "preprocess", Skinr will create a $vars['skinr'] variable - * containing the appropriate skin classes for the specified preprocess hook. - * Example: $data[MODULENAME]['preprocess'][PREPROCESS_HOOK] = ... + * @return + * An array of element types this module supports. + */ +function hook_skinr_config() { + return array('block'); +} + +/** + * Provide a list of all available theme hooks for a given element. * - * Form options: - * - "index_handler" is required. It specifies a function that returns an index where - * Skinr can find the values in its data structure. - * - "access_handler" specifies a function that returns TRUE if you wish to grant access - * to skinr, or FALSE if not. - * - "data_handler" specifies a function that returns the data used to populate the form. - * This is useful in cases where a module caches data (like panels and views) and has - * an option to cancel changes. - * - "submit_handler" specifies a function that process the form data and saves it. - * - "preprocess_hook" is required. Each skin states which preprocess hooks it will - * work for. This parameter will limit the available skins by the specified - * preprocess hook. - * - "title" overrides the default title on the Skinr fieldset. - * - "description" overrides the default description that provides additional - * information to the user about this Skinr selector. - * - "weight" overrides the order where Skinrs selector appears on the form. - * - "collapsed" sets whether the fieldset appears collapsed or not. Defaults to TRUE. - * - "selector_weight" overrides the weight of the selector field inside the fieldset. - * This is useful, for instance, if you have multiple modules add selectors to the - * same form. - * - "selector_title" overrides the title of the selector field inside the fieldset. + * @param $module + * The module implementing given element. + * @param $element + * An element. * - * Preprocess options: - * - "indexhandler" is required. It specifies a function that returns an index where - * Skinr can find the values in its data structure. + * @return + * An array of theme hooks. */ -function hook_skinr_config() { - $data['example']['form']['block_admin_configure'] = array( - 'index_handler' => 'example_skinr_index_handler', - 'preprocess_hook' => 'block', - 'title' => t('Skinr settings'), - 'description' => t('Here you can manage which Skinr styles, if any, you want to apply.'), - 'weight' => 1, - 'collapsed' => TRUE, - 'selector_weight' => 0, - 'selector_title' => t('Choose Skinr Style(s)'), - ); - $data['example']['form']['block_add_block_form'] = array( - 'index_handler' => 'example_skinr_index_handler', - 'title' => t('Skinr settings'), - 'description' => t('Here you can manage which Skinr styles, if any, you want to apply to this block.'), - 'weight' => -10, - 'collapsed' => FALSE, - ); +function hook_skinr_theme_hooks($module, $element) { + $theme_hooks = array(); - $data['example']['preprocess']['block'] = array( - 'index_handler' => 'block_skinr_preprocess_handler_block', - ); + if ($module == 'node') { + $theme_hooks = array( + 'node_' . $element, + 'node', + ); + } + + return $theme_hooks; +} - return $data; +/** + * Perform alterations to theme hooks before widgets are rendered. + * + * @param $theme_hooks + * An array of theme hooks. + * @param $module + * The module implementing given element. + * @param $element + * An element. + */ +function hook_skinr_theme_hooks_alter(&$theme_hooks, $module, $element) { + if ($module == 'node') { + array_unshift($theme_hooks, 'node_' . $element . '_custom'); + } +} + +/** + * Return an array of element ids. + * + * @todo Needs a better description. + * + * @param $variables + * The variables array from skinr_preprocess(). + * @param $hook + * The name of the theme hook. + * @param $op + * The operation being performed: + * - 'preprocess' + * - 'contextual_links' + * + * @return + * An array of element arrays, keyed by element type. Example: + * @code + * array( + * 'block' => array('system__navigation'), + * ); + * @endcode + * + * @see skinr_preprocess() + */ +function hook_skinr_elements(&$variables, $hook, $op) { + $elements = array(); + if ($hook == 'block') { + $elements['block'] = array($variables['block']->module . '__' . $variables['block']->delta); + } + return $elements; } /** diff --git a/skinr.handlers.inc b/skinr.handlers.inc deleted file mode 100644 index a67699b..0000000 --- a/skinr.handlers.inc +++ /dev/null @@ -1,211 +0,0 @@ - $theme, - 'module' => $module, - 'element' => $element, - ); - return skinr_skin_load_multiple(skinr_skin_get_sids($params)); -} - -/** - * Skinr submit handler. - * - * @param &$form - * Passes in the $form parameter from hook_form_submit(). - * @param $form_state - * Passes in the $form_state parameter from hook_form_submit(). - * @param $module - * The module that is currently being processed. - * @param $form_settings - * The settings from hook_skinr_config() for the form that's currently being - * processed. - */ -function skinr_submit_handler(&$form, $form_state, $module, $form_settings) { - if (!$element = skinr_handler('form_index_handler', 'submit', $form_settings['index_handler'], $form, $form_state)) { - // We require a valid element to continue. - // @todo This should really be in a validation handler. - drupal_set_message(t("Skinr settings weren't saved due to an error."), 'error'); - return; - } - - if (isset($form_state['values']['skinr_settings'][$module . '_group'])) { - foreach ($form_state['values']['skinr_settings'][$module . '_group'] as $theme_name => $theme) { - // Process widgets. - if (!empty($theme) && is_array($theme)) { - foreach ($theme as $skin_name => $options) { - if ($skin_name == '_additional' && !user_access('edit advanced skin settings')) { - // This user doesn't have access to alter these options. - continue; - } - - // Ensure options is an array. - if (!is_array($options)) { - $options = $skin_name == '_additional' ? explode(' ', $options) : array($options); - } - // Sanitize options. - $options = _skinr_array_strip_empty($options); - - // Find existing skin. - $params = array( - 'theme' => $theme_name, - 'module' => $module, - 'element' => $element, - 'skin' => $skin_name, - ); - $sids = skinr_skin_get_sids($params); - - unset($skin); - if (!empty($sids)) { - $sid = reset($sids); - $skin = skinr_skin_load($sid); - } - - if (empty($options)) { - if (!empty($skin)) { - // Delete this skin configuration. - skinr_skin_delete($skin->sid); - } - continue; - } - - if (empty($skin)) { - // It doesn't exist, so create a new skin. - $skin = new stdClass(); - $skin->theme = $theme_name; - $skin->module = $module; - $skin->element = $element; - $skin->skin = $skin_name; - } - $skin->options = $options; - $skin->status = 1; - - // Save skin. - if (!skinr_skin_save($skin)) { - drupal_set_message(t("Skinr settings for %skin weren't saved due to an error.", array('%skin' => $skin_name)), 'error'); - } - } - } - } - } -} - -/** - * Implements hook_skinr_api_VERSION(). - */ -function skinr_skinr_api_2() { -} - -/** - * Helper function for built-in integration code. - */ -function skinr_skinr_api_modules() { - return array( - 'path' => drupal_get_path('module', 'skinr') . '/modules', - ); -} - -function block_skinr_api_2() { - return skinr_skinr_api_modules(); -} - -function comment_skinr_api_2() { - return skinr_skinr_api_modules(); -} - -function node_skinr_api_2() { - return skinr_skinr_api_modules(); -} - -function views_skinr_api_2() { - return skinr_skinr_api_modules(); -} diff --git a/skinr.module b/skinr.module index 3821d57..08e696d 100644 --- a/skinr.module +++ b/skinr.module @@ -47,6 +47,9 @@ function skinr_help($path, $arg) { function skinr_hook_info() { $hooks = array( 'skinr_api_2', + 'skinr_elements', + 'skinr_theme_hooks', + 'skinr_theme_hooks_alter', ); $hooks = array_fill_keys($hooks, array( 'group' => 'skinr', @@ -74,82 +77,80 @@ function skinr_preprocess(&$variables, $hook) { return; } - $config = skinr_get_config_info(); $current_theme = skinr_current_theme(); - $theme_registry = theme_get_registry(); $skin_info = skinr_get_skin_info(); + $theme_registry = theme_get_registry(); $original_hook = (isset($theme_registry[$hook]['original hook']) ? $theme_registry[$hook]['original hook'] : $hook); - foreach ($config as $module => $module_settings) { - if (!empty($module_settings['preprocess'][$original_hook])) { - $preprocess_settings = $module_settings['preprocess'][$original_hook]; - $elements = skinr_handler('preprocess_index_handler', 'preprocess', $preprocess_settings['index_handler'], $variables); - if (empty($elements)) { - // We can receive empty arrays; if that happens, there's no point in continuing. - continue; - } + // An array of $elements based on $module and $original_hook, derived from $variables. + $array_elements = skinr_invoke_all('skinr_elements', $variables, $original_hook, 'preprocess'); + foreach ($array_elements as $module => $elements) { + if (empty($elements)) { + // We can receive empty arrays; if that happens, there's no point + // in continuing. + continue; + } - // Get a list of skin configuration IDs to pass to - // skinr_skin_load_multiple(). - $params = array( - 'theme' => $current_theme, - 'module' => $module, - 'element' => $elements, - 'status' => 1, - ); - $sids = skinr_skin_get_sids($params); - if (empty($sids)) { - // Noting to apply. - continue; - } + // Get a list of skin configuration IDs to pass to + // skinr_skin_load_multiple(). + $params = array( + 'theme' => $current_theme, + 'module' => $module, + 'element' => $elements, + 'status' => 1, + ); + $sids = skinr_skin_get_sids($params); + if (empty($sids)) { + // Noting to apply. + continue; + } - $applied_skins = array(); - foreach (skinr_skin_load_multiple($sids) as $skin) { - $applied_skins = array($skin->skin => $skin->options) + $applied_skins; - } + $applied_skins = array(); + foreach (skinr_skin_load_multiple($sids) as $skin) { + $applied_skins = array($skin->skin => $skin->options) + $applied_skins; + } - // Invoke hook_skinr_preprocess_alter() in all modules. - // @todo Review whether this alter hook is useful or not, and if it's in - // the right place or not. - $context = array( - 'hook' => $hook, - 'variables' => &$variables, - 'theme' => $current_theme, - 'module' => $module, - 'elements' => $elements, - 'options' => $applied_skins, - ); - drupal_alter('skinr_preprocess', $context); + // Invoke hook_skinr_preprocess_alter() in all modules. + // @todo Review whether this alter hook is useful or not, and if it's in + // the right place or not. + $context = array( + 'hook' => $hook, + 'variables' => &$variables, + 'theme' => $current_theme, + 'module' => $module, + 'elements' => $elements, + 'options' => $applied_skins, + ); + drupal_alter('skinr_preprocess', $context); - // Use drupal_process_attached() to add attachements such as JS and CSS. - if (!empty($applied_skins)) { - foreach ($applied_skins as $skin_name => $skin_options) { + // Use drupal_process_attached() to add attachements such as JS and CSS. + if (!empty($applied_skins)) { + foreach ($applied_skins as $skin_name => $skin_options) { - // Special case for _additional. - if ($skin_name == '_additional') { - continue; - } + // Special case for _additional. + if ($skin_name == '_additional') { + continue; + } - // Make sure this skin is enabled for the current theme. - if (isset($skin_info[$skin_name]['attached'])) { - $elements['#attached'] = $skin_info[$skin_name]['attached']; - drupal_process_attached($elements); - } + // Make sure this skin is enabled for the current theme. + if (isset($skin_info[$skin_name]['attached'])) { + $elements['#attached'] = $skin_info[$skin_name]['attached']; + drupal_process_attached($elements); + } - if (!is_array($skin_options)) { - $skin_options = array($skin_options); - } - foreach ($skin_options as $skin_option) { - if (isset($skin_info[$skin_name]['options'][$skin_option]['attached'])) { - $elements['#attached'] = $skin_info[$skin_name]['options'][$skin_option]['attached']; - drupal_process_attached($elements); - } + if (!is_array($skin_options)) { + $skin_options = array($skin_options); + } + foreach ($skin_options as $skin_option) { + if (isset($skin_info[$skin_name]['options'][$skin_option]['attached'])) { + $elements['#attached'] = $skin_info[$skin_name]['options'][$skin_option]['attached']; + drupal_process_attached($elements); } } - - $variables['classes_array'] = array_merge($variables['classes_array'], skinr_flatten_skins_array($applied_skins)); } + + $variables['classes_array'] = array_merge($variables['classes_array'], skinr_flatten_skins_array($applied_skins)); } } } @@ -414,19 +415,17 @@ function skinr_rule_is_visible($rid, $path = NULL, $account = NULL) { * - path: The path to the extension. * - directory: (optional) The sub-directory holding Skinr plugin files. * - ...: Any other properties defined by the module or theme. - * - * @todo Cache this. */ -function skinr_implements() { +function skinr_implements_api() { $cache = &drupal_static(__FUNCTION__); if (!isset($cache)) { + if ($cached = cache_get('skinr_implements_api')) { + $cache = $cached->data; + return $cache; + } $cache = array(); - // Load built-in support code for Drupal core modules. - // @todo Remove this when we eliminate skinr handlers. - module_load_include('inc', 'skinr', 'skinr.handlers'); - // Collect hook_skinr_api_VERSION() module implementations. This will also // auto-load $module.skinr.inc files, which may contain skin/group hook // implementations (when not using the plugin system). @@ -451,11 +450,6 @@ function skinr_implements() { $file = $cache[$module]['path'] . '/' . $module . '.skinr.inc'; if (file_exists(DRUPAL_ROOT . '/' . $file)) { $cache[$module]['include file'] = $file; - // When rebuilding the cache, we auto-load the include file for - // convenience. Calling code should invoke skinr_load_includes() - // on the extensions they want to act with. - // @todo Remove this. - include_once DRUPAL_ROOT . '/' . $file; } } // Populate defaults. @@ -528,38 +522,213 @@ function skinr_implements() { $file = $cache[$name]['path'] . '/' . $name . '.skinr.inc'; if (file_exists(DRUPAL_ROOT . '/' . $file)) { $cache[$name]['include file'] = $file; - // When rebuilding the cache, we auto-load the include file for - // convenience. Calling code should invoke skinr_load_includes() - // on the extensions they want to act with. - // @todo Remove this. - include_once DRUPAL_ROOT . '/' . $file; } } } + + cache_set('skinr_implements_api', $cache); } return $cache; } /** - * Loads $extension.skinr.inc include files of passed in extensions. + * Determine whether a module implements a hook. + * + * Replacement for module_hook() that only invokes modules that implement + * the current version of Skinr API. It also supports $module.skinr.inc files + * in themes and custom paths. * - * @todo These hook implementations should not be required to be loaded at all, - * rewrite the code that is currently not using the cache. + * @param $module + * The name of the module (without the .module extension). + * @param $hook + * The name of the hook (e.g. "skinr_skin_info" or "skinr_theme_hooks"). + * + * @return + * TRUE if the module is both installed and enabled, and the hook is + * implemented in that module. */ -function skinr_load_includes(array $extensions) { - foreach ($extensions as $extension) { +function skinr_hook($module, $hook) { + $function = $module . '_' . $hook; + if (function_exists($function)) { + return TRUE; + } + // If the hook implementation does not exist, check whether it may live in an + // include file in a custom path. + $extensions = skinr_implements_api(); + if (isset($extensions[$module])) { + $extension = $extensions[$module]; if (isset($extension['include file'])) { - include_once DRUPAL_ROOT . '/' . $extension['include file']; + // The module specified a custom path. module_hook() only auto-loads + // $module.skinr.inc in a module's root folder. + skinr_load_include($extension['include file']); + if (function_exists($module . '_' . $hook)) { + return TRUE; + } + } + else { + // Run through module_hook() to auto-load $module.skinr.inc from a + // non-custom path. + if (module_hook($module, $hook)) { + return TRUE; + } } } + return FALSE; +} + +/** + * Determine which modules are implementing a hook. + * + * Replacement for module_implements() that only invokes modules that implement + * the current version of Skinr API. It also supports $module.skinr.inc files + * in themes and custom paths. + * + * @param $hook + * The name of the hook (e.g. "skinr_skin_info" or "skinr_theme_hooks"). + * + * @return + * An array with the names of the modules which are implementing this hook. + * + * @see skinr_exit() + */ +function skinr_implements($hook) { + $implementations = &drupal_static(__FUNCTION__, array()); + + // Fetch implementations from cache. + if (empty($implementations)) { + $implementations = cache_get('skinr_implements', 'cache_bootstrap'); + if ($implementations === FALSE) { + $implementations = array(); + } + else { + $implementations = $implementations->data; + } + } + + if (!isset($implementations[$hook])) { + $implementations['#write_cache'] = TRUE; + + $extensions = skinr_implements_api(); + $implementations[$hook] = array(); + foreach ($extensions as $module => $extension) { + if (isset($extension['include file'])) { + // The module specified a custom path. module_implements() and + // module_hook() only auto-load $module.skinr.inc in a module's + // root folder. + $include_file = skinr_load_include($extension['include file']); + if (function_exists($module . '_' . $hook)) { + $implementations[$hook][$module] = $include_file ? $extension['include file'] : FALSE; + } + } + else { + // Run through module_hook() to auto-load $module.skinr.inc from a + // non-custom path. + if (module_hook($module, $hook)) { + $implementations[$hook][$module] = FALSE; + } + } + } + // Allow modules to change the weight of specific implementations but avoid + // an infinite loop. + if ($hook != 'skinr_implements_alter') { + drupal_alter('skinr_implements', $implementations[$hook], $hook); + } + } + else { + foreach ($implementations[$hook] as $module => $file) { + if ($file) { + skinr_load_include($file); + } + else { + module_hook($module, $hook); + } + // It is possible that a module removed a hook implementation without the + // implementations cache being rebuilt yet, so we check whether the + // function exists on each request to avoid undefined function errors. + // Since module_hook() may needlessly try to load the include file again, + // function_exists() is used directly here. + if (!function_exists($module . '_' . $hook)) { + // Clear out the stale implementation from the cache and force a cache + // refresh to forget about no longer existing hook implementations. + unset($implementations[$hook][$module]); + $implementations['#write_cache'] = TRUE; + } + } + } + + return array_keys($implementations[$hook]); +} + +/** + * Implements hook_exit(). + * + * @see module_implements_write_cache() + */ +function skinr_exit($destination = NULL) { + $implementations = &drupal_static('skinr_implements'); + // Check whether we need to write the cache. We do not want to cache hooks + // which are only invoked on HTTP POST requests since these do not need to be + // optimized as tightly, and not doing so keeps the cache entry smaller. + if (isset($implementations['#write_cache']) && ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD')) { + unset($implementations['#write_cache']); + cache_set('skinr_implements', $implementations, 'cache_bootstrap'); + } +} + +/** + * Invoke a hook in all enabled modules and themes that implement it. + * + * Replacement for module_invoke_all() that only invokes modules that implement + * the current version of Skinr API. It also supports $module.skinr.inc files + * in themes and custom paths. + * + * @param $hook + * The name of the hook to invoke. + * @param ... + * Arguments to pass to the hook. + * + * @return + * An array of return values of the hook implementations. If modules return + * arrays from their implementations, those are merged into one array. + */ +function skinr_invoke_all($hook) { + $args = func_get_args(); + // Remove $hook from the arguments. + unset($args[0]); + $return = array(); + foreach (skinr_implements($hook) as $module) { + $function = $module . '_' . $hook; + if (function_exists($function)) { + $result = call_user_func_array($function, $args); + if (isset($result) && is_array($result)) { + $return = array_merge_recursive($return, $result); + } + elseif (isset($result)) { + $return[] = $result; + } + } + } + + return $return; +} + +/** + * Loads a $module.skinr.inc include file. + */ +function skinr_load_include($file) { + if (is_file($file)) { + include_once $file; + return $file; + } + return FALSE; } /** * Includes Skinr plugin files for an extension, if any. * * @param $extension - * The API information for an extension, as returned by skinr_implements(). + * The API information for an extension, as returned by skinr_implements_api(). */ function skinr_load_plugins($extension) { static $loaded = array(); @@ -663,7 +832,7 @@ function skinr_skin_save(&$skin) { // Clear internal properties. unset($skin->original); // Clear the static loading cache. - // @todo If we have a more granular reset for skinr_skin_load_multiple(), we + // @todo Once we have a more granular reset for skinr_skin_load_multiple(), we // need to use it here. drupal_static_reset('skinr_skin_load_multiple'); @@ -1092,10 +1261,13 @@ function skinr_get_skin_info() { } $skin_info = array(); - foreach (skinr_implements() as $name => $extension) { - $hooks = array( - "{$name}_skinr_skin_info" => $extension, - ); + foreach (skinr_implements_api() as $name => $extension) { + $hooks = array(); + // Run through skinr_hook to ensure the required include gets loaded. + if (skinr_hook($name, 'skinr_skin_info')) { + $hooks["{$name}_skinr_skin_info"] = $extension; + } + // Load the extension's plugins, if any. if ($files = skinr_load_plugins($extension)) { // The base path for plugins is the directory defined by the extension. @@ -1145,10 +1317,13 @@ function skinr_get_group_info() { } $group_info = array(); - foreach (skinr_implements() as $name => $extension) { - $hooks = array( - "{$name}_skinr_group_info" => $extension, - ); + foreach (skinr_implements_api() as $name => $extension) { + $hooks = array(); + // Run through skinr_hook to ensure the required include gets loaded. + if (skinr_hook($name, 'skinr_group_info')) { + $hooks["{$name}_skinr_group_info"] = $extension; + } + // Load the extension's plugins, if any. if ($files = skinr_load_plugins($extension)) { // The base path for plugins is the directory defined by the extension. @@ -1199,31 +1374,9 @@ function skinr_get_config_info() { if (!isset($config_info)) { if ($cached = cache_get('skinr_config_info')) { $config_info = $cached->data; - - // Load the module integration files. - // @todo Whatever currently needs to be invoked has to be cached instead. - skinr_load_includes($config_info); - return $config_info; } - $config_info = array(); - - foreach (skinr_implements() as $name => $extension) { - $function = "{$name}_skinr_config_info"; - if (function_exists($function)) { - $extension_info = $function(); - if (isset($extension_info) && is_array($extension_info)) { - // @todo Yuck! Rewrite hook_skinr_config_info() API structure. Why do - // implementations return info keyed by their own module name? - if (isset($extension['include file'])) { - foreach ($extension_info as &$info) { - $info['include file'] = $extension['include file']; - } - } - $config_info = array_merge_recursive($config_info, $extension_info); - } - } - } + $config_info = skinr_invoke_all('skinr_config_info'); // Allow modules to alter config info via hook_skinr_config_info_alter(). drupal_alter('skinr_config_info', $config_info); @@ -1235,113 +1388,26 @@ function skinr_get_config_info() { } /** - * Prepare default configuration data for modules. + * Provide a list of all available theme hooks for a given element. * - * @todo Search and destroy. + * @param $module + * The module implementing given element. + * @param $element + * An element. + * + * @return + * An array of theme hooks. */ -function skinr_config_info_default() { - return array( - 'access_handler' => 'skinr_access_handler', - 'index_handler' => 'skinr_index_handler', - 'data_handler' => 'skinr_data_handler', - 'submit_handler' => 'skinr_submit_handler', - 'submit_handler_attach_to' => array('#submit'), - 'skinr_title' => t('Skinr'), - 'skinr_weight' => 1, - 'title' => '', - 'description' => t('Manage which skins you want to apply to the hooks'), - 'collapsed' => TRUE, - 'weight' => 0, - ); -} +function skinr_theme_hooks($module, $element) { + $theme_hooks = &drupal_static(__FUNCTION__, array()); -/** - * Execute a module's data handler. - * - * @param $type - * The type of handler to execute. Possible values: - * - 'access_handler': - * - 'contextual_links': - * - 'data_handler': - * - 'form_index_handler': - * - 'preprocess_index_handler': - * - 'preprocess_hook_callback': - * - 'submit_handler': - * @param $op - * For 'access_handler' the possible values are 'edit skin settings' - * and 'edit advanced skin settings'. - * For 'contextual_links' an empty string is passed. - * For 'data_handler' the possible values are 'form' and 'submit'. - * For 'form_index_handler' the possible values are 'form' and 'submit'. - * For 'preprocess_index_handler' the possible values are 'preprocess'. - * For 'preprocess_hook_callback' an empty string is passed. - * For 'submit_handler' an empty string is passed. - * @param $handler - * The function name for this handler as gotten from skinr_fetch_config(). - * @param $a3 - * For 'access_handler', passes in the $form parameter as provided to a form - * function. - * For 'contextual_links', passes in the $variables parameter from - * skinr_preprocess(). - * For 'data_handler', passes in the $form parameter from hook_form_submit(). - * For 'form_index_handler': - * - For $op 'form', passes in the $form parameter from hook_form_alter(). - * - For $op 'submit', passes in the $form parameter from hook_form_submit(). - * For 'preprocess_index_handler', passes in the $variables parameter from - * module_preprocess(). - * For 'preprocess_hook_callback', passes in the $form parameter from - * hook_form_alter(). - * For 'submit_handler', passes in the $form parameter from hook_form_alter(). - * - * @param $a4 - * For 'access_handler', passes in the $form_state array as provided to a - * form function. - * For 'data_handler', passes in the $form_state parameter form - * hook_form_submit(). - * For 'form_index_handler': - * - For $op 'form', passes in the $form_state parameter from - * hook_form_alter(). - * - For $op 'submit', passes in the $form_state parameter from - * hook_form_submit(). - * For 'preprocess_hook_callback', passes in the $form_state parameter from - * hook_form_alter(). - * For 'submit_handler', passes in the $form_state parameter from - * hook_form_alter(). - * @param $a5 - * For 'data_handler', passes in the module that is currently being processed. - * For 'submit_handler', passes in the module that is currently being - * processed. - * @param $a6 - * For 'data_handler', passes in the settings from hook_skinr_config() for - * the form that's currently being processed. - * For 'submit_handler', passes in the settings from hook_skinr_config() for - * the form that's currently being processed. - * @param $a7 - */ -function skinr_handler($type, $op, $handler, &$a3, $a4 = NULL, $a5 = NULL, $a6 = NULL, $a7 = NULL) { - // @todo Once we eliminate skinr_handler, all functions in skinr.handlers.inc can - // be moved out of it and the file eliminated. - if (in_array($handler, array('skinr_access_handler', 'skinr_index_handler', 'skinr_data_handler', 'skinr_submit_handler'))) { - module_load_include('inc', 'skinr', 'skinr.handlers'); + if (!isset($theme_hooks[$module][$element])) { + // Invoke hook_skinr_theme_hooks() and hook_skinr_theme_hooks_alter(). + $theme_hooks[$module][$element] = skinr_invoke_all('skinr_theme_hooks', $module, $element); + drupal_alter('skinr_theme_hooks', $theme_hooks[$module][$element], $module, $element); } - if (is_callable($handler)) { - switch ($type) { - case 'contextual_links': - case 'preprocess_index_handler': - return $handler($a3); - - case 'preprocess_hook_callback': - return $handler($a3, $a4); - - case 'data_handler': - case 'submit_handler': - return $handler($a3, $a4, $a5, $a6, $a7); - - default: - return $handler($op, $a3, $a4); - } - } + return $theme_hooks[$module][$element]; } /** @@ -1371,3 +1437,28 @@ function skinr_themes_enabled() { function skinr_themes_disabled() { skinr_cache_reset(); } + +/** + * Helper function for built-in integration code. + */ +function skinr_skinr_api_modules() { + return array( + 'path' => drupal_get_path('module', 'skinr') . '/modules', + ); +} + +function block_skinr_api_2() { + return skinr_skinr_api_modules(); +} + +function comment_skinr_api_2() { + return skinr_skinr_api_modules(); +} + +function node_skinr_api_2() { + return skinr_skinr_api_modules(); +} + +function views_skinr_api_2() { + return skinr_skinr_api_modules(); +} diff --git a/skinr.skinr.inc b/skinr.skinr.inc index 862a332..f8c2e80 100644 --- a/skinr.skinr.inc +++ b/skinr.skinr.inc @@ -2,13 +2,14 @@ /** * @file - * Provide skinr handling for page level rules. + * Implements page and region level rules, and adds default groups. */ /** - * @defgroup skinr page rule handlers - * @{ + * Implements hook_skinr_api_VERSION(). */ +function skinr_skinr_api_2() { +} /** * Implements hook_skinr_group_info(). @@ -38,162 +39,46 @@ function skinr_skinr_group_info() { * Implementation of hook_skinr_config_info(). */ function skinr_skinr_config_info() { - $data['rules']['form']['skinr_rule_edit'] = array( - 'index_handler' => 'rules_skinr_form_index_handler', - 'preprocess_hook_callback' => 'rules_skinr_preprocess_hook_callback', - 'title' => t('rule settings'), - 'skinr_weight' => 0, - 'collapsed' => FALSE, - ); - $data['rules']['form']['skinr_ui_form'] = array( - 'preprocess_hook_callback' => 'rules_skinr_preprocess_hook_callback', - 'title' => t('rule settings'), - 'collapsed' => FALSE, - ); - $data['rules']['preprocess']['html'] = array( - 'index_handler' => 'rules_skinr_preprocess_index_handler', - ); - $data['rules']['preprocess']['region'] = array( - 'index_handler' => 'rules_skinr_preprocess_index_handler', - ); - $data['rules']['contextual_links']['html'] = array( - 'contextual_links_handler' => 'rules_skinr_contextual_links', - ); - $data['rules']['contextual_links']['region'] = array( - 'contextual_links_handler' => 'rules_skinr_contextual_links', - ); - - return $data; -} - -/** - * Skinr form index handler. - * - * @param $op - * What kind of action is being performed. Possible values: - * - 'form': the form elements for Skinr are being inserted in a form. - * - 'submit': the form has been submitted. - * @param &$form - * - For 'form', passes in the $form parameter from hook_form_alter(). - * - For 'submit', passes in the $form parameter from hook_form_submit(). - * @param $form_state - * - For 'form', passes in the $form_state parameter from hook_form_alter(). - * - For 'submit', passes in the $form_state parameter from hook_form_submit(). - * @return - * The index where we can find our values in Skinr's data structure. - */ -function rules_skinr_form_index_handler($op, &$form, $form_state) { - switch ($op) { - case 'form': - if (!empty($form['rule']['rid']['#value'])) { - return $form['rule']['rid']['#value']; - } - else { - return 0; - } - - case 'submit': - return $form_state['values']['rid']; - } + return array('rules'); } /** - * Skinr preprocess_hook_callback. - * - * @param &$form - * Passes in the $form parameter from hook_form_alter(). - * @param $form_state - * Passes in the $form_state parameter from hook_form_alter(). - * @return - * The preprocess_hook we wish to use. + * Implements hook_skinr_theme_hooks(). */ -function rules_skinr_preprocess_hook_callback(&$form, $form_state) { - $preprocess_hooks = array(); +function skinr_skinr_theme_hooks($module, $element) { + $theme_hooks = array(); - if (!empty($form['rule'])) { - $hooks = explode('__', $form['rule']['rule_type']['#value']); - } - else { - $rule = skinr_rule_load($form['skinr']['element']['#value']); + if ($module == 'rules') { + $rule = skinr_rule_load($element); $hooks = explode('__', $rule->rule_type); - } - while (count($hooks)) { - $preprocess_hooks[] = implode('__', $hooks); - array_pop($hooks); + while (count($hooks)) { + $theme_hooks[] = implode('__', $hooks); + array_pop($hooks); + } } - return $preprocess_hooks; + return $theme_hooks; } /** - * Skinr preprocess index handler. - * - * @param &$variables - * Passes in the $variables parameter from module_preprocess(). - * @return - * The index where we can find our values in Skinr's data structure. If an - * array is returned, it will loop through each index in Skinr's data - * structure and merge the returned classes. + * Implements hook_skinr_elements(). */ -function rules_skinr_preprocess_index_handler(&$variables) { - if (!empty($variables['region'])) { - $rule_type = 'region__' . $variables['region']; - } - else { - $rule_type = 'page'; - } - $rules = skinr_rule_load_multiple(array(), array('rule_type' => $rule_type)); +function skinr_skinr_elements($variables, $hook) { + $elements = array(); + if ($hook == 'html' || $hook == 'region') { + $elements['rules'] = array(); - // Find any page level skinr options and return an array of them. - $indices = array(); - foreach ($rules as $rule) { - if (skinr_rule_is_visible($rule->rid)) { - $indices[] = $rule->rid; - } - } - return $indices; -} - -/** - * Skinr contextual links handler. - * - * @param &$variables - * Passes in the $variables parameter from skinr_preprocess(). - * @return - * An associative array. Each value is an array that forms the function - * arguments for menu_contextual_links(). For example: - * @code - * $links = array( - * 'skinr-modulename' => array( - * 'admin/appearance/skinr/edit', array('system', 'navigation')), - * ), - * 'skinr-modulename-1' => array( - * 'admin/appearance/skinr/edit', array('system', 'something-else')), - * ), - * ); - * @endcode - */ -function rules_skinr_contextual_links(&$variables) { - if (!empty($variables['region'])) { - $rule_type = 'region__' . $variables['region']; - } - else { $rule_type = 'page'; - } - $rules = skinr_rule_load_multiple(array(), array('rule_type' => $rule_type)); - $links = array(); - $counter = 1; + if ($hook == 'region') { + $rule_type = 'region__' . $variables['region']; + } - foreach ($rules as $rule) { - if (skinr_rule_is_visible($rule->rid)) { - $links['skinr-rule-' . $counter++] = array( - 'admin/config/skinr/edit/nojs', array('rule', $rule->rid), - ); + $rules = skinr_rule_load_multiple(array(), array('rule_type' => $rule_type)); + foreach ($rules as $rule) { + if (skinr_rule_is_visible($rule->rid)) { + $elements['rules'][] = $rule->rid; + } } } - return $links; + return $elements; } - -/** - * @} - */ diff --git a/skinr_panels/skinr_panels.module b/skinr_panels/skinr_panels.module index 6083fab..72eb3bc 100644 --- a/skinr_panels/skinr_panels.module +++ b/skinr_panels/skinr_panels.module @@ -16,11 +16,7 @@ * Implements hook_skinr_api(). */ function skinr_panels_skinr_api_2() { - // @todo An empty array can be returned once we remove skinr_handlers() and - // implement proper hooks for plugin functions. - return array( - 'path' => drupal_get_path('module', 'skinr_panels'), - ); + return array(); } /** @@ -56,27 +52,35 @@ function skinr_panels_theme_registry_alter(&$theme_registry) { */ function skinr_panels_preprocess(&$variables, $hook) { if ($hook == 'panels_pane' && user_access('edit skin settings')) { - // Ensure includes are properly loaded. - // @todo Remove this once we have proper hooks for plugin functions. - skinr_get_config_info(); // Get contextual links. - $contextual_links = skinr_handler('contextual_links', '', 'skinr_panels_skinr_contextual_links', $variables); + $contextual_links = array(); + $counter = 0; + $array_elements = skinr_invoke_all('skinr_elements', $variables, $hook, 'contextual_links'); + $module = 'panels'; + $elements = $array_elements[$module]; - // Need to set contextual links through Skinr API so we have a valid, and - // consistent, link title. It's also used in our hook_preprocess_links() - // hack. - _skinr_ui_set_contextual_links($hook, $contextual_links); + foreach ($elements as $element) { + $contextual_links['skinr-' . $module . '-' . $counter++] = array( + 'admin/appearance/skinr/edit/nojs', array($module, $element), + ); + } + if (!empty($contextual_links)) { + // Need to set contextual links through Skinr API so we have a valid, and + // consistent, link title. It's also used in our hook_preprocess_links() + // hack. + _skinr_ui_set_contextual_links($hook, $contextual_links); - // Render links. - $element = array( - '#type' => 'contextual_links', - '#contextual_links' => $contextual_links, - ); - $element = contextual_pre_render_links($element); + // Render links. + $element = array( + '#type' => 'contextual_links', + '#contextual_links' => $contextual_links, + ); + $element = contextual_pre_render_links($element); - // Add in the Skinr links. - $variables['content']->admin_links += $element['#links']; + // Add in the Skinr links. + $variables['content']->admin_links += $element['#links']; + } } } diff --git a/skinr_panels/skinr_panels.skinr.inc b/skinr_panels/skinr_panels.skinr.inc index 25cac37..7400262 100644 --- a/skinr_panels/skinr_panels.skinr.inc +++ b/skinr_panels/skinr_panels.skinr.inc @@ -1,97 +1,44 @@ 'skinr_panels_skinr_preprocess_hook_callback', - 'title' => t('panel pane settings'), - 'collapsed' => FALSE, - ); - $data['panels']['preprocess']['panels_pane'] = array( - 'index_handler' => 'skinr_panels_skinr_preprocess_index_handler', - ); - $data['panels']['contextual_links']['panels_pane'] = array( - 'contextual_links_handler' => 'skinr_panels_skinr_contextual_links', - ); - - return $data; + return array('panels'); } /** - * Skinr preprocess hook callback. - * - * @param &$form - * Passes in the $form parameter from hook_form_alter(). - * @param $form_state - * Passes in the $form_state parameter from hook_form_alter(). - * - * @return - * An array of preprocess hooks we wish to use. + * Implements hook_skinr_theme_hooks(). */ -function skinr_panels_skinr_preprocess_hook_callback(&$form, $form_state) { - if (strpos($form['skinr']['element']['#value'], 'region') === 0) { - return 'panels_region'; - } - elseif (strpos($form['skinr']['element']['#value'], 'pane') === 0) { - return 'panels_pane'; - } - else { - return 'panels_display'; +function skinr_panels_skinr_theme_hooks($module, $element) { + $theme_hooks = array(); + + if ($module == 'panels') { + if (strpos($element, 'region') === 0) { + $theme_hooks[] = 'panels_region'; + } + elseif (strpos($element, 'pane') === 0) { + $theme_hooks[] = 'panels_pane'; + } + else { + $theme_hooks[] = 'panels_display'; + } } -} -/** - * Skinr preprocess index handler. - * - * @param &$variables - * Passes in the $variables parameter from module_preprocess(). - * - * @return - * The index where we can find our values in Skinr's data structure. If an - * array is returned, it will loop through each index in Skinr's data - * structure and merge the returned classes. - */ -function skinr_panels_skinr_preprocess_index_handler(&$variables) { - $index = array(); - $index[] = 'pane__' . $variables['pane']->did . '__' . $variables['pane']->pid; - return $index; + return $theme_hooks; } /** - * Skinr contextual links handler. - * - * @param &$variables - * Passes in the $variables parameter from skinr_preprocess(). - * - * @return - * An array. Each value is an array that forms the function arguments for - * menu_contextual_links(). For example: - * @code - * array( - * 'admin/appearance/skinr/edit', array('system', 'navigation')), - * ) - * @endcode + * Implements hook_skinr_elements(). */ -function skinr_panels_skinr_contextual_links(&$variables) { - $links = array(); - $links['skinr-panels'] = array( - 'admin/appearance/skinr/edit/nojs', array('panels', 'pane__' . $variables['pane']->did . '__' . $variables['pane']->pid), - ); - return $links; +function skinr_panels_skinr_elements($variables, $hook) { + $elements = array(); + if ($hook == 'panels_pane') { + $elements['panels'] = array('pane__' . $variables['pane']->did . '__' . $variables['pane']->pid); + } + return $elements; } - -/** - * @} - */ diff --git a/skinr_panels/tests/skinr_panels.test b/skinr_panels/tests/skinr_panels.test index d64de8f..fc213ae 100644 --- a/skinr_panels/tests/skinr_panels.test +++ b/skinr_panels/tests/skinr_panels.test @@ -41,8 +41,12 @@ class SkinrPanelsTestCase extends DrupalWebTestCase { /** * Tests panels plugin. + * + * @todo The below test doesn't work due to CTools/Panels not passing along + * enough data to create unique element ids when panels are in code. Skinr + * currently doesn't support panels in code. */ - function testPanelsDefault() { + function xtestPanelsDefault() { // Test panels pages. // Go to panel page. $this->drupalGet('skinr-panels-test-panel'); diff --git a/skinr_ui.admin.inc b/skinr_ui.admin.inc index 06d02c0..3b9595d 100644 --- a/skinr_ui.admin.inc +++ b/skinr_ui.admin.inc @@ -84,7 +84,7 @@ function skinr_ui_filters() { $config = skinr_get_config_info(); $options = array('[any]' => t('any')); - foreach ($config as $type => $data) { + foreach ($config as $type) { $options[$type] = $type; } diff --git a/skinr_ui.api.php b/skinr_ui.api.php new file mode 100644 index 0000000..cbc400a --- /dev/null +++ b/skinr_ui.api.php @@ -0,0 +1,24 @@ + array('administer skinr'), 'file' => 'skinr_ui.rules.inc', ); - $items['admin/appearance/skinr/rules/edit'] = array( + $items['admin/appearance/skinr/rules/edit/%skinr_rule'] = array( 'title' => 'Edit rule', 'page callback' => 'drupal_get_form', - 'page arguments' => array('skinr_rule_edit'), + 'page arguments' => array('skinr_rule_edit', 5), 'type' => MENU_CALLBACK, 'access arguments' => array('administer skinr'), 'file' => 'skinr_ui.rules.inc', ); - $items['admin/appearance/skinr/rules/delete'] = array( + $items['admin/appearance/skinr/rules/delete/%skinr_rule'] = array( 'title' => 'Delete rule', 'page callback' => 'drupal_get_form', - 'page arguments' => array('skinr_rule_delete_confirm'), + 'page arguments' => array('skinr_rule_delete_confirm', 5), 'type' => MENU_CALLBACK, 'access arguments' => array('administer skinr'), 'file' => 'skinr_ui.rules.inc', @@ -258,7 +275,14 @@ function skinr_ui_help($path, $arg) { return '

' . t('To import skin configurations, paste exported code and click the "Import" button.') . '

'; case 'admin/appearance/skinr/export': return '

' . t('To export skin configurations, ensure the correct theme is selected and click the "Export" button.') . '

'; - break; + case 'admin/appearance/skinr/edit/%/%/%': + // @todo Make this help text more relevant. + $theme_hooks = skinr_theme_hooks($arg[5], $arg[6]); + return '

' . t('Manage which skins you want to apply to the hooks !hooks.', array('!hooks' => implode(', ', $theme_hooks))) . '

'; + case 'admin/appearance/skinr/rules/edit/%': + // @todo Make this help text more relevant. + $theme_hooks = skinr_theme_hooks('rules', $arg[5]); + return '

' . t('Manage which skins you want to apply to the hooks !hooks.', array('!hooks' => implode(', ', $theme_hooks))) . '

'; } } @@ -289,11 +313,10 @@ function skinr_ui_edit_contextual_title($module, $element) { foreach ($links as $link) { if ($link[1][0] == $module && $link[1][1] == $element) { if (count($links) > 1) { - return t('Edit skin !number', array('!number' => $counter)); + return t('Edit skin !number', array('!number' => $counter++)); } break 2; } - $counter++; } } return t('Edit skin'); @@ -355,7 +378,8 @@ function skinr_ui_form($form, &$form_state, $arguments) { ); } - $form['submit'] = array( + $form['actions'] = array('#type' => 'actions'); + $form['actions']['submit'] = array( '#type' => 'submit', '#value' => t('Save'), '#weight' => 50, @@ -373,7 +397,20 @@ function skinr_ui_form_alter(&$form, $form_state, $form_id) { return; } - $config = skinr_get_config_info(); + // Ensure module and element values are set. + if (empty($form['skinr']['module']['#value']) || empty($form['skinr']['element']['#value'])) { + return; + } + + // Check for access. + if (!skinr_ui_access('edit skin settings')) { + // Deny access. + return; + } + + $module = $form['skinr']['module']['#value']; + $element = $form['skinr']['element']['#value']; + $groups = skinr_get_group_info(); $skin_infos = skinr_get_skin_info(); @@ -382,234 +419,197 @@ function skinr_ui_form_alter(&$form, $form_state, $form_id) { $skin_infos[$skin_name]['status'] = skinr_skin_info_status_get($skin_infos[$skin_name]); } - foreach ($config as $module => $module_settings) { - if (isset($module_settings['form'][$form_id])) { - if (!empty($form['skinr']) && $form['skinr']['module']['#value'] !== $module) { - continue; - } - - $form_settings = array_merge(skinr_config_info_default(), $module_settings['form'][$form_id]); - - // Check for access. - if (!skinr_handler('access_handler', 'edit skin settings', $form_settings['access_handler'], $form, $form_state)) { - // Deny access. - break; - } - - // Ensure we have the required preprocess_hook or preprocess_hook_callback. - if (empty($form_settings['preprocess_hook']) && empty($form_settings['preprocess_hook_callback'])) { - trigger_error(sprintf("No preprocess_hook or preprocess_hook_callback was found for form_id '%s' in module '%s'.", $form_id, $module), E_USER_ERROR); - } + // Invoke hook_skinr_theme_hooks() and hook_skinr_theme_hooks_alter(). + $theme_hooks = skinr_theme_hooks($module, $element); - $themes = list_themes(); - ksort($themes); + $form['skinr_settings'] = array( + '#tree' => TRUE, + // Set weight to accommodate Rules UI. + '#weight' => 0, + ); - foreach ($themes as $theme) { - if (!$theme->status) { - continue; - } - if (!isset($form['skinr_settings'])) { - $form['skinr_settings'] = array( - '#tree' => TRUE, - '#weight' => $form_settings['skinr_weight'], - ); - } - - $preprocess_hooks = isset($form_settings['preprocess_hook']) ? $form_settings['preprocess_hook'] : skinr_handler('preprocess_hook_callback', '', $form_settings['preprocess_hook_callback'], $form, $form_state); - if (!is_array($preprocess_hooks)) { - $preprocess_hooks = array($preprocess_hooks); - } + $themes = list_themes(); + ksort($themes); + // Get current theme, but make sure it's not the admin theme when we're editing with AJAX. + $current_theme = skinr_current_theme(TRUE); - // If this hook is a region, and the region does not exist for this - // theme, don't bother outputting any of the settings. - if (strpos($preprocess_hooks[0], 'region') === 0) { - // Strip the region__ part off the region name. - $region = substr($preprocess_hooks[0], 8); + foreach ($themes as $theme) { + if (!$theme->status) { + continue; + } - $regions = system_region_list($theme->name, REGIONS_VISIBLE); - if (!isset($regions[$region])) { - continue; - } - } + // If this hook is a region, and the region does not exist for this + // theme, don't bother outputting any of the settings. + if (strpos($theme_hooks[0], 'region') === 0) { + // Strip the region__ part off the region name. + $region = substr($theme_hooks[0], 8); - if (!$form_state['submitted']) { - if ($skins = skinr_handler('data_handler', 'form', $form_settings['data_handler'], $form, $form_state, $theme->name, $module, $form_settings)) { - $defaults = array(); - foreach ($skins as $skin) { - $defaults[$skin->skin] = $skin->options; - } - } - else { - $defaults = array(); - } - } - else { - // Handle preview before submit. - // @todo Is this still needed? If so, it needs to be fixed. - $defaults = $form_state['values']; - } + $regions = system_region_list($theme->name, REGIONS_VISIBLE); + if (!isset($regions[$region])) { + continue; + } + } - if (!isset($form['skinr_settings'][$module . '_group'])) { - $form['skinr_settings'][$module . '_group'] = array( - '#type' => 'fieldset', - '#title' => t('@skinr_title @title', array('@skinr_title' => $form_settings['skinr_title'], '@title' => $form_settings['title'])), - '#description' => t($form_settings['description']) . ' ' . implode(', ', $preprocess_hooks) . '.', - '#weight' => $form_settings['weight'], - '#collapsible' => TRUE, - '#collapsed' => $form_settings['collapsed'], - ); + if (!$form_state['submitted']) { + $params = array( + 'theme' => $theme->name, + 'module' => $module, + 'element' => $element, + ); + if ($skins = skinr_skin_load_multiple(skinr_skin_get_sids($params))) { + $defaults = array(); + foreach ($skins as $skin) { + $defaults[$skin->skin] = $skin->options; } + } + else { + $defaults = array(); + } + } + else { + // Handle preview before submit. + // @todo Is this still needed? If so, it needs to be fixed. + $defaults = $form_state['values']; + } - // Get current theme, but make sure it's not the admin theme when we're editing with AJAX. - $current_theme = skinr_current_theme(TRUE); - - $form['skinr_settings'][$module . '_group'][$theme->name] = array( - '#type' => 'fieldset', - '#title' => $theme->info['name'] . ($theme->name == $current_theme ? ' (' . t('enabled + default') . ')' : ''), - '#collapsible' => TRUE, - '#collapsed' => $theme->name == $current_theme ? FALSE : TRUE, + if (!isset($form['skinr_settings'][$module . '_group'])) { + $form['skinr_settings'][$module . '_group'] = array( + '#type' => 'container', + ); + if ($module == 'rules') { + $form['skinr_settings']['skinr_settings_title'] = array( + '#type' => 'item', + '#title' => t('Skinr settings'), + '#weight' => -1, ); - if ($theme->name == $current_theme) { - $form['skinr_settings'][$module . '_group'][$theme->name]['#attributes'] = array('class' => array('skinr-ui-current-theme')); - $form['skinr_settings'][$module . '_group'][$theme->name]['#weight'] = -10; - } - - // Create individual widgets for each skin. - foreach ($skin_infos as $skin_name => $skin_info) { - // Check if this skin is disabled. - if (empty($skin_info['status'][$theme->name])) { - continue; - } + } + } - // Check if this skin applies to this hook. - if (!is_array($skin_info['theme hooks']) || (!in_array('*', $skin_info['theme hooks']) && !_skinr_is_featured($preprocess_hooks, $skin_info['theme hooks']))) { - continue; - } + $form['skinr_settings'][$module . '_group'][$theme->name] = array( + '#type' => 'fieldset', + '#title' => $theme->info['name'] . ($theme->name == $current_theme ? ' (' . t('enabled + default') . ')' : ''), + '#collapsible' => TRUE, + '#collapsed' => $theme->name == $current_theme ? FALSE : TRUE, + ); + if ($theme->name == $current_theme) { + // Current theme goes at the top. + $form['skinr_settings'][$module . '_group'][$theme->name]['#attributes'] = array('class' => array('skinr-ui-current-theme')); + $form['skinr_settings'][$module . '_group'][$theme->name]['#weight'] = -10; + } - // Create widget. - $field = array(); - if (!empty($skin_info['form callback']) && function_exists($skin_info['form callback'])) { - // @todo Allow for custom form callbacks. - } - else { - switch ($skin_info['type']) { - case 'checkboxes': - $field = array( - '#type' => 'checkboxes', - '#multiple' => TRUE, - '#title' => t($skin_info['title']), - '#options' => skinr_ui_info_options_to_form_options($skin_info['options']), - '#default_value' => isset($defaults[$skin_name]) ? $defaults[$skin_name] : array(), - '#description' => t($skin_info['description']), - '#weight' => isset($skin_info['weight']) ? $skin_info['weight'] : NULL, - ); - break; - case 'radios': - $field = array( - '#type' => 'radios', - '#title' => t($skin_info['title']), - '#options' => array_merge(array('' => '<none>'), skinr_ui_info_options_to_form_options($skin_info['options'])), - '#default_value' => isset($defaults[$skin_name]) ? $defaults[$skin_name] : '', - '#description' => t($skin_info['description']), - '#weight' => isset($skin_info['weight']) ? $skin_info['weight'] : NULL, - ); - break; - case 'select': - $field = array( - '#type' => 'select', - '#title' => t($skin_info['title']), - '#options' => array_merge(array('' => ''), skinr_ui_info_options_to_form_options($skin_info['options'])), - '#default_value' => isset($defaults[$skin_name]) ? $defaults[$skin_name] : '', - '#description' => t($skin_info['description']), - '#weight' => isset($skin_info['weight']) ? $skin_info['weight'] : NULL, - ); - break; - default: - // Raise an error. - drupal_set_message(t("Widget %name's type is invalid.", array('%name' => $skin_name)), 'error', FALSE); - break; - } - } - if (empty($skin_info['group']) || empty($groups[$skin_info['group']])) { - $form['skinr_settings'][$module . '_group'][$theme->name][$skin_name] = $field; - } - else { - if (!empty($field) && !isset($form['skinr_settings'][$module . '_group'][$theme->name][$skin_info['group']])) { - $group = $groups[$skin_info['group']]; - $form['skinr_settings'][$module . '_group'][$theme->name][$skin_info['group']] = array( - '#type' => 'fieldset', - '#title' => t($group['title']), - '#description' => t($group['description']), - '#weight' => isset($group['weight']) ? $group['weight'] : NULL, - ); - } - $form['skinr_settings'][$module . '_group'][$theme->name][$skin_info['group']][$skin_name] = $field; - } - } + // Create individual widgets for each skin. + foreach ($skin_infos as $skin_name => $skin_info) { + // Check if this skin is disabled. + if (empty($skin_info['status'][$theme->name])) { + continue; + } - // Check for access. - if (skinr_handler('access_handler', 'edit advanced skin settings', $form_settings['access_handler'], $form, $form_state)) { - $skin_name = '_additional'; - $form['skinr_settings'][$module . '_group'][$theme->name]['_additional'] = array( - '#type' => 'textfield', - '#title' => t('CSS classes'), - '#size' => 40, - '#description' => t('To add CSS classes manually, enter classes separated by a single space i.e. first-class second-class'), - '#default_value' => isset($defaults[$skin_name]) ? $defaults[$skin_name] : '', - ); + // Check if this skin applies to this hook. + if (!is_array($skin_info['theme hooks']) || (!in_array('*', $skin_info['theme hooks']) && !_skinr_is_featured($theme_hooks, $skin_info['theme hooks']))) { + continue; + } - // Only add validation handler once. - if (!isset($form['#validate']) || !in_array('skinr_ui_form_validate', $form['#validate'])) { - $form['#validate'][] = 'skinr_ui_form_validate'; - } - // Special for views. - if (isset($form['buttons']['submit']['#validate']) && !in_array('skinr_ui_form_validate', $form['buttons']['submit']['#validate'])) { - $form['buttons']['submit']['#validate'][] = 'skinr_ui_form_validate'; - } + // Create widget. + $field = array(); + if (!empty($skin_info['form callback']) && function_exists($skin_info['form callback'])) { + // @todo Allow for custom form callbacks. + } + else { + switch ($skin_info['type']) { + case 'checkboxes': + $field = array( + '#type' => 'checkboxes', + '#multiple' => TRUE, + '#title' => t($skin_info['title']), + '#options' => skinr_ui_info_options_to_form_options($skin_info['options']), + '#default_value' => isset($defaults[$skin_name]) ? $defaults[$skin_name] : array(), + '#description' => t($skin_info['description']), + '#weight' => isset($skin_info['weight']) ? $skin_info['weight'] : NULL, + ); + break; + case 'radios': + $field = array( + '#type' => 'radios', + '#title' => t($skin_info['title']), + '#options' => array_merge(array('' => '<none>'), skinr_ui_info_options_to_form_options($skin_info['options'])), + '#default_value' => isset($defaults[$skin_name]) ? $defaults[$skin_name] : '', + '#description' => t($skin_info['description']), + '#weight' => isset($skin_info['weight']) ? $skin_info['weight'] : NULL, + ); + break; + case 'select': + $field = array( + '#type' => 'select', + '#title' => t($skin_info['title']), + '#options' => array_merge(array('' => ''), skinr_ui_info_options_to_form_options($skin_info['options'])), + '#default_value' => isset($defaults[$skin_name]) ? $defaults[$skin_name] : '', + '#description' => t($skin_info['description']), + '#weight' => isset($skin_info['weight']) ? $skin_info['weight'] : NULL, + ); + break; + default: + // Raise an error. + drupal_set_message(t("Widget %name's type is invalid.", array('%name' => $skin_name)), 'error', FALSE); + break; } } - - // Add weight to additional settings and submit form elements. - $form['additional_settings']['#weight'] = 39; - $form['submit']['#weight'] = 40; - - // Only add submit handler once. - // Find the property to check. - $attr = &$form; - foreach($form_settings['submit_handler_attach_to'] as $part) { - $attr = &$attr[$part]; + if (empty($skin_info['group']) || empty($groups[$skin_info['group']])) { + $form['skinr_settings'][$module . '_group'][$theme->name][$skin_name] = $field; } - if (!empty($attr) && !in_array('skinr_ui_form_submit', $attr)) { - $string = $attr[] = 'skinr_ui_form_submit'; + else { + if (!empty($field) && !isset($form['skinr_settings'][$module . '_group'][$theme->name][$skin_info['group']])) { + $group = $groups[$skin_info['group']]; + $form['skinr_settings'][$module . '_group'][$theme->name][$skin_info['group']] = array( + '#type' => 'fieldset', + '#title' => t($group['title']), + '#description' => t($group['description']), + '#weight' => isset($group['weight']) ? $group['weight'] : NULL, + ); + } + $form['skinr_settings'][$module . '_group'][$theme->name][$skin_info['group']][$skin_name] = $field; } + } - // Keep looping, there might be other modules that implement the same form_id. + // Check for access. + if (skinr_ui_access('edit advanced skin settings')) { + $skin_name = '_additional'; + $form['skinr_settings'][$module . '_group'][$theme->name]['_additional'] = array( + '#type' => 'textfield', + '#title' => t('CSS classes'), + '#size' => 40, + '#description' => t('To add CSS classes manually, enter classes separated by a single space i.e. first-class second-class'), + '#default_value' => isset($defaults[$skin_name]) ? $defaults[$skin_name] : '', + ); } } + + // Only add validation handler once. + if (!isset($form['#validate']) || !in_array('skinr_ui_form_validate', $form['#validate'])) { + $form['#validate'][] = 'skinr_ui_form_validate'; + } + + // Only add submit handler once. + if (!isset($form['#submit']) || !in_array('skinr_ui_form_submit', $form['#submit'])) { + $form['#submit'][] = 'skinr_ui_form_submit'; + } } /** * Form validation handler for skinr_ui_form_alter(). */ function skinr_ui_form_validate($form, &$form_state) { - $form_id = $form_state['values']['form_id']; - $config = skinr_get_config_info(); + $module = $form_state['values']['module']; + $element = $form_state['values']['element']; $error = FALSE; - foreach ($config as $module => $module_settings) { - if (isset($module_settings['form'][$form_id]) && isset($form_state['values']['skinr_settings'][$module . '_group'])) { - foreach ($form_state['values']['skinr_settings'][$module . '_group'] as $theme_name => $theme) { - if (isset($theme['_additional'])) { - $form_settings = array_merge(skinr_config_info_default(), $module_settings['form'][$form_id]); - - // Validate additional classes field. - if (preg_match('/[^a-zA-Z0-9\-\_\s]/', $theme['_additional'])) { - form_set_error('skinr_settings][' . $module . '_group][' . $theme_name . '][_additional', t('Additional classes for Skinr may only contain alphanumeric characters, spaces, - and _.')); - $error = TRUE; - } - - // Keep looping, there might be other modules that implement the same form_id. + if (isset($form_state['values']['skinr_settings'][$module . '_group'])) { + foreach ($form_state['values']['skinr_settings'][$module . '_group'] as $theme_name => $theme) { + if (isset($theme['_additional'])) { + // Validate additional classes field. + if (preg_match('/[^a-zA-Z0-9\-\_\s]/', $theme['_additional'])) { + form_set_error('skinr_settings][' . $module . '_group][' . $theme_name . '][_additional', t('Additional classes for Skinr may only contain alphanumeric characters, spaces, - and _.')); + $error = TRUE; } } } @@ -618,15 +618,13 @@ function skinr_ui_form_validate($form, &$form_state) { // Undo any grouping to ease processing on submit. if (!$error) { $groups = skinr_get_group_info(); - foreach ($config as $module => $module_settings) { - if (isset($module_settings['form'][$form_id]) && isset($form_state['values']['skinr_settings'][$module . '_group'])) { - foreach ($form_state['values']['skinr_settings'][$module . '_group'] as $theme_name => $theme) { - foreach ($groups as $group_name => $group) { - if (!empty($theme[$group_name]) && is_array($theme[$group_name])) { - $group_values = $theme[$group_name]; - unset($form_state['values']['skinr_settings'][$module . '_group'][$theme_name][$group_name]); - $form_state['values']['skinr_settings'][$module . '_group'][$theme_name] = array_merge($form_state['values']['skinr_settings'][$module . '_group'][$theme_name], $group_values); - } + if (isset($form_state['values']['skinr_settings'][$module . '_group'])) { + foreach ($form_state['values']['skinr_settings'][$module . '_group'] as $theme_name => $theme) { + foreach ($groups as $group_name => $group) { + if (!empty($theme[$group_name]) && is_array($theme[$group_name])) { + $group_values = $theme[$group_name]; + unset($form_state['values']['skinr_settings'][$module . '_group'][$theme_name][$group_name]); + $form_state['values']['skinr_settings'][$module . '_group'][$theme_name] = array_merge($form_state['values']['skinr_settings'][$module . '_group'][$theme_name], $group_values); } } } @@ -638,16 +636,68 @@ function skinr_ui_form_validate($form, &$form_state) { * Form submission handler for skinr_ui_form_alter(). */ function skinr_ui_form_submit($form, &$form_state) { - $form_id = $form_state['values']['form_id']; - $config = skinr_get_config_info(); $current_theme = skinr_current_theme(TRUE); - foreach ($config as $module => $module_settings) { - if (isset($module_settings['form'][$form_id])) { - $form_settings = array_merge(skinr_config_info_default(), $module_settings['form'][$form_id]); - skinr_handler('submit_handler', '', $form_settings['submit_handler'], $form, $form_state, $module, $form_settings); + $module = $form_state['values']['module']; + $element = $form_state['values']['element']; + + if (isset($form_state['values']['skinr_settings'][$module . '_group'])) { + foreach ($form_state['values']['skinr_settings'][$module . '_group'] as $theme_name => $theme) { + // Process widgets. + if (!empty($theme) && is_array($theme)) { + foreach ($theme as $skin_name => $options) { + if ($skin_name == '_additional' && !user_access('edit advanced skin settings')) { + // This user doesn't have access to alter these options. + continue; + } + + // Ensure options is an array. + if (!is_array($options)) { + $options = $skin_name == '_additional' ? explode(' ', $options) : array($options); + } + // Sanitize options. + $options = _skinr_array_strip_empty($options); + + // Find existing skin. + $params = array( + 'theme' => $theme_name, + 'module' => $module, + 'element' => $element, + 'skin' => $skin_name, + ); + $sids = skinr_skin_get_sids($params); - // Keep looping, there might be other modules that implement the same form_id. + unset($skin); + if (!empty($sids)) { + $sid = reset($sids); + $skin = skinr_skin_load($sid); + } + + if (empty($options)) { + if (!empty($skin)) { + // Delete this skin configuration. + skinr_skin_delete($skin->sid); + } + continue; + } + + if (empty($skin)) { + // It doesn't exist, so create a new skin. + $skin = new stdClass(); + $skin->theme = $theme_name; + $skin->module = $module; + $skin->element = $element; + $skin->skin = $skin_name; + } + $skin->options = $options; + $skin->status = 1; + + // Save skin. + if (!skinr_skin_save($skin)) { + drupal_set_message(t("Skinr settings for %skin weren't saved due to an error.", array('%skin' => $skin_name)), 'error'); + } + } + } } } } @@ -656,22 +706,26 @@ function skinr_ui_form_submit($form, &$form_state) { * Implements hook_preprocess(). */ function skinr_ui_preprocess(&$variables, $hook) { - $config = skinr_get_config_info(); - $original_hook = $hook; $theme_registry = theme_get_registry(); if (isset($theme_registry[$hook]['original hook'])) { $original_hook = $theme_registry[$hook]['original hook']; } - foreach ($config as $module => $module_settings) { - if (!empty($module_settings['contextual_links'][$original_hook])) { - // Set contextual links. - if ($contextual_links = skinr_handler('contextual_links', '', $module_settings['contextual_links'][$original_hook]['contextual_links_handler'], $variables)) { - skinr_ui_contextual_links($variables, $original_hook, $contextual_links); - } + $contextual_links = array(); + $counter = 0; + $array_elements = skinr_invoke_all('skinr_elements', $variables, $original_hook, 'contextual_links'); + foreach ($array_elements as $module => $elements) { + foreach ($elements as $element) { + $contextual_links['skinr-' . $module . '-' . $counter++] = array( + 'admin/appearance/skinr/edit/nojs', array($module, $element), + ); } } + if (!empty($contextual_links)) { + skinr_ui_contextual_links($variables, $original_hook, $contextual_links); + } + return; } /** @@ -742,9 +796,9 @@ function _skinr_ui_set_contextual_links($hook = NULL, $links = NULL) { * Helper function to determine whether one of a set of hooks exists in a list * of required theme hooks. * - * @param $preprocess_hooks - * An array of theme hooks available to this element. * @param $theme_hooks + * An array of theme hooks available to this element. + * @param $allowed_hooks * An array of allowed theme hooks. * * @return @@ -752,9 +806,9 @@ function _skinr_ui_set_contextual_links($hook = NULL, $links = NULL) { * * @todo Rename function to be more descriptive. */ -function _skinr_is_featured($preprocess_hooks, $theme_hooks) { - foreach ($preprocess_hooks as $preprocess_hook) { - if (in_array($preprocess_hook, $theme_hooks)) { +function _skinr_is_featured($theme_hooks, $allowed_hooks) { + foreach ($theme_hooks as $theme_hook) { + if (in_array($theme_hook, $allowed_hooks)) { return TRUE; } } diff --git a/skinr_ui.rules.inc b/skinr_ui.rules.inc index 2a217e7..911199b 100644 --- a/skinr_ui.rules.inc +++ b/skinr_ui.rules.inc @@ -127,55 +127,41 @@ function skinr_rule_add_submit($form, &$form_state) { * @see skinr_rule_edit_submit() * @ingroup forms */ -function skinr_rule_edit($form, &$form_state, $rid = NULL) { +function skinr_rule_edit($form, &$form_state, $rule) { + $form['skinr']['module'] = array( + '#type' => 'hidden', + '#value' => 'rules', + ); + $form['skinr']['element'] = array( + '#type' => 'hidden', + '#value' => $rule->rid, + ); + $form['rule'] = array( '#weight' => -1, ); - if (isset($form_state['values'])) { - $rule = array( - 'title' => $form_state['values']['title'], - 'rule_type' => $form_state['values']['rule_type'], - 'node_types' => $form_state['values']['types'], - 'roles' => $form_state['values']['roles'], - 'visibility' => $form_state['values']['visibility'], - 'pages' => $form_state['values']['pages'], - ); - } - elseif (isset($rid) && $rule = skinr_rule_load($rid)) { - $rule = (array) $rule; - $form['rule']['rid'] = array( - '#type' => 'value', - '#value' => $rid, - ); - } - else { - $rule = array( - 'title' => '', - 'rule_type' => '', - 'node_types' => array(), - 'roles' => array(), - 'visibility' => 0, - 'pages' => '', - ); - } + $form['rule']['rid'] = array( + '#type' => 'value', + '#value' => $rule->rid, + ); $form['rule']['title'] = array( '#type' => 'textfield', '#title' => t('Rule title'), - '#default_value' => $rule['title'], + '#default_value' => $rule->title, '#description' => t('Descriptive title for this rule; used by administrators.'), '#required' => TRUE, ); $form['rule']['rule_type'] = array( '#type' => 'hidden', - '#value' => $rule['rule_type'], + '#value' => $rule->rule_type, ); $form['rule']['rule_type_displayed'] = array( '#type' => 'item', '#title' => t('Rule type'), - '#markup' => $rule['rule_type'], + '#markup' => $rule->rule_type, '#description' => t('Type of element the rule is applied to.'), ); @@ -202,14 +188,14 @@ function skinr_rule_edit($form, &$form_state, $rid = NULL) { ); $access = user_access('use PHP for settings'); - if (isset($rule['visibility']) && $rule['visibility'] == SKINR_RULE_VISIBILITY_PHP && !$access) { + if ($rule->visibility == SKINR_RULE_VISIBILITY_PHP && !$access) { $form['visibility']['path']['visibility'] = array( '#type' => 'value', '#value' => SKINR_RULE_VISIBILITY_PHP, ); $form['visibility']['path']['pages'] = array( '#type' => 'value', - '#value' => isset($rule['pages']) ? $rule['pages'] : '', + '#value' => $rule->pages, ); } else { @@ -231,12 +217,12 @@ function skinr_rule_edit($form, &$form_state, $rid = NULL) { '#type' => 'radios', '#title' => t('Show block on specific pages'), '#options' => $options, - '#default_value' => isset($rule['visibility']) ? $rule['visibility'] : SKINR_RULE_VISIBILITY_NOTLISTED, + '#default_value' => $rule->visibility, ); $form['visibility']['path']['pages'] = array( '#type' => 'textarea', '#title' => '' . $title . '', - '#default_value' => isset($rule['pages']) ? $rule['pages'] : '', + '#default_value' => $rule->pages, '#description' => $description, ); } @@ -253,7 +239,7 @@ function skinr_rule_edit($form, &$form_state, $rid = NULL) { $form['visibility']['node_type']['types'] = array( '#type' => 'checkboxes', '#title' => t('Show block for specific content types'), - '#default_value' => $rule['node_types'], + '#default_value' => $rule->node_types, '#options' => node_type_get_names(), '#description' => t('Show this block only on pages that display content of the given type(s). If you select no types, there will be no type-specific limitation.'), ); @@ -271,7 +257,7 @@ function skinr_rule_edit($form, &$form_state, $rid = NULL) { $form['visibility']['role']['roles'] = array( '#type' => 'checkboxes', '#title' => t('Show block for specific roles'), - '#default_value' => $rule['roles'], + '#default_value' => $rule->roles, '#options' => $role_options, '#description' => t('Show this rule only for the selected role(s). If you select no roles, the rule will be visible to all users.'), ); @@ -281,13 +267,11 @@ function skinr_rule_edit($form, &$form_state, $rid = NULL) { '#type' => 'submit', '#value' => t('Save rule'), ); - if (isset($rule['rid'])) { - $form['actions']['delete'] = array( - '#type' => 'submit', - '#value' => t('Delete'), - '#submit' => array('skinr_rule_delete_submit'), - ); - } + $form['actions']['delete'] = array( + '#type' => 'submit', + '#value' => t('Delete'), + '#submit' => array('skinr_rule_delete_submit'), + ); return $form; } @@ -336,13 +320,12 @@ function skinr_rule_delete_submit($form, &$form_state) { * * @ingroup forms */ -function skinr_rule_delete_confirm($form, &$form_state, $rid) { +function skinr_rule_delete_confirm($form, &$form_state, $rule) { $form['rid'] = array( '#type' => 'value', - '#value' => $rid, + '#value' => $rule->rid, ); - $rule = skinr_rule_load($rid); return confirm_form($form, t('Are you sure you want to delete %title?', array('%title' => $rule->title)), isset($_GET['destination']) ? $_GET['destination'] : 'admin/appearance/skinr/rules', diff --git a/tests/skinr.test b/tests/skinr.test index 47d211a..66ae632 100644 --- a/tests/skinr.test +++ b/tests/skinr.test @@ -167,10 +167,10 @@ class SkinrApiTestCase extends SkinrWebTestCase { /** * Tests skinr_implements(). */ - public function testSkinrImplements() { + public function testSkinrImplementsAPI() { // Verify that skinr_implements() only returns extensions that are // compatible with this version of Skinr. - $extensions = skinr_implements(); + $extensions = skinr_implements_api(); // The expected extensions and their specific properties, if any. $all_expected = array( @@ -287,6 +287,51 @@ class SkinrApiTestCase extends SkinrWebTestCase { } /** + * Test module_implements() caching. + */ + function testSkinrImplements() { + // Test clearing cache. + cache_clear_all('skinr_implements', 'cache_bootstrap'); + $this->assertFalse(cache_get('skinr_implements', 'cache_bootstrap'), t('The skinr implements cache is empty.')); + $this->drupalGet(''); + $this->assertTrue(cache_get('skinr_implements', 'cache_bootstrap'), t('The skinr implements cache is populated after requesting a page.')); + + // Test clearing cache with an authenticated user. + $this->user = $this->drupalCreateUser(array()); + $this->drupalLogin($this->user); + cache_clear_all('skinr_implements', 'cache_bootstrap'); + $this->drupalGet(''); + $this->assertTrue(cache_get('skinr_implements', 'cache_bootstrap'), t('The skinr implements cache is populated after requesting a page.')); + + // Make sure {$module}.skinr.inc files (both in the module root, which are + // auto-loaded by drupal, and in custom paths and themes, which are + // loaded by skinr_implements()) are loaded when the hook is called. Also + // ensure only module that implement the current Skinr API are loaded. + $modules = skinr_implements('skinr_skin_info'); + + // Ensure the hook is found in includes. + $this->assertTrue(in_array('skinr_test', $modules), 'Hook found in {$module}.skinr.inc file auto-loaded by module_hook().'); + $this->assertTrue(in_array('skinr_test_subtheme', $modules), 'Hook found in {$module}.skinr.inc file in custom path.'); + + // Ensure that skinr_test_incompatible is not included. + $this->assertTrue(!in_array('skinr_test_incompatible', $modules), 'Hook in incompatible module not found.'); + } + + /** + * Test that module_invoke_all() can load a hook defined in hook_hook_info(). + */ + function testSkinrInvokeAll() { + // Ensure functions from {$module}.skinr.inc in both module root and in + // custom paths are triggered. + $config_info = skinr_invoke_all('skinr_config_info'); + $this->assertTrue(in_array('rules', $config_info), 'Function triggered in {$module}.skinr.inc file auto-loaded by module_hook().'); + $this->assertTrue(in_array('node', $config_info), 'Function triggered in {$module}.skinr.inc file in custom path.'); + + // Ensure that skinr_test_incompatible is not included. + $this->assertTrue(!in_array('skinr_test_incompatible', $config_info), 'Function in incompatible module not triggered.'); + } + + /** * Tests hook_skinr_skin_info(). */ public function testSkinrSkinInfo() { @@ -391,15 +436,24 @@ class SkinrApiTestCase extends SkinrWebTestCase { $config = skinr_get_config_info(); // Skinr's own implementation in skinr.skinr.inc should always be found. - $this->assertTrue(isset($config['rules']), 'hook_skinr_config_info() in $module.skinr.inc found.'); - unset($config['rules']); + $this->assertTrue(in_array('rules', $config), 'hook_skinr_config_info() in $module.skinr.inc found.'); + foreach ($config as $key => $type) { + if ($type == 'rules') { + unset($config[$key]); + } + } // Skinr's implementation on behalf of Node module in modules/node.skinr.inc // should be found. - $this->assertTrue(isset($config['node']), 'hook_skinr_config_info() in a custom path found.'); - unset($config['node']); + $this->assertTrue(in_array('node', $config), 'hook_skinr_config_info() in a custom path found.'); + foreach ($config as $key => $type) { + if ($type == 'node') { + unset($config[$key]); + } + } - // Ensure that skinr_test_incompatible is not contained. + // Ensure that skinr_test_incompatible is not included. + $this->verbose(highlight_string('assertTrue(!isset($config['skinr_test_incompatible']), 'Incompatible hook_skinr_config_info() not found.'); // After asserting all expected, the list of skins should be empty. $this->assertTrue(empty($config), 'No unexpected skins found.'); diff --git a/tests/skinr_test_incompatible/skinr_test_incompatible.module b/tests/skinr_test_incompatible/skinr_test_incompatible.module index 9c46b13..743b26f 100644 --- a/tests/skinr_test_incompatible/skinr_test_incompatible.module +++ b/tests/skinr_test_incompatible/skinr_test_incompatible.module @@ -30,8 +30,5 @@ function skinr_test_incompatible_skinr_skin_info() { * Implements hook_skinr_config_info(). */ function skinr_test_incompatible_skinr_config_info() { - $config['skinr_test_incompatible']['preprocess']['html'] = array( - 'index_handler' => 'rules_skinr_preprocess_index_handler', - ); - return $config; + return array('skinr_test_incompatible'); }