commit b0eaef0f3e3b99cc0fee72461a22b25bb9091135 Author: fago Date: Wed Jul 31 20:44:10 2013 +0200 SVG and icon font. diff --git a/modules/data.rules.inc b/modules/data.rules.inc index e78420b..412586f 100644 --- a/modules/data.rules.inc +++ b/modules/data.rules.inc @@ -8,6 +8,19 @@ */ /** + * Implements hook_rules_category_info() on behalf of the pseudo data module. + */ +function rules_data_category_info() { + return array( + 'rules_data' => array( + 'label' => t('Data'), + 'equals group' => t('Data'), + 'weight' => -50, + ), + ); +} + +/** * Implements hook_rules_file_info() on behalf of the pseudo data module. * @see rules_core_modules() */ diff --git a/modules/entity.rules.inc b/modules/entity.rules.inc index 76ec4ee..64776ae 100644 --- a/modules/entity.rules.inc +++ b/modules/entity.rules.inc @@ -16,6 +16,19 @@ function rules_entity_file_info() { } /** + * Implements hook_rules_category_info() on behalf of the pseudo entity module. + */ +function rules_entity_category_info() { + return array( + 'rules_entity' => array( + 'label' => t('Entities'), + 'equals group' => t('Entities'), + 'weight' => -50, + ), + ); +} + +/** * Implements hook_rules_action_info() on behalf of the entity module. * @see rules_core_modules() */ diff --git a/modules/node.eval.inc b/modules/node.eval.inc index 39922b0..50940a7 100644 --- a/modules/node.eval.inc +++ b/modules/node.eval.inc @@ -18,7 +18,7 @@ abstract class RulesNodeConditionBase extends RulesConditionHandlerBase { 'parameter' => array( 'node' => array('type' => 'node', 'label' => t('Content')), ), - 'group' => t('Node'), + 'category' => 'node', 'access callback' => 'rules_node_integration_access', ); } diff --git a/modules/node.rules.inc b/modules/node.rules.inc index a126931..2629840 100644 --- a/modules/node.rules.inc +++ b/modules/node.rules.inc @@ -8,6 +8,18 @@ */ /** + * Implements hook_rules_category_info() on behalf of the node module. + */ +function rules_node_category_info() { + return array( + 'node' => array( + 'label' => t('Node'), + 'equals group' => t('Node'), + ), + ); +} + +/** * Implements hook_rules_file_info() on behalf of the node module. */ function rules_node_file_info() { @@ -21,28 +33,28 @@ function rules_node_event_info() { $items = array( 'node_insert' => array( 'label' => t('After saving new content'), - 'group' => t('Node'), + 'category' => 'node', 'variables' => rules_events_node_variables(t('created content')), 'access callback' => 'rules_node_integration_access', 'class' => 'RulesNodeEventHandler', ), 'node_update' => array( 'label' => t('After updating existing content'), - 'group' => t('Node'), + 'category' => 'node', 'variables' => rules_events_node_variables(t('updated content'), TRUE), 'access callback' => 'rules_node_integration_access', 'class' => 'RulesNodeEventHandler', ), 'node_presave' => array( 'label' => t('Before saving content'), - 'group' => t('Node'), + 'category' => 'node', 'variables' => rules_events_node_variables(t('saved content'), TRUE), 'access callback' => 'rules_node_integration_access', 'class' => 'RulesNodeEventHandler', ), 'node_view' => array( 'label' => t('Content is viewed'), - 'group' => t('Node'), + 'category' => 'node', 'help' => t("Note that if drupal's page cache is enabled, this event won't be generated for pages served from cache."), 'variables' => rules_events_node_variables(t('viewed content')) + array( 'view_mode' => array( @@ -58,7 +70,7 @@ function rules_node_event_info() { ), 'node_delete' => array( 'label' => t('After deleting content'), - 'group' => t('Node'), + 'category' => 'node', 'variables' => rules_events_node_variables(t('deleted content')), 'access callback' => 'rules_node_integration_access', 'class' => 'RulesNodeEventHandler', @@ -96,7 +108,7 @@ function rules_node_action_info() { 'parameter' => array( 'node' => array('type' => 'node', 'label' => t('Content'), 'save' => TRUE), ), - 'group' => t('Node'), + 'category' => 'node', 'access callback' => 'rules_node_admin_access', ); // Add support for hand-picked core actions. diff --git a/modules/rules_core.rules.inc b/modules/rules_core.rules.inc index 4b8889b..39fff93 100644 --- a/modules/rules_core.rules.inc +++ b/modules/rules_core.rules.inc @@ -9,6 +9,19 @@ */ /** + * Implements hook_rules_category_info() on behalf of the rules_core. + */ +function rules_rules_core_category_info() { + return array( + 'rules_components' => array( + 'label' => t('Components'), + 'equals group' => t('Components'), + 'weight' => 50, + ), + ); +} + +/** * Implements hook_rules_file_info() on behalf of the pseudo rules_core module. * * @see rules_core_modules() diff --git a/rules.api.php b/rules.api.php index 0ac6b94..b4c121f 100644 --- a/rules.api.php +++ b/rules.api.php @@ -156,6 +156,58 @@ function hook_rules_action_info() { } /** + * Define categories for Rules items, e.g. actions, conditions or events. + * + * Categories are similar to the previously used 'group' key in e.g. + * hook_rules_action_info(), but have a machine name and some more optional + * keys like a weight, or an icon. + * + * For best compatibility, modules may keep using the 'group' key for referring + * to categories. However, if a 'group' key and a 'category' is given the group + * will be treated as grouping in the given category (e.g. group "paypal" in + * category "commerce payment"). + * + * @return + * An array of information about the module's provided categories. + * The array contains a sub-array for each category, with the category name as + * the key. Names may only contain lowercase alpha-numeric characters + * and underscores and should be prefixed with the providing module name. + * Possible attributes for each sub-array are: + * - label: The label of the category. Start capitalized. Required. + * - weight: (optional) A weight for sorting the category. Defaults to 0. + * - equals group: (optional) For BC, categories may be defined that equal + * a previsouly used 'group'. + * - icon: (optional) The relative file path of a category item to use. + * The icon should be a transparent SVG containing no colors (only #fff). + * See XXX for instructions on how to create a suiting icon. + * Note that the icon is currently not used by Rules, however other UIs + * building upon Rules (like fluxkraft) may do, and future releases of Rules + * might do as well. If no icon and icon font class is given, an icon is + * auto-generated. If both an icon font and icon is given, the icon is + * preferred. + * - icon font class: (optional) An icon font class referring to a suiting + * icon. Icon font class names should map to the ones as defined by Font + * Awesome, while themes might want to choose to provide another icon font. + * See http://fortawesome.github.io/Font-Awesome/cheatsheet/. + * - icon font background color: (optional) The color used as icon background. + * Should have a high contrast to white. + */ +function hook_rules_category_info() { + return array( + 'rules_data' => array( + 'label' => t('Data'), + 'equals group' => t('Data'), + 'weight' => -50, + ), + 'fluxtwitter' => array( + 'label' => t('Twitter'), + 'icon font class' => 'icon-twitter', + 'icon font background color' => '#30a9fd', + ), + ); +} + +/** * Specify files containing rules integration code. * * All files specified in that hook will be included when rules looks for diff --git a/rules.rules.inc b/rules.rules.inc index 120773d..fcd3c94 100644 --- a/rules.rules.inc +++ b/rules.rules.inc @@ -59,6 +59,13 @@ function rules_rules_file_info() { } /** + * Implements hook_rules_category_info(). + */ +function rules_rules_category_info() { + return _rules_rules_collect_items('category_info'); +} + +/** * Implements hook_rules_action_info(). */ function rules_rules_action_info() { diff --git a/ui/ui.core.inc b/ui/ui.core.inc index 8b47b0b..a51c6af 100644 --- a/ui/ui.core.inc +++ b/ui/ui.core.inc @@ -842,47 +842,10 @@ class RulesPluginUI extends FacesExtender implements RulesPluginUIInterface { } /** - * Returns an array of options to use with a select for the items specified - * in the given hook. - * - * @param $item_type - * The item type to get options for. One of 'data', 'event', 'condition' and - * 'action'. - * @param $items - * (optional) An array of items to restrict the options to. - * - * @return - * An array of options. + * @see RulesUICategory::getOptions() */ public static function getOptions($item_type, $items = NULL) { - $sorted_data = array(); - $ungrouped = array(); - $data = $items ? $items : rules_fetch_data($item_type . '_info'); - foreach ($data as $name => $info) { - // Verfiy the current user has access to use it. - if (!user_access('bypass rules access') && !empty($info['access callback']) && !call_user_func($info['access callback'], $item_type, $name)) { - continue; - } - if (!empty($info['group'])) { - $sorted_data[drupal_ucfirst($info['group'])][$name] = drupal_ucfirst($info['label']); - } - else { - $ungrouped[$name] = drupal_ucfirst($info['label']); - } - } - asort($ungrouped); - foreach ($sorted_data as $key => $choices) { - asort($choices); - $sorted_data[$key] = $choices; - } - ksort($sorted_data); - // Always move the 'Components' group down it it exists. - if (isset($sorted_data[t('Components')])) { - $copy = $sorted_data[t('Components')]; - unset($sorted_data[t('Components')]); - $sorted_data[t('Components')] = $copy; - } - return $ungrouped + $sorted_data; + return RulesUICategory::getOptions($item_type, $items = NULL); } public static function formDefaults(&$form, &$form_state) { @@ -1176,3 +1139,137 @@ class RulesActionContainerUI extends RulesContainerPluginUI { $form['elements']['#caption'] = t('Actions'); } } + +/** + * Class holding category related methods. + */ +class RulesUICategory { + + /** + * Gets info about all available categories, or about a specific category. + * + * @return array + */ + public static function getInfo($category = NULL) { + $data = rules_fetch_data('category_info'); + if (isset($category)) { + return $data[$category]; + } + return $data; + } + + /** + * Returns a group label, e.g. as usable for opt-groups in a select list. + * + * @param array $item_info + * The info-array of an item, e.g. an entry of hook_rules_action_info(). + * @param bool $in_category + * (optional) Whether group labels for grouping inside a category should be + * return. Defaults to FALSE. + * + * @return string|boolean + * The group label to use, or FALSE if none can be found. + */ + public static function getItemGroup($item_info, $in_category = FALSE) { + if (isset($item_info['category']) && !$in_category) { + return self::getCategory($item_info, 'label'); + } + else if (!empty($item_info['group'])) { + return $item_info['group']; + } + return FALSE; + } + + /** + * Gets the category for the given item info array. + * + * @param array $item_info + * The info-array of an item, e.g. an entry of hook_rules_action_info(). + * @param string|null $key + * (optional) The key of the category info to return, e.g. 'label'. If none + * is given the whole info array is returned. + * + * @return array|mixed|false + * Either the whole category info array or the value of the given key. If + * no category can be found, FALSE is returned. + */ + public static function getCategory($item_info, $key = NULL) { + if (isset($item_info['category'])) { + $info = self::getInfo($item_info['category']); + return isset($key) ? $info[$key] : $info; + } + return FALSE; + } + + /** + * Returns an array of options to use with a select for the items specified + * in the given hook. + * + * @param $item_type + * The item type to get options for. One of 'data', 'event', 'condition' and + * 'action'. + * @param $items + * (optional) An array of items to restrict the options to. + * + * @return + * An array of options. + */ + public static function getOptions($item_type, $items = NULL) { + $sorted_data = array(); + $ungrouped = array(); + $data = $items ? $items : rules_fetch_data($item_type . '_info'); + foreach ($data as $name => $info) { + // Verfiy the current user has access to use it. + if (!user_access('bypass rules access') && !empty($info['access callback']) && !call_user_func($info['access callback'], $item_type, $name)) { + continue; + } + if ($group = RulesUICategory::getItemGroup($info)) { + $sorted_data[drupal_ucfirst($group)][$name] = drupal_ucfirst($info['label']); + } + else { + $ungrouped[$name] = drupal_ucfirst($info['label']); + } + } + asort($ungrouped); + foreach ($sorted_data as $key => $choices) { + asort($choices); + $sorted_data[$key] = $choices; + } + + // Sort the grouped data by category weights, defaulting to weight 0 for + // groups without a respective category. + $sorted_groups = array(); + foreach (array_keys($sorted_data) as $label) { + $sorted_groups[$label] = array('weight' => 0, 'label' => $label); + } + // Add in category weights. + foreach (RulesUICategory::getInfo() as $info) { + if (isset($sorted_groups[$info['label']])) { + $sorted_groups[$info['label']] = $info; + } + } + uasort($sorted_groups, '_rules_ui_sort_categories'); + + // Now replace weights with group content. + foreach ($sorted_groups as $group => $weight) { + $sorted_groups[$group] = $sorted_data[$group]; + } + return $ungrouped + $sorted_groups; + } +} + +/** + * Helper for sorting categories. + */ +function _rules_ui_sort_categories($a, $b) { + // @see element_sort() + $a_weight = isset($a['weight']) ? $a['weight'] : 0; + $b_weight = isset($b['weight']) ? $b['weight'] : 0; + if ($a_weight == $b_weight) { + // @see element_sort_by_title() + $a_title = isset($a['label']) ? $a['label'] : ''; + $b_title = isset($b['label']) ? $b['label'] : ''; + return strnatcasecmp($a_title, $b_title); + } + return ($a_weight < $b_weight) ? -1 : 1; +}