diff options
author | Ctibor Brančík <ctibor@brancik.cz> | 2016-03-20 19:27:01 +0100 |
---|---|---|
committer | Ctibor Brančík <ctibor@brancik.cz> | 2016-03-20 19:27:01 +0100 |
commit | 29a6913890a675ddf1a9239b4407f105e02dc95d (patch) | |
tree | dd9ba21b73e9e704952b49d5153616a9dfa9b98f /sites/all/modules/ctools/plugins | |
parent | 5ddacae6306ce071d4f7e4d438960d6d3a4c6bd8 (diff) | |
download | brdo-29a6913890a675ddf1a9239b4407f105e02dc95d.tar.gz brdo-29a6913890a675ddf1a9239b4407f105e02dc95d.tar.bz2 |
Added drupal modules for site
Diffstat (limited to 'sites/all/modules/ctools/plugins')
158 files changed, 13234 insertions, 0 deletions
diff --git a/sites/all/modules/ctools/plugins/access/book.inc b/sites/all/modules/ctools/plugins/access/book.inc new file mode 100644 index 000000000..4b4f7eaae --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/book.inc @@ -0,0 +1,94 @@ +<?php + +/** + * @file + * Plugin to provide access control based on whether a node belongs to a book. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +if (module_exists('book')) { + $plugin = array( + 'title' => t("Book: node is in a book"), + 'description' => t('Control access based upon a node belonging to a book.'), + 'callback' => 'ctools_book_node_ctools_access_check', + 'default' => array('book' => array()), + 'settings form' => 'ctools_book_node_ctools_access_settings', + 'settings form submit' => 'ctools_book_node_ctools_access_settings_submit', + 'summary' => 'ctools_book_node_ctools_access_summary', + 'required context' => new ctools_context_required(t('Node'), 'node'), + ); +} + +/** + * Settings form for the 'by book_node' access plugin. + */ +function ctools_book_node_ctools_access_settings($form, &$form_state, $conf) { + $options = array( + 'any' => t('In any book'), + ); + $books = book_get_books(); + foreach ($books as $bid => $book) { + $options[$bid] = $book['title']; + } + $form['settings']['book'] = array( + '#title' => t('Book'), + '#type' => 'checkboxes', + '#options' => $options, + '#description' => t('Pass only if the node belongs to one of the selected books'), + '#default_value' => $conf['book'], + '#required' => TRUE, + ); + return $form; +} + +/** + * Check for access. + */ +function ctools_book_node_ctools_access_check($conf, $context) { + // As far as I know there should always be a context at this point, but this + // is safe. + if (empty($context) || empty($context->data) || empty($context->data->book)) { + return FALSE; + } + + if ($conf['book']['any']) { + return !empty($context->data->book); + } + + foreach ($conf['book'] as $bid => $value) { + if ($bid == 'any') { + continue; + } + if ($value && ($bid == $context->data->book['bid'])) { + return TRUE; + } + } + + return FALSE; +} + +/** + * Provide a summary description based upon the checked node_languages. + */ +function ctools_book_node_ctools_access_summary($conf, $context) { + if ($conf['book']['any']) { + return t('@identifier belongs to a book', array('@identifier' => $context->identifier)); + } + + $books = array(); + foreach ($conf['book'] as $bid => $value) { + if ($value) { + $node = node_load($bid); + $books[] = $node->title; + } + } + + if (count($books) == 1) { + return t('@identifier belongs to the book "@book"', array('@book' => $books[0], '@identifier' => $context->identifier)); + } + + return t('@identifier belongs in multiple books', array('@identifier' => $context->identifier)); +} diff --git a/sites/all/modules/ctools/plugins/access/compare_users.inc b/sites/all/modules/ctools/plugins/access/compare_users.inc new file mode 100644 index 000000000..c271ff4e3 --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/compare_users.inc @@ -0,0 +1,70 @@ +<?php + +/** + * @file + * Ctools access plugin to provide access/visiblity if two user contexts are equal. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("User: compare"), + 'description' => t('Compare two users (logged-in user and user being viewed, for example)'), + 'callback' => 'ctools_compare_users_access_check', + 'default' => array( + 'equality' => 1, + ), + 'settings form' => 'ctools_compare_users_settings', + 'summary' => 'ctools_compare_users_ctools_access_summary', + 'required context' => array( + new ctools_context_required(t('First User'), 'user'), + new ctools_context_required(t("Second User"), 'user') + ), +); + +/** + * Settings form for the 'by perm' access plugin + */ +function ctools_compare_users_settings($form, &$form_state, $conf) { + + $form['settings']['helptext'] = array( + '#type' => 'markup', + '#value' => '<div>' . t('Grant access based on comparison of the two user contexts. For example, to grant access to a user to view their own profile, choose "logged in user" and "user being viewed" and say "grant access if equal". When they\'re the same, access will be granted.') . '</div>', + ); + + $form['settings']['equality'] = array( + '#type' => 'radios', + '#title' => t('Grant access if user contexts are'), + '#options' => array(1 => t('Equal'), 0 => t('Not equal')), + '#default_value' => $conf['equality'], + ); + return $form; +} + +/** + * Check for access. + */ +function ctools_compare_users_access_check($conf, $context) { + + if (empty($context) || count($context) != 2 || empty($context[0]->data) || empty($context[1]->data)) { + return FALSE; + } + $account1 = $context[0]->data; + $account2 = $context[1]->data; + + // xor returns false if the two bools are the same, and true if they are not. + // i.e, if we asked for equality and they are equal, return true. + // If we asked for inequality and they are equal, return false. + return ($account1->uid == $account2->uid) xor empty($conf['equality']); +} + +/** + * Describe an instance of this plugin. + */ +function ctools_compare_users_ctools_access_summary($conf, $context) { + $comparison = !empty($conf['equality']) ? "is" : 'is not'; + + return t('@id1 @comp @id2', array('@comp' => $comparison, '@id1' => $context[0]->identifier, '@id2' => $context[1]->identifier)); +} diff --git a/sites/all/modules/ctools/plugins/access/context_exists.inc b/sites/all/modules/ctools/plugins/access/context_exists.inc new file mode 100644 index 000000000..aabc62dd9 --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/context_exists.inc @@ -0,0 +1,51 @@ +<?php + +/** + * @file + * Plugin to provide access control/visibility based on existence of a specified context + */ + +$plugin = array( + 'title' => t("Context exists"), + 'description' => t('Control access by whether or not a context exists and contains data.'), + 'callback' => 'ctools_context_exists_ctools_access_check', + 'settings form' => 'ctools_context_exists_ctools_access_settings', + 'summary' => 'ctools_context_exists_ctools_access_summary', + 'required context' => new ctools_context_required(t('Context'), 'any', TRUE), + 'defaults' => array('exists' => TRUE), +); + +/** + * Settings form + */ +function ctools_context_exists_ctools_access_settings($form, &$form_state, $conf) { + $form['settings']['exists'] = array( + '#type' => 'radios', + '#description' => t("Check to see if the context exists (contains data) or does not exist (contains no data). For example, if a context is optional and the path does not contain an argument for that context, it will not exist."), + '#options' => array(TRUE => t('Exists'), FALSE => t("Doesn't exist")), + '#default_value' => $conf['exists'], + ); + return $form; +} + +/** + * Check for access + */ +function ctools_context_exists_ctools_access_check($conf, $context) { + // xor returns false if the two bools are the same, and true if they are not. + // i.e, if we asked for context_exists and it does, return true. + // If we asked for context does not exist and it does, return false. + return (empty($context->data) xor !empty($conf['exists'])); +} + +/** + * Provide a summary description based upon the specified context + */ +function ctools_context_exists_ctools_access_summary($conf, $context) { + if (!empty($conf['exists'])) { + return t('@identifier exists', array('@identifier' => $context->identifier)); + } + else { + return t('@identifier does not exist', array('@identifier' => $context->identifier)); + } +} diff --git a/sites/all/modules/ctools/plugins/access/entity_bundle.inc b/sites/all/modules/ctools/plugins/access/entity_bundle.inc new file mode 100644 index 000000000..e07a048de --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/entity_bundle.inc @@ -0,0 +1,136 @@ +<?php + +/** + * @file + * Plugin to provide access control based upon entity bundle. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Entity: bundle"), + 'description' => t('Control access by entity bundle.'), + 'callback' => 'ctools_entity_bundle_ctools_access_check', + 'default' => array('type' => array()), + 'settings form' => 'ctools_entity_bundle_ctools_access_settings', + 'settings form submit' => 'ctools_entity_bundle_ctools_access_settings_submit', + 'summary' => 'ctools_entity_bundle_ctools_access_summary', + 'restrictions' => 'ctools_entity_bundle_ctools_access_restrictions', + 'get child' => 'ctools_entity_bundle_ctools_access_get_child', + 'get children' => 'ctools_entity_bundle_ctools_access_get_children', +); + +function ctools_entity_bundle_ctools_access_get_child($plugin, $parent, $child) { + $plugins = ctools_entity_bundle_ctools_access_get_children($plugin, $parent); + return $plugins[$parent . ':' . $child]; +} + +function ctools_entity_bundle_ctools_access_get_children($plugin, $parent) { + $entities = entity_get_info(); + $plugins = array(); + foreach ($entities as $entity_type => $entity) { + $plugin['title'] = t('@entity: Bundle', array('@entity' => $entity['label'])); + $plugin['keyword'] = $entity_type; + $plugin['description'] = t('Control access by @entity entity bundle.', array('@entity' => $entity_type)); + $plugin['name'] = $parent . ':' . $entity_type; + $plugin['required context'] = new ctools_context_required(t(ucfirst($entity_type)), $entity_type); + $plugins[$parent . ':' . $entity_type] = $plugin; + } + + return $plugins; +} + +/** + * Settings form for the 'by entity_bundle' access plugin + */ +function ctools_entity_bundle_ctools_access_settings($form, &$form_state, $conf) { + $plugin = $form_state['plugin']; + $entity_type = explode(':', $plugin['name']); + $entity_type = $entity_type[1]; + $entity = entity_get_info($entity_type); + foreach ($entity['bundles'] as $type => $info) { + $options[$type] = check_plain($info['label']); + } + + $form['settings']['type'] = array( + '#title' => t('Entity Bundle'), + '#type' => 'checkboxes', + '#options' => $options, + '#description' => t('Only the checked entity bundles will be valid.'), + '#default_value' => $conf['type'], + ); + return $form; +} + +/** + * Compress the entity bundles allowed to the minimum. + */ +function ctools_entity_bundle_ctools_access_settings_submit($form, &$form_state) { + $form_state['values']['settings']['type'] = array_filter($form_state['values']['settings']['type']); +} + +/** + * Check for access. + */ +function ctools_entity_bundle_ctools_access_check($conf, $context, $plugin) { + list($plugin_name, $entity_type) = explode(':', $plugin['name']); + if (!$entity_type) { + return FALSE; + }; + + $entity = entity_get_info($entity_type); + // As far as I know there should always be a context at this point, but this + // is safe. + if (empty($context) || empty($context->data) || empty($context->data->{$entity['entity keys']['bundle']})) { + return FALSE; + } + + if (array_filter($conf['type']) && empty($conf['type'][$context->data->{$entity['entity keys']['bundle']}])) { + return FALSE; + } + + return TRUE; +} + +/** + * Inform the UI that we've eliminated a bunch of possibilities for this + * context. + */ +function ctools_entity_bundle_ctools_access_restrictions($conf, &$context) { + if (isset($context->restrictions['type'])) { + $context->restrictions['type'] = array_unique(array_merge($context->restrictions['type'], array_keys(array_filter($conf['type'])))); + } + else { + $context->restrictions['type'] = array_keys(array_filter($conf['type'])); + } +} + +/** + * Provide a summary description based upon the checked entity_bundle. + */ +function ctools_entity_bundle_ctools_access_summary($conf, $context, $plugin) { + if (!isset($conf['type'])) { + $conf['type'] = array(); + } + + list($plugin_name, $entity_type) = explode(':', $plugin['name']); + if (!$entity_type) { + return t('Error, misconfigured entity_bundle access plugin'); + }; + + $entity = entity_get_info($entity_type); + + $names = array(); + foreach (array_filter($conf['type']) as $type) { + $names[] = check_plain($entity['bundles'][$type]['label']); + } + + if (empty($names)) { + return t('@identifier is any bundle', array('@identifier' => $context->identifier)); + } + + return format_plural(count($names), '@identifier is bundle "@types"', '@identifier bundle is one of "@types"', array('@types' => implode(', ', $names), '@identifier' => $context->identifier)); +} + diff --git a/sites/all/modules/ctools/plugins/access/entity_field_value.inc b/sites/all/modules/ctools/plugins/access/entity_field_value.inc new file mode 100644 index 000000000..fa94a4818 --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/entity_field_value.inc @@ -0,0 +1,410 @@ +<?php + +/** + * @file + * Plugin to provide access control based upon entity bundle. + */ + +$plugin = array( + 'title' => t("(Custom) Entity: Field Value"), + 'description' => t('Control access by entity field value.'), + 'callback' => 'ctools_entity_field_value_ctools_access_check', + 'default' => array('type' => array()), + 'settings form' => 'ctools_entity_field_value_ctools_access_settings', + 'settings form submit' => 'ctools_entity_field_value_ctools_access_settings_submit', + 'summary' => 'ctools_entity_field_value_ctools_access_summary', + 'get child' => 'ctools_entity_field_value_ctools_access_get_child', + 'get children' => 'ctools_entity_field_value_ctools_access_get_children', +); + +function ctools_entity_field_value_ctools_access_get_child($plugin, $parent, $child) { + $plugins = &drupal_static(__FUNCTION__, array()); + if (empty($plugins[$parent . ':' . $child])) { + list($entity_type, $bundle_type, $field_name) = explode(':', $child); + $plugins[$parent . ':' . $child] = _ctools_entity_field_value_ctools_access_get_child($plugin, $parent, $entity_type, $bundle_type, $field_name); + } + + return $plugins[$parent . ':' . $child]; +} + +function ctools_entity_field_value_ctools_access_get_children($plugin, $parent) { + $plugins = &drupal_static(__FUNCTION__, array()); + if (!empty($plugins)) { + return $plugins; + } + $entities = entity_get_info(); + foreach ($entities as $entity_type => $entity) { + foreach ($entity['bundles'] as $bundle_type => $bundle) { + foreach (field_info_instances($entity_type, $bundle_type) as $field_name => $field) { + if (!isset($plugins[$parent . ':' . $entity_type . ':' . $bundle_type . ':' . $field_name])) { + $plugin = _ctools_entity_field_value_ctools_access_get_child($plugin, $parent, $entity_type, $bundle_type, $field_name, $entity, $bundle, $field); + $plugins[$parent . ':' . $entity_type . ':' . $bundle_type . ':' . $field_name] = $plugin; + } + } + } + } + + return $plugins; +} + +function _ctools_entity_field_value_ctools_access_get_child($plugin, $parent, $entity_type, $bundle_type, $field_name, $entity = NULL, $bundle = NULL, $field = NULL) { + // check that the entity, bundle and field arrays have a value. + // If not, load theme using machine names. + if (empty($entity)) { + $entity = entity_get_info($entity_type); + } + + if (empty($bundle)) { + $bundle = $entity['bundles'][$bundle_type]; + } + + if (empty($field)) { + $field_instances = field_info_instances($entity_type, $bundle_type); + $field = $field_instances[$field_name]; + } + + $plugin['title'] = t('@entity @type: @field Field', array('@entity' => $entity['label'], '@type' => $bundle_type, '@field' => $field['label'])); + $plugin['keyword'] = $entity_type; + $plugin['description'] = t('Control access by @entity entity bundle.', array('@entity' => $entity_type)); + $plugin['name'] = $parent . ':' . $entity_type . ':' . $bundle_type . ':' . $field_name; + $plugin['required context'] = new ctools_context_required(t(ucfirst($entity_type)), $entity_type, array( + 'type' => $bundle_type, + )); + + return $plugin; +} + +/** + * Settings form for the 'by entity_bundle' access plugin + */ +function ctools_entity_field_value_ctools_access_settings($form, &$form_state, $conf) { + $plugin = $form_state['plugin']; + list($parent, $entity_type, $bundle_type, $field_name) = explode(':', $plugin['name']); + $entity_info = entity_get_info($entity_type); + $instances = field_info_instances($entity_type, $bundle_type); + $instance = $instances[$field_name]; + $field = field_info_field_by_id($instance['field_id']); + foreach ($field['columns'] as $column => $attributes) { + $columns[$column] = _field_sql_storage_columnname($field_name, $column); + } + ctools_include('fields'); + $entity = (object)array( + $entity_info['entity keys']['bundle'] => $bundle_type, + ); + + foreach ($columns as $column => $sql_column) { + if (isset($conf[$sql_column])) { + if (is_array($conf[$sql_column])) { + foreach ($conf[$sql_column] as $delta => $conf_value) { + if (is_numeric($delta)) { + if (is_array($conf_value)) { + $entity->{$field_name}[LANGUAGE_NONE][$delta][$column] = $conf_value[$column]; + } + else { + $entity->{$field_name}[LANGUAGE_NONE][$delta][$column] = $conf_value; + } + } + } + } + else { + $entity->{$field_name}[LANGUAGE_NONE][0][$column] = $conf[$sql_column]; + } + } + } + + $form['#parents'] = array('settings'); + $langcode = field_valid_language(NULL); + $form['settings'] += (array) ctools_field_invoke_field($instance, 'form', $entity_type, $entity, $form, $form_state, array('default' => TRUE, 'language' => $langcode)); + // weight is really not important once this is populated and will only interfere with the form layout. + foreach (element_children($form['settings']) as $element) { + unset($form['settings'][$element]['#weight']); + } + + return $form; +} + +function ctools_entity_field_value_ctools_access_settings_submit($form, &$form_state) { + $plugin = $form_state['plugin']; + list($parent, $entity_type, $bundle_type, $field_name) = explode(':', $plugin['name']); + $langcode = field_valid_language(NULL); + $langcode = isset($form_state['input']['settings'][$field_name][$langcode]) ? $langcode : LANGUAGE_NONE; + $instances = field_info_instances($entity_type, $bundle_type); + $instance = $instances[$field_name]; + $field = field_info_field_by_id($instance['field_id']); + foreach ($field['columns'] as $column => $attributes) { + $columns[$column] = _field_sql_storage_columnname($field_name, $column); + } + $items = _ctools_entity_field_value_get_proper_form_items($field, $form_state['values']['settings'][$field_name][$langcode], array_keys($columns)); + foreach ($columns as $column => $sql_column) { + $column_items = _ctools_entity_field_value_filter_items_by_column($items, $column); + $form_state['values']['settings'][$sql_column] = $column_items; + } + $form_state['values']['settings'][$field_name][$langcode] = $items; +} + +function _ctools_entity_field_value_get_proper_form_items($field, $form_items, $columns) { + $items = array(); + + if (!is_array($form_items)) { // Single value item. + foreach ($columns as $column) { + $items[0][$column] = $form_items; + } + return $items; + } + + foreach ($form_items as $delta => $value) { + $item = array(); + if (is_numeric($delta)) { // Array of field values. + if (!is_array($value)) { // Single value in array. + foreach ($columns as $column) { + $item[$column] = $value; + } + } + else { // Value has colums. + foreach ($columns as $column) { + $item[$column] = isset($value[$column]) ? $value[$column] : ''; + } + } + } + $items[] = $item; + } + + // Check if $form_items is an array of columns. + $item = array(); + $has_columns = FALSE; + foreach ($columns as $column) { + if (isset($form_items[$column])) { + $has_columns = TRUE; + $item[$column] = $form_items[$column]; + } + else { + $item[$column] = ''; + } + } + if ($has_columns) { + $items[] = $item; + } + + // Remove empty values. + $items = _field_filter_items($field, $items); + return $items; +} + +function _ctools_entity_field_value_filter_items_by_column($items, $column) { + $column_items = array(); + foreach ($items as $delta => $values) { + $column_items[$delta] = isset($values[$column]) ? $values[$column] : ''; + } + return $column_items; +} + +/** + * Check for access. + */ +function ctools_entity_field_value_ctools_access_check($conf, $context, $plugin) { + if ((!is_object($context)) || (empty($context->data))) { + // If the context doesn't exist -- for example, a newly added entity + // reference is used as a pane visibility criteria -- we deny access. + return FALSE; + } + + list($parent, $entity_type, $bundle_type, $field_name) = explode(':', $plugin['name']); + + if ($field_items = field_get_items($entity_type, $context->data, $field_name)) { + $langcode = field_language($entity_type, $context->data, $field_name); + // Get field storage columns. + $instance = field_info_instance($entity_type, $field_name, $bundle_type); + $field = field_info_field_by_id($instance['field_id']); + $columns = array(); + foreach ($field['columns'] as $column => $attributes) { + $columns[$column] = _field_sql_storage_columnname($field_name, $column); + } + + if (isset($conf[$field_name])) { + // We have settings for this field. + $conf_value_array = _ctools_entity_field_value_ctools_access_get_conf_field_values($conf[$field_name], $langcode); + if (empty($conf_value_array)) { + return FALSE; + } + + // Check field value. + foreach ($field_items as $field_value) { + // Iterate through config values. + foreach ($conf_value_array as $conf_value) { + $match = FALSE; + foreach ($field_value as $field_column => $value) { + // Check access only for stored in config column values. + if (isset($conf_value[$field_column])) { + if ($value == $conf_value[$field_column]) { + $match = TRUE; + } + else { + $match = FALSE; + break; + } + } + } + if ($match) { + return TRUE; + } + } + } + return FALSE; + } + } + + return FALSE; +} + +function _ctools_entity_field_value_ctools_access_get_conf_field_values($values, $langcode = LANGUAGE_NONE) { + if (!is_array($values) || !isset($values[$langcode])) { + return NULL; + } + $conf_values = array(); + + foreach ($values[$langcode] as $delta => $value) { + $conf_values[$delta] = $value; + } + + return $conf_values; +} + +/** + * Provide a summary description based upon the checked entity_bundle. + */ +function ctools_entity_field_value_ctools_access_summary($conf, $context, $plugin) { + list($parent, $entity_type, $bundle_type, $field_name) = explode(':', $plugin['name']); + $instances = field_info_instances($entity_type, $bundle_type); + $instance = $instances[$field_name]; + $field = field_info_field_by_id($instance['field_id']); + $entity_info = entity_get_info($entity_type); + $entity = (object)array( + $entity_info['entity keys']['bundle'] => $bundle_type, + ); + $keys = array(); + $value_keys = array(); + $keyed_elements = array(); + foreach ($field['columns'] as $column => $attributes) { + $conf_key = _field_sql_storage_columnname($field_name, $column); + $keyed_elements["@{$column}_value"] = array(); + + if (isset($conf[$conf_key])) { + if (is_array($conf[$conf_key])) { + $i = 0; + foreach ($conf[$conf_key] as $conf_value) { + if (!is_array($conf_value)) { + $entity->{$field_name}[LANGUAGE_NONE][$i][$column] = $conf_value; + $keyed_elements["@{$column}_value"][$i] = array('#markup' => $conf_value); + } + elseif (isset($conf_value[$column])) { + $entity->{$field_name}[LANGUAGE_NONE][$i][$column] = $conf_value[$column]; + $keyed_elements["@{$column}_value"][$i] = array('#markup' => $conf_value[$column]); + } + $i++; + } + } + else { + $entity->{$field_name}[LANGUAGE_NONE][0][$column] = $conf[$conf_key]; + $keyed_elements["@{$column}_value"][0] = array('#markup' => $conf[$conf_key]); + } + } + + $keys['@' . $column] = $column; + $value_keys[] = "@{$column}_value"; + } + $elements = array(); + $items = isset($entity->{$field_name}[LANGUAGE_NONE]) ? $entity->{$field_name}[LANGUAGE_NONE] : array(); + $view_mode = 'full'; + ctools_include('fields'); + $display = field_get_display($instance, $view_mode, $entity); + if (!isset($display['module'])) { + $display['module'] = $field['module']; + } + if (isset($display['module'])) { + // Choose simple formatter for well known cases. + switch ($display['module']) { + case 'text': + $display['type'] = 'text_default'; + break; + + case 'list': + $display['type'] = 'list_default'; + if ($field['type'] == 'list_boolean') { + $allowed_values = list_allowed_values($field, $instance, $entity_type, $entity); + foreach ($items as $item) { + if (isset($allowed_values[$item['value']])) { + if ($allowed_values[$item['value']] == '') { + $display['type'] = 'list_key'; + break; + } + } + else { + $display['type'] = 'list_key'; + } + } + } + break; + + case 'taxonomy': + $display['type'] = 'taxonomy_term_reference_plain'; + break; + + case 'entityreference': + $display['type'] = 'entityreference_label'; + break; + + default : + // Use field instance formatter setting. + break; + } + + $function = $display['module'] . '_field_formatter_view'; + if (function_exists($function)) { + $entity_group = array(0 => $entity); + $item_group = array(0 => $items); + $instance_group = array(0 => $instance); + field_default_prepare_view($entity_type, $entity_group, $field, $instance_group, LANGUAGE_NONE, $item_group, $display); + $elements = $function($entity_type, $entity, $field, $instance, LANGUAGE_NONE, $item_group[0], $display); + } + } + if (count($elements) > 0) { + foreach ($field['columns'] as $column => $attributes) { + if (count($field['columns']) == 1) { + $keyed_elements["@{$column}_value"] = $elements; + } + } + } + $values = array(); + foreach ($value_keys as $key) { + $output = array(); + $elements = $keyed_elements[$key]; + if (is_array($elements)) { + foreach ($elements as $element_key => $element) { + if (is_numeric($element_key)) { + $value_str= strip_tags(drupal_render($element)); + if (strlen($value_str) > 0) { + $output[] = $value_str; + } + } + } + } + else { + $value_str = strip_tags(drupal_render($elements)); + if (strlen($value_str) > 0) { + $output[] = $value_str; + } + } + $value = implode(', ', $output); + if ($value !== '') { + $values[$key] = implode(', ', $output); + } + } + $string = ''; + $value_count = count($values); + foreach ($keys as $key_name => $column) { + if (isset($values[$key_name . '_value'])) { + $string .= ($value_count > 1) ? " @{$column} = @{$column}_value" : "@{$column}_value"; + } + } + return t('@field is set to "!value"', array('@field' => $instance['label'], '!value' => format_string($string, array_merge($keys, $values)))); +} diff --git a/sites/all/modules/ctools/plugins/access/front.inc b/sites/all/modules/ctools/plugins/access/front.inc new file mode 100644 index 000000000..1bbc6e057 --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/front.inc @@ -0,0 +1,46 @@ +<?php + +/** + * @file + * Plugin to provide access control based on drupal_is_front_page. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Front page'), + 'description' => t('Is this the front page.'), + 'callback' => 'ctools_front_ctools_access_check', + 'default' => array('negate' => 0), + 'settings form' => 'ctools_front_ctools_access_settings', + 'summary' => 'ctools_front_ctools_access_summary', +); + +/** + * Settings form for the 'by parent term' access plugin + */ +function ctools_front_ctools_access_settings($form, &$form_state, $conf) { + // No additional configuration necessary. + return $form; +} + +/** + * Check for access. + */ +function ctools_front_ctools_access_check($conf, $context) { + if (drupal_is_front_page()) { + return TRUE; + } + else { + return FALSE; + } +} + +/** + * Provide a summary description based upon the checked terms. + */ +function ctools_front_ctools_access_summary($conf, $context) { + return t('The front page'); +} diff --git a/sites/all/modules/ctools/plugins/access/node.inc b/sites/all/modules/ctools/plugins/access/node.inc new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/node.inc diff --git a/sites/all/modules/ctools/plugins/access/node_access.inc b/sites/all/modules/ctools/plugins/access/node_access.inc new file mode 100644 index 000000000..fcd275d94 --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/node_access.inc @@ -0,0 +1,89 @@ +<?php + +/** + * @file + * Plugin to provide access control based upon node type. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Node: accessible"), + 'description' => t('Control access with built in Drupal node access test.'), + 'callback' => 'ctools_node_access_ctools_access_check', + 'default' => array('type' => 'view'), + 'settings form' => 'ctools_node_access_ctools_access_settings', + 'settings form submit' => 'ctools_node_access_ctools_access_settings_submit', + 'summary' => 'ctools_node_access_ctools_access_summary', + 'required context' => array( + new ctools_context_required(t('User'), 'user'), + new ctools_context_required(t('Node'), 'node'), + ), +); + +/** + * Settings form for the 'by node_access' access plugin + */ +function ctools_node_access_ctools_access_settings($form, &$form_state, $conf) { + $form['settings']['type'] = array( + '#title' => t('Operation'), + '#type' => 'radios', + '#options' => array( + 'view' => t('View'), + 'update' => t('Update'), + 'delete' => t('Delete'), + 'create' => t('Create nodes of the same type'), + ), + '#description' => t('Using built in Drupal node access rules, determine if the user can perform the selected operation on the node.'), + '#default_value' => $conf['type'], + ); + return $form; +} + +/** + * Check for access. + */ +function ctools_node_access_ctools_access_check($conf, $context) { + // As far as I know there should always be a context at this point, but this + // is safe. + list($user_context, $node_context) = $context; + if (empty($node_context) || empty($node_context->data) || empty($node_context->data->type)) { + return FALSE; + } + + if (empty($user_context) || empty($user_context->data)) { + return FALSE; + } + + if ($conf['type'] == 'create') { + return node_access('create', $node_context->data->type, $user_context->data); + } + else { + return node_access($conf['type'], $node_context->data, $user_context->data); + } +} + +/** + * Provide a summary description based upon the checked node_accesss. + */ +function ctools_node_access_ctools_access_summary($conf, $context) { + list($user_context, $node_context) = $context; + $replacement = array('@user' => $user_context->identifier, '@node' => $node_context->identifier); + + switch ($conf['type']) { + case 'view': + return t('@user can view @node.', $replacement); + + case 'update': + return t('@user can edit @node.', $replacement); + + case 'delete': + return t('@user can delete @node.', $replacement); + + case 'create': + return t('@user can create nodes of the same type as @node.', $replacement); + } +} + diff --git a/sites/all/modules/ctools/plugins/access/node_comment.inc b/sites/all/modules/ctools/plugins/access/node_comment.inc new file mode 100644 index 000000000..915ee20e2 --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/node_comment.inc @@ -0,0 +1,31 @@ +<?php +/** + * @file + * Plugin to provide access control based upon node comment status. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Node: comments are open"), + 'description' => t('Control access by the nodes comment status.'), + 'callback' => 'ctools_node_comment_ctools_access_check', + 'summary' => 'ctools_node_comment_ctools_access_summary', + 'required context' => new ctools_context_required(t('Node'), 'node'), +); + +/** + * Checks for access. + */ +function ctools_node_comment_ctools_access_check($conf, $context) { + return (!empty($context->data) && $context->data->comment == 2); +} + +/** + * Provides a summary description based upon the checked node_status. + */ +function ctools_node_comment_ctools_access_summary($conf, $context) { + return t('Returns true if the nodes comment status is "open".'); +} diff --git a/sites/all/modules/ctools/plugins/access/node_language.inc b/sites/all/modules/ctools/plugins/access/node_language.inc new file mode 100644 index 000000000..0fdcfc66a --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/node_language.inc @@ -0,0 +1,114 @@ +<?php + +/** + * @file + * Plugin to provide access control based upon node type. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +if (module_exists('locale')) { + $plugin = array( + 'title' => t("Node: language"), + 'description' => t('Control access by node language.'), + 'callback' => 'ctools_node_language_ctools_access_check', + 'default' => array('language' => array()), + 'settings form' => 'ctools_node_language_ctools_access_settings', + 'settings form submit' => 'ctools_node_language_ctools_access_settings_submit', + 'summary' => 'ctools_node_language_ctools_access_summary', + 'required context' => new ctools_context_required(t('Node'), 'node'), + ); +} + +/** + * Settings form for the 'by node_language' access plugin + */ +function ctools_node_language_ctools_access_settings($form, &$form_state, $conf) { + $options = array( + 'current' => t('Current site language'), + 'default' => t('Default site language'), + 'no_language' => t('No language'), + ); + $options = array_merge($options, locale_language_list()); + $form['settings']['language'] = array( + '#title' => t('Language'), + '#type' => 'checkboxes', + '#options' => $options, + '#description' => t('Pass only if the node is in one of the selected languages.'), + '#default_value' => $conf['language'], + ); + return $form; +} + +/** + * Check for access. + */ +function ctools_node_language_ctools_access_check($conf, $context) { + // As far as I know there should always be a context at this point, but this + // is safe. + if (empty($context) || empty($context->data) || !isset($context->data->language)) { + return FALSE; + } + + global $language; + + // Specialcase: if 'no language' is checked, return TRUE if the language field is + // empty. + if (!empty($conf['language']['no_language'])) { + if (empty($context->data->language)) { + return TRUE; + } + } + + // Specialcase: if 'current' is checked, return TRUE if the current site language + // matches the node language. + if (!empty($conf['language']['current'])) { + if ($context->data->language == $language->language) { + return TRUE; + } + } + + // Specialcase: If 'default' is checked, return TRUE if the default site language + // matches the node language. + if (!empty($conf['language']['default'])) { + if ($context->data->language == language_default('language')) { + return TRUE; + } + } + + if (array_filter($conf['language']) && empty($conf['language'][$context->data->language])) { + return FALSE; + } + + return TRUE; +} + +/** + * Provide a summary description based upon the checked node_languages. + */ +function ctools_node_language_ctools_access_summary($conf, $context) { + $languages = array( + 'current' => t('Current site language'), + 'default' => t('Default site language'), + 'no_language' => t('No language'), + ); + $languages = array_merge($languages, locale_language_list()); + + if (!isset($conf['language'])) { + $conf['language'] = array(); + } + + $names = array(); + foreach (array_filter($conf['language']) as $language) { + $names[] = $languages[$language]; + } + + if (empty($names)) { + return t('@identifier is in any language', array('@identifier' => $context->identifier)); + } + + return format_plural(count($names), '@identifier language is "@languages"', '@identifier language is one of "@languages"', array('@languages' => implode(', ', $names), '@identifier' => $context->identifier)); +} + diff --git a/sites/all/modules/ctools/plugins/access/node_status.inc b/sites/all/modules/ctools/plugins/access/node_status.inc new file mode 100644 index 000000000..ad5ba4009 --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/node_status.inc @@ -0,0 +1,33 @@ +<?php + +/** + * @file + * Plugin to provide access control based upon node (un)published status. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Node: (un)published"), + 'description' => t('Control access by the nodes published status.'), + 'callback' => 'ctools_node_status_ctools_access_check', + 'summary' => 'ctools_node_status_ctools_access_summary', + 'required context' => new ctools_context_required(t('Node'), 'node'), +); + +/** + * Check for access. + */ +function ctools_node_status_ctools_access_check($conf, $context) { + return (!empty($context->data) && $context->data->status); +} + +/** + * Provide a summary description based upon the checked node_statuss. + */ +function ctools_node_status_ctools_access_summary($conf, $context) { + return t('Returns true if the nodes status is "published".'); +} + diff --git a/sites/all/modules/ctools/plugins/access/node_type.inc b/sites/all/modules/ctools/plugins/access/node_type.inc new file mode 100644 index 000000000..23a38453a --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/node_type.inc @@ -0,0 +1,117 @@ +<?php + +/** + * @file + * Plugin to provide access control based upon node type. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Node: type"), + 'description' => t('Control access by node_type.'), + 'callback' => 'ctools_node_type_ctools_access_check', + 'default' => array('type' => array()), + 'settings form' => 'ctools_node_type_ctools_access_settings', + 'settings form submit' => 'ctools_node_type_ctools_access_settings_submit', + 'summary' => 'ctools_node_type_ctools_access_summary', + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'restrictions' => 'ctools_node_type_ctools_access_restrictions', +); + +/** + * Settings form for the 'by node_type' access plugin + */ +function ctools_node_type_ctools_access_settings($form, &$form_state, $conf) { + $types = node_type_get_types(); + foreach ($types as $type => $info) { + $options[$type] = check_plain($info->name); + } + + $form['settings']['type'] = array( + '#title' => t('Node type'), + '#type' => 'checkboxes', + '#options' => $options, + '#description' => t('Only the checked node types will be valid.'), + '#default_value' => $conf['type'], + ); + return $form; +} + +/** + * Compress the node_types allowed to the minimum. + */ +function ctools_node_type_ctools_access_settings_submit($form, &$form_state) { + $form_state['values']['settings']['type'] = array_filter($form_state['values']['settings']['type']); +} + +/** + * Check for access. + */ +function ctools_node_type_ctools_access_check($conf, $context) { + // As far as I know there should always be a context at this point, but this + // is safe. + if (empty($context) || empty($context->data) || empty($context->data->type)) { + return FALSE; + } + + if (array_filter($conf['type']) && empty($conf['type'][$context->data->type])) { + return FALSE; + } + + return TRUE; +} + +/** + * Inform the UI that we've eliminated a bunch of possibilities for this + * context. + */ +function ctools_node_type_ctools_access_restrictions($conf, &$context) { + if (isset($context->restrictions['type'])) { + $context->restrictions['type'] = array_unique(array_merge($context->restrictions['type'], array_keys(array_filter($conf['type'])))); + } + else { + $context->restrictions['type'] = array_keys(array_filter($conf['type'])); + } +} + +/** + * Provide a summary description based upon the checked node_types. + */ +function ctools_node_type_ctools_access_summary($conf, $context) { + if (!isset($conf['type'])) { + $conf['type'] = array(); + } + $types = node_type_get_types(); + + $names = array(); + // If a node type doesn't exist, let the user know, but prevent a notice. + $missing_types = array(); + + foreach (array_filter($conf['type']) as $type) { + if (!empty($types[$type])) { + $names[] = check_plain($types[$type]->name); + } + else { + $missing_types[] = check_plain($type); + } + } + + if (empty($names) && empty($missing_types)) { + return t('@identifier is any node type', array('@identifier' => $context->identifier)); + } + + if (!empty($missing_types)) { + $output = array(); + if (!empty($names)) { + $output[] = format_plural(count($names), '@identifier is type "@types"', '@identifier type is one of "@types"', array('@types' => implode(', ', $names), '@identifier' => $context->identifier)); + } + $output[] = format_plural(count($missing_types), 'Missing/ deleted type "@types"', 'Missing/ deleted type is one of "@types"', array('@types' => implode(', ', $missing_types))); + return implode(' | ', $output); + } + + return format_plural(count($names), '@identifier is type "@types"', '@identifier type is one of "@types"', array('@types' => implode(', ', $names), '@identifier' => $context->identifier)); +} + diff --git a/sites/all/modules/ctools/plugins/access/path_visibility.inc b/sites/all/modules/ctools/plugins/access/path_visibility.inc new file mode 100644 index 000000000..60b86124e --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/path_visibility.inc @@ -0,0 +1,88 @@ +<?php + +/** + * @file + * Plugin to provide access control/visibility based on path. + */ + +$plugin = array( + 'title' => t('String: URL path'), + 'description' => t('Control access by the current path.'), + 'callback' => 'ctools_path_visibility_ctools_access_check', + 'settings form' => 'ctools_path_visibility_ctools_access_settings', + 'summary' => 'ctools_path_visibility_ctools_access_summary', + 'required context' => new ctools_context_optional(t('Path'), 'string'), + 'default' => array('visibility_setting' => 1, 'paths' => ''), +); + +/** + * Settings form + */ +function ctools_path_visibility_ctools_access_settings($form, &$form_state, $conf) { + $form['settings']['note'] = array( + '#value' => '<div class="description">' . t('Note: if no context is chosen, the current page path will be used.') . '</div>', + ); + + $form['settings']['visibility_setting'] = array( + '#type' => 'radios', + '#options' => array( + 1 => t('Allow access on the following pages'), + 0 => t('Allow access on all pages except the following pages'), + ), + '#default_value' => $conf['visibility_setting'], + ); + + $form['settings']['paths'] = array( + '#type' => 'textarea', + '#title' => t('Paths'), + '#default_value' => $conf['paths'], + '#description' => t("Enter one page per line as Drupal paths. The '*' character is a wildcard. Example paths are %blog for the blog page and %blog-wildcard for every personal blog. %front is the front page.", array('%blog' => 'blog', '%blog-wildcard' => 'blog/*', '%front' => '<front>')), + ); + return $form; +} + +/** + * Check for access. + */ +function ctools_path_visibility_ctools_access_check($conf, $context) { + if (isset($context->data)) { + $base_path = $context->data; + } + else { + $base_path = $_GET['q']; + } + + $path = drupal_get_path_alias($base_path); + $page_match = drupal_match_path($path, $conf['paths']); + + // If there's a path alias, we may still be at the un-aliased path + // so check that as well. + if (!isset($context->data) && $path != $base_path) { + $page_match = $page_match || drupal_match_path($base_path, $conf['paths']); + } + + // When $conf['visibility_setting'] has a value of 0, the block is displayed + // on all pages except those listed in $block->pages. When set to 1, it + // is displayed only on those pages listed in $block->pages. + $page_match = !($conf['visibility_setting'] xor $page_match); + + return $page_match; +} + +/** + * Provide a summary description. + */ +function ctools_path_visibility_ctools_access_summary($conf, $context) { + $paths = array(); + foreach (explode("\n", $conf['paths']) as $path) { + $paths[] = check_plain($path); + } + + $identifier = $context->type == 'any' ? t('Current path') : $context->identifier; + if ($conf['visibility_setting']) { + return format_plural(count($paths), '@identifier is "@paths"', '@identifier type is one of "@paths"', array('@paths' => implode(', ', $paths), '@identifier' => $identifier)); + } + else { + return format_plural(count($paths), '@identifier is not "@paths"', '@identifier type is not one of "@paths"', array('@paths' => implode(', ', $paths), '@identifier' => $identifier)); + } +} diff --git a/sites/all/modules/ctools/plugins/access/perm.inc b/sites/all/modules/ctools/plugins/access/perm.inc new file mode 100644 index 000000000..67516faf6 --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/perm.inc @@ -0,0 +1,73 @@ +<?php + +/** + * @file + * Plugin to provide access control based on user permission strings. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("User: permission"), + 'description' => t('Control access by permission string.'), + 'callback' => 'ctools_perm_ctools_access_check', + 'default' => array('perm' => 'access content'), + 'settings form' => 'ctools_perm_ctools_access_settings', + 'summary' => 'ctools_perm_ctools_access_summary', + 'required context' => new ctools_context_required(t('User'), 'user'), +); + +/** + * Settings form for the 'by perm' access plugin + */ +function ctools_perm_ctools_access_settings($form, &$form_state, $conf) { + $perms = array(); + // Get list of permissions + foreach (module_list(FALSE, FALSE, TRUE) as $module) { + // By keeping them keyed by module we can use optgroups with the + // 'select' type. + if ($permissions = module_invoke($module, 'permission')) { + foreach ($permissions as $id => $permission) { + $perms[$module][$id] = $permission['title']; + } + } + } + + $form['settings']['perm'] = array( + '#type' => 'select', + '#options' => $perms, + '#title' => t('Permission'), + '#default_value' => $conf['perm'], + '#description' => t('Only users with the selected permission flag will be able to access this.'), + ); + + return $form; +} + +/** + * Check for access. + */ +function ctools_perm_ctools_access_check($conf, $context) { + // As far as I know there should always be a context at this point, but this + // is safe. + if (empty($context) || empty($context->data)) { + return FALSE; + } + + return user_access($conf['perm'], $context->data); +} + +/** + * Provide a summary description based upon the checked roles. + */ +function ctools_perm_ctools_access_summary($conf, $context) { + if (!isset($conf['perm'])) { + return t('Error, unset permission'); + } + + $permissions = module_invoke_all('permission'); + return t('@identifier has "@perm"', array('@identifier' => $context->identifier, '@perm' => $permissions[$conf['perm']]['title'])); +} + diff --git a/sites/all/modules/ctools/plugins/access/php.inc b/sites/all/modules/ctools/plugins/access/php.inc new file mode 100644 index 000000000..35da86d9a --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/php.inc @@ -0,0 +1,64 @@ +<?php + +/** + * @file + * Plugin to provide access control based on evaluated PHP. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("PHP Code"), + 'description' => t('Control access through arbitrary PHP code.'), + 'callback' => 'ctools_php_ctools_access_check', + 'default' => array('description' => '', 'php' => ''), + 'settings form' => 'ctools_php_ctools_access_settings', + 'summary' => 'ctools_php_ctools_access_summary', + 'all contexts' => TRUE, +); + +/** + * Settings form for the 'by perm' access plugin + * + * @todo Need a way to provide a list of all available contexts to be used by + * the eval-ed PHP. + */ +function ctools_php_ctools_access_settings($form, &$form_state, $conf) { + $perms = array(); + + $form['settings']['description'] = array( + '#type' => 'textfield', + '#title' => t('Administrative desc'), + '#default_value' => $conf['description'], + '#description' => t('A description for this test for administrative purposes.'), + ); + $form['settings']['php'] = array( + '#type' => 'textarea', + '#title' => t('PHP Code'), + '#default_value' => $conf['php'], + '#description' => t('Access will be granted if the following PHP code returns <code>TRUE</code>. Do not include <?php ?>. Note that executing incorrect PHP-code can break your Drupal site. All contexts will be available in the <em>$contexts</em> variable.'), + ); + if (!user_access('use PHP for settings')) { + $form['settings']['php']['#disabled'] = TRUE; + $form['settings']['php']['#value'] = $conf['php']; + $form['settings']['php']['#description'] .= ' ' . t('You do not have sufficient permissions to edit PHP code.'); + } + return $form; +} + +/** + * Check for access. + */ +function ctools_php_ctools_access_check($__conf, $contexts) { + $access = eval($__conf['php']); + return $access; +} + +/** + * Provide a summary description based upon the checked roles. + */ +function ctools_php_ctools_access_summary($conf, $contexts) { + return !empty($conf['description']) ? check_plain($conf['description']) : t('No description'); +} diff --git a/sites/all/modules/ctools/plugins/access/role.inc b/sites/all/modules/ctools/plugins/access/role.inc new file mode 100644 index 000000000..b6332544f --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/role.inc @@ -0,0 +1,79 @@ +<?php + +/** + * @file + * Plugin to provide access control based upon role membership. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("User: role"), + 'description' => t('Control access by role.'), + 'callback' => 'ctools_role_ctools_access_check', + 'default' => array('rids' => array()), + 'settings form' => 'ctools_role_ctools_access_settings', + 'settings form submit' => 'ctools_role_ctools_access_settings_submit', + 'summary' => 'ctools_role_ctools_access_summary', + 'required context' => new ctools_context_required(t('User'), 'user'), +); + +/** + * Settings form for the 'by role' access plugin + */ +function ctools_role_ctools_access_settings($form, &$form_state, $conf) { + $form['settings']['rids'] = array( + '#type' => 'checkboxes', + '#title' => t('Role'), + '#default_value' => $conf['rids'], + '#options' => ctools_get_roles(), + '#description' => t('Only the checked roles will be granted access.'), + ); + return $form; +} + +/** + * Compress the roles allowed to the minimum. + */ +function ctools_role_ctools_access_settings_submit($form, &$form_state) { + $form_state['values']['settings']['rids'] = array_keys(array_filter($form_state['values']['settings']['rids'])); +} + +/** + * Check for access. + */ +function ctools_role_ctools_access_check($conf, $context) { + // As far as I know there should always be a context at this point, but this + // is safe. + if (empty($context) || empty($context->data) || !isset($context->data->roles)) { + return FALSE; + } + + $roles = array_keys($context->data->roles); + $roles[] = $context->data->uid ? DRUPAL_AUTHENTICATED_RID : DRUPAL_ANONYMOUS_RID; + return (bool) array_intersect($conf['rids'], $roles); +} + +/** + * Provide a summary description based upon the checked roles. + */ +function ctools_role_ctools_access_summary($conf, $context) { + if (!isset($conf['rids'])) { + $conf['rids'] = array(); + } + $roles = ctools_get_roles(); + + $names = array(); + foreach (array_filter($conf['rids']) as $rid) { + $names[] = check_plain($roles[$rid]); + } + + if (empty($names)) { + return t('@identifier can have any role', array('@identifier' => $context->identifier)); + } + + return format_plural(count($names), '@identifier has role "@roles"', '@identifier has one of "@roles"', array('@roles' => implode(', ', $names), '@identifier' => $context->identifier)); +} + diff --git a/sites/all/modules/ctools/plugins/access/site_language.inc b/sites/all/modules/ctools/plugins/access/site_language.inc new file mode 100644 index 000000000..9ff2f70c8 --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/site_language.inc @@ -0,0 +1,87 @@ +<?php + +/** + * @file + * Plugin to provide access control based upon node type. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +if (module_exists('locale')) { + $plugin = array( + 'title' => t("User: language"), + 'description' => t('Control access by the language the user or site currently uses.'), + 'callback' => 'ctools_site_language_ctools_access_check', + 'default' => array('language' => array()), + 'settings form' => 'ctools_site_language_ctools_access_settings', + 'settings form submit' => 'ctools_site_language_ctools_access_settings_submit', + 'summary' => 'ctools_site_language_ctools_access_summary', + ); +} + +/** + * Settings form for the 'by site_language' access plugin + */ +function ctools_site_language_ctools_access_settings($form, &$form_state, $conf) { + $options = array( + 'default' => t('Default site language'), + ); + $options = array_merge($options, locale_language_list()); + $form['settings']['language'] = array( + '#title' => t('Language'), + '#type' => 'checkboxes', + '#options' => $options, + '#description' => t('Pass only if the current site language is one of the selected languages.'), + '#default_value' => $conf['language'], + ); + return $form; +} + +/** + * Check for access. + */ +function ctools_site_language_ctools_access_check($conf, $context) { + global $language; + + // Specialcase: If 'default' is checked, return TRUE if the default site language + // matches the node language. + if (!empty($conf['language']['default'])) { + if ($language->language == language_default('language')) { + return TRUE; + } + } + + if (array_filter($conf['language']) && empty($conf['language'][$language->language])) { + return FALSE; + } + + return TRUE; +} + +/** + * Provide a summary description based upon the checked site_languages. + */ +function ctools_site_language_ctools_access_summary($conf, $context) { + $languages = array( + 'default' => t('Default site language'), + ); + $languages = array_merge($languages, locale_language_list()); + + if (!isset($conf['language'])) { + $conf['language'] = array(); + } + + $names = array(); + foreach (array_filter($conf['language']) as $language) { + $names[] = $languages[$language]; + } + + if (empty($names)) { + return t('Site language is any language'); + } + + return format_plural(count($names), 'Site language is "@languages"', 'Site language is one of "@languages"', array('@languages' => implode(', ', $names))); +} + diff --git a/sites/all/modules/ctools/plugins/access/string_equal.inc b/sites/all/modules/ctools/plugins/access/string_equal.inc new file mode 100644 index 000000000..ad1c88d82 --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/string_equal.inc @@ -0,0 +1,94 @@ +<?php + +/** + * @file + * Plugin to provide access control/visibility based on specified context string matching user-specified string + */ + +$plugin = array( + 'title' => t("String: comparison"), + 'description' => t('Control access by string match.'), + 'callback' => 'ctools_string_equal_ctools_access_check', + 'settings form' => 'ctools_string_equal_ctools_access_settings', + 'summary' => 'ctools_string_equal_ctools_access_summary', + 'required context' => new ctools_context_required(t('String'), 'string'), + 'defaults' => array('operator' => '=', 'value' => '', 'case' => FALSE), +); + +/** + * Settings form + */ +function ctools_string_equal_ctools_access_settings($form, &$form_state, $conf) { + $form['settings']['operator'] = array( + '#type' => 'radios', + '#title' => t('Operator'), + '#options' => array( + '=' => t('Equal'), + '!=' => t('Not equal'), + 'regex' => t('Regular expression'), + '!regex' => t('Not equal to regular expression'), + ), + '#default_value' => $conf['operator'], + '#description' => t('If using a regular expression, you should enclose the pattern in slashes like so: <em>/foo/</em>. If you need to compare against slashes you can use another character to enclose the pattern, such as @. See <a href="http://www.php.net/manual/en/reference.pcre.pattern.syntax.php">PHP regex documentation</a> for more.'), + ); + + $form['settings']['value'] = array( + '#type' => 'textfield', + '#title' => t('String'), + '#default_value' => $conf['value'], + ); + + $form['settings']['case'] = array( + '#type' => 'checkbox', + '#title' => t('Case sensitive'), + '#default_value' => $conf['case'], + ); + return $form; +} + +/** + * Check for access + */ +function ctools_string_equal_ctools_access_check($conf, $context) { + if (empty($context) || empty($context->data)) { + $string = ''; + } + else { + $string = $context->data; + } + + $value = $conf['value']; + if (empty($conf['case'])) { + $string = drupal_strtolower($string); + $value = drupal_strtolower($value); + } + + switch ($conf['operator']) { + case '=': + return $string === $value; + case '!=': + return $string !== $value; + case 'regex': + return preg_match($value, $string); + case '!regex': + return !preg_match($value, $string); + } +} + +/** + * Provide a summary description based upon the specified context + */ +function ctools_string_equal_ctools_access_summary($conf, $context) { + $values = array('@identifier' => $context->identifier, '@value' => $conf['value']); + switch ($conf['operator']) { + case '=': + return t('@identifier is "@value"', $values); + case '!=': + return t('@identifier is not "@value"', $values); + case 'regex': + return t('@identifier matches "@value"', $values); + case '!regex': + return t('@identifier does not match "@value"', $values); + } +} + diff --git a/sites/all/modules/ctools/plugins/access/string_length.inc b/sites/all/modules/ctools/plugins/access/string_length.inc new file mode 100644 index 000000000..91abf2276 --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/string_length.inc @@ -0,0 +1,80 @@ +<?php + +/** + * @file + * Plugin to provide access control/visibility based on length of + * a string context. + */ + +$plugin = array( + 'title' => t("String: length"), + 'description' => t('Control access by length of string context.'), + 'callback' => 'ctools_string_length_ctools_access_check', + 'settings form' => 'ctools_string_length_ctools_access_settings', + 'summary' => 'ctools_string_length_ctools_access_summary', + 'required context' => new ctools_context_required(t('String'), 'string'), + 'defaults' => array('operator' => '=', 'length' => 0), +); + +/** + * Settings form for the 'by role' access plugin. + */ +function ctools_string_length_ctools_access_settings($form, &$form_state, $conf) { + $form['settings']['operator'] = array( + '#type' => 'radios', + '#title' => t('Operator'), + '#options' => array( + '>' => t('Greater than'), + '>=' => t('Greater than or equal to'), + '=' => t('Equal to'), + '!=' => t('Not equal to'), + '<' => t('Less than'), + '<=' => t('Less than or equal to'), + ), + '#default_value' => $conf['operator'], + ); + $form['settings']['length'] = array( + '#type' => 'textfield', + '#title' => t('Length of string'), + '#size' => 3, + '#default_value' => $conf['length'], + '#description' => t('Access/visibility will be granted based on string context length.'), + ); + return $form; +} + +/** + * Check for access. + */ +function ctools_string_length_ctools_access_check($conf, $context) { + if (empty($context) || empty($context->data)) { + $length = 0; + } + else { + $length = drupal_strlen($context->data); + } + + switch ($conf['operator']) { + case '<': + return $length < $conf['length']; + case '<=': + return $length <= $conf['length']; + case '=': + return $length == $conf['length']; + case '!=': + return $length != $conf['length']; + case '>': + return $length > $conf['length']; + case '>=': + return $length >= $conf['length']; + } + // Invalid Operator sent, return FALSE. + return FALSE; +} + +/** + * Provide a summary description based upon the checked roles. + */ +function ctools_string_length_ctools_access_summary($conf, $context) { + return t('@identifier must be @comp @length characters', array('@identifier' => $context->identifier, '@comp' => $conf['operator'], '@length' => $conf['length'])); +} diff --git a/sites/all/modules/ctools/plugins/access/term.inc b/sites/all/modules/ctools/plugins/access/term.inc new file mode 100644 index 000000000..36e70de47 --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/term.inc @@ -0,0 +1,129 @@ +<?php + +/** + * @file + * Plugin to provide access control based upon specific terms. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Taxonomy: term"), + 'description' => t('Control access by a specific term.'), + 'callback' => 'ctools_term_ctools_access_check', + 'default' => array('vids' => array()), + 'settings form' => 'ctools_term_ctools_access_settings', + 'settings form validation' => 'ctools_term_ctools_access_settings_validate', + 'settings form submit' => 'ctools_term_ctools_access_settings_submit', + 'summary' => 'ctools_term_ctools_access_summary', + 'required context' => new ctools_context_required(t('Term'), array('taxonomy_term', 'terms')), +); + +/** + * Settings form for the 'by term' access plugin + */ +function ctools_term_ctools_access_settings($form, &$form_state, $conf) { + // If no configuration was saved before, set some defaults. + if (empty($conf)) { + $conf = array( + 'vid' => 0, + ); + } + if (!isset($conf['vid'])) { + $conf['vid'] = 0; + } + + $form['settings']['vid'] = array( + '#title' => t('Vocabulary'), + '#type' => 'select', + '#options' => array(), + '#description' => t('Select the vocabulary for this form.'), + '#id' => 'ctools-select-vid', + '#default_value' => $conf['vid'], + '#required' => TRUE, + ); + + ctools_include('dependent'); + $options = array(); + + // A note: Dependency works strangely on these forms as they have never been + // updated to a more modern system so they are not individual forms of their + // own like the content types. + + $form['settings']['#tree'] = TRUE; + + // Loop over each of the configured vocabularies. + foreach (taxonomy_get_vocabularies() as $vid => $vocabulary) { + $options[$vid] = $vocabulary->name; + $form['settings'][$vocabulary->vid] = array( + '#title' => t('Terms'), + '#description' => t('Select a term or terms from @vocabulary.', array('@vocabulary' => $vocabulary->name)), //. $description, + '#dependency' => array('ctools-select-vid' => array($vocabulary->vid)), + '#default_value' => !empty($conf[$vid]) ? $conf[$vid] : '', + '#multiple' => TRUE, + ); + + $terms = array(); + foreach (taxonomy_get_tree($vocabulary->vid) as $tid => $term) { + $terms[$term->tid] = str_repeat('-', $term->depth) . ($term->depth ? ' ' : '') . $term->name; + } + $form['settings'][$vocabulary->vid]['#type'] = 'select'; + $form['settings'][$vocabulary->vid]['#options'] = $terms; + unset($terms); + } + $form['settings']['vid']['#options'] = $options; + return $form; +} + +/** + * Check for access. + */ +function ctools_term_ctools_access_check($conf, $context) { + // As far as I know there should always be a context at this point, but this + // is safe. + if (empty($context) || empty($context->data) || empty($context->data->vid) || empty($context->data->tid)) { + return FALSE; + } + + // Get the $vid. + if (!isset($conf['vid'])) { + return FALSE; + } + $vid = $conf['vid']; + + // Get the terms. + if (!isset($conf[$vid])) { + return FALSE; + } + + $return = FALSE; + + $terms = array_filter($conf[$vid]); + // For multi-term if any terms coincide, let's call that good enough: + if (isset($context->tids)) { + return (bool) array_intersect($terms, $context->tids); + } + else { + return in_array($context->data->tid, $terms); + } +} + +/** + * Provide a summary description based upon the checked terms. + */ +function ctools_term_ctools_access_summary($conf, $context) { + $vid = $conf['vid']; + $terms = array(); + foreach ($conf[$vid] as $tid) { + $term = taxonomy_term_load($tid); + $terms[] = $term->name; + } + + return format_plural(count($terms), + '@term can be the term "@terms"', + '@term can be one of these terms: @terms', + array('@terms' => implode(', ', $terms), + '@term' => $context->identifier)); +} diff --git a/sites/all/modules/ctools/plugins/access/term_has_parent.inc b/sites/all/modules/ctools/plugins/access/term_has_parent.inc new file mode 100644 index 000000000..a079e92af --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/term_has_parent.inc @@ -0,0 +1,172 @@ +<?php +/** + * @file + * Plugin to provide access control based upon a parent term. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Taxonomy: term has parent(s)"), + 'description' => t('Control access if a term belongs to a specific parent term.'), + 'callback' => 'ctools_term_has_parent_ctools_access_check', + 'default' => array('vid' => array(), 'negate' => 0), + 'settings form' => 'ctools_term_has_parent_ctools_access_settings', + 'settings form submit' => 'ctools_term_has_parent_ctools_access_settings_submit', + 'summary' => 'ctools_term_has_parent_ctools_access_summary', + 'required context' => new ctools_context_required(t('Term'), array('taxonomy_term', 'terms')), +); + +/** + * Settings form for the 'by parent term' access plugin + */ +function ctools_term_has_parent_ctools_access_settings($form, &$form_state, $conf) { + // If no configuration was saved before, set some defaults. + if (empty($conf)) { + $conf = array( + 'vid' => 0, + ); + } + if (!isset($conf['vid'])) { + $conf['vid'] = 0; + } + + $form['settings']['vid'] = array( + '#title' => t('Vocabulary'), + '#type' => 'select', + '#options' => array(), + '#description' => t('Select the vocabulary for this form.'), + '#id' => 'ctools-select-vid', + '#default_value' => $conf['vid'], + '#required' => TRUE, + ); + + ctools_include('dependent'); + $options = array(); + + // A note: Dependency works strangely on these forms as they have never been + // updated to a more modern system so they are not individual forms of their + // own like the content types. + + $form['settings']['#tree'] = TRUE; + + // Loop over each of the configured vocabularies. + foreach (taxonomy_get_vocabularies() as $vid => $vocabulary) { + $options[$vid] = $vocabulary->name; + $form['settings']['vid_' . $vid] = array( + '#title' => t('Terms'), + '#description' => t('Select a term or terms from @vocabulary.', array('@vocabulary' => $vocabulary->name)), + '#dependency' => array('ctools-select-vid' => array($vocabulary->vid)), + '#default_value' => !empty($conf['vid_' . $vid]) ? $conf['vid_' . $vid] : '', + '#size' => 10, + '#multiple' => TRUE, + //@todo: Remove the following workaround when the following patch is in core. {@see:http://drupal.org/node/1117526} + '#name' => sprintf("settings[%u][]", $vid), + '#attributes' => array('multiple' => 'multiple'), + ); + + $terms = array(); + foreach (taxonomy_get_tree($vocabulary->vid) as $term) { + $terms[$term->tid] = str_repeat('-', $term->depth) . ($term->depth ? ' ' : '') . $term->name; + } + //$form['settings']['vid_' . $vid]['#type'] = 'select'; + $form['settings']['vid_' . $vid]['#type'] = 'checkboxes'; + $form['settings']['vid_' . $vid]['#options'] = $terms; + unset($terms); + } + $form['settings']['vid']['#options'] = $options; + $form['settings']['include_self'] = array( + '#title' => t('Include these term(s) as candidates?'), + '#description' => t('When this rule is evaluated, should the term(s) you select be included as candidates for access?'), + '#default_value' => !empty($conf['include_self']) ? $conf['include_self'] : FALSE, + '#type' => 'checkbox', + ); + return $form; +} + +/** + * Filters values to store less. + */ +function ctools_term_has_parent_ctools_access_settings_submit($form, &$form_state) { + foreach ($form_state['values']['settings'] as $key => $value) { + if (strpos($key, 'vid_') === 0) { + $form_state['values']['settings'][$key] = array_filter($form_state['values']['settings'][$key]); + } + } +} + +/** + * Check for access. + */ +function ctools_term_has_parent_ctools_access_check($conf, $context) { + // As far as I know there should always be a context at this point, but this + // is safe. + if (empty($context) || empty($context->data) || empty($context->data->vid) || empty($context->data->tid)) { + return FALSE; + } + + // Get the $vid. + if (!isset($conf['vid'])) { + return FALSE; + } + $vid = $conf['vid']; + + // we'll start looking up the hierarchy from our context term id. + $current_term = $context->data->tid; + + $term=''; + + // scan up the tree. + while (true) { + // select parent as term_parent to avoid PHP5 complications with the parent keyword + //@todo: Find a way to reduce the number of queries required for really deep hierarchies. + $term = db_query("SELECT parent AS term_parent, tid AS tid FROM {taxonomy_term_hierarchy} th WHERE th.tid = :tid", array(':tid'=>$current_term))->fetchObject(); + + // if no term is found, get out of the loop + if (!$term || empty($term->tid)) { + break; + } + + // check the term selected, if the user asked it to. + if (!empty($conf['include_self']) && isset($conf['vid_' . $vid][$term->tid])) { + return TRUE; + } + + // did we find the parent TID we were looking for? + if (isset($conf['vid_' . $vid][$term->tid])) { + // YES, we're done! + return TRUE; + } + // Nope, we didn't find it. + + // If this is the top of the hierarchy, stop scanning. + if ($term->term_parent==0) { + break; + } + + // update the parent, and keep scanning. + $current_term = $term->term_parent; + } + + return FALSE; +} + +/** + * Provide a summary description based upon the checked terms. + */ +function ctools_term_has_parent_ctools_access_summary($conf, $context) { + $vid = (int)$conf['vid']; + $terms = array(); + foreach ($conf['vid_' . $vid] as $tid) { + $term = taxonomy_term_load($tid); + $terms[] = $term->name; + } + + return format_plural(count($terms), + '@term can have the parent "@terms"', + '@term can have one of these parents: @terms', + array('@terms' => implode(', ', $terms), + '@term' => $context->identifier)); +} diff --git a/sites/all/modules/ctools/plugins/access/term_parent.inc b/sites/all/modules/ctools/plugins/access/term_parent.inc new file mode 100644 index 000000000..acbaf8720 --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/term_parent.inc @@ -0,0 +1,86 @@ +<?php + +/** + * @file + * Plugin to provide access control based upon a parent term. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Taxonomy: parent term"), + 'description' => t('Control access by existence of a parent term.'), + 'callback' => 'ctools_term_parent_ctools_access_check', + 'default' => array('vid' => array(), 'negate' => 0), + 'settings form' => 'ctools_term_parent_ctools_access_settings', + 'settings form validation' => 'ctools_term_parent_ctools_access_settings_validate', + 'settings form submit' => 'ctools_term_parent_ctools_access_settings_submit', + 'summary' => 'ctools_term_parent_ctools_access_summary', + 'required context' => new ctools_context_required(t('Term'), array('taxonomy_term', 'terms')), +); + +/** + * Settings form for the 'by parent term' access plugin + */ +function ctools_term_parent_ctools_access_settings($form, &$form_state, $conf) { + // If no configuration was saved before, set some defaults. + if (empty($conf)) { + $conf = array( + 'vid' => 0, + ); + } + if (!isset($conf['vid'])) { + $conf['vid'] = 0; + } + + $form['settings']['vid'] = array( + '#title' => t('Vocabulary'), + '#type' => 'select', + '#options' => array(), + '#description' => t('Select the vocabulary for this form. If there exists a parent term in that vocabulary, this access check will succeed.'), + '#id' => 'ctools-select-vid', + '#default_value' => $conf['vid'], + '#required' => TRUE, + ); + + $options = array(); + + // Loop over each of the configured vocabularies. + foreach (taxonomy_get_vocabularies() as $vid => $vocabulary) { + $options[$vid] = $vocabulary->name; + } + $form['settings']['vid']['#options'] = $options; + return $form; +} + +/** + * Check for access. + */ +function ctools_term_parent_ctools_access_check($conf, $context) { + // As far as I know there should always be a context at this point, but this + // is safe. + if (empty($context) || empty($context->data) || empty($context->data->vid) || empty($context->data->tid)) { + return FALSE; + } + + // Get the $vid. + if (!isset($conf['vid'])) { + return FALSE; + } + $vid = $conf['vid']; + + $count = db_query('SELECT COUNT(*) FROM {taxonomy_term_hierarchy} th INNER JOIN {taxonomy_term_data} td ON th.parent = td.tid WHERE th.tid = :tid AND td.vid = :vid', array(':tid' => $context->data->tid, ':vid' => $vid))->fetchField(); + + return $count ? TRUE : FALSE; +} + +/** + * Provide a summary description based upon the checked terms. + */ +function ctools_term_parent_ctools_access_summary($conf, $context) { + $vocab = taxonomy_vocabulary_load($conf['vid']); + + return t('"@term" has parent in vocabulary "@vocab"', array('@term' => $context->identifier, '@vocab' => $vocab->name)); +} diff --git a/sites/all/modules/ctools/plugins/access/term_vocabulary.inc b/sites/all/modules/ctools/plugins/access/term_vocabulary.inc new file mode 100644 index 000000000..b003138df --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/term_vocabulary.inc @@ -0,0 +1,127 @@ +<?php + +/** + * @file + * Plugin to provide access control based upon term vocabulary + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Taxonomy: vocabulary"), + 'description' => t('Control access by vocabulary.'), + 'callback' => 'ctools_term_vocabulary_ctools_access_check', + 'default' => array('vids' => array()), + 'settings form' => 'ctools_term_vocabulary_ctools_access_settings', + 'settings form submit' => 'ctools_term_vocabulary_ctools_access_settings_submit', + 'summary' => 'ctools_term_vocabulary_ctools_access_summary', + 'required context' => new ctools_context_required(t('Vocabulary'), array( + 'taxonomy_term', + 'terms', + 'taxonomy_vocabulary' + )), +); + +/** + * Settings form for the 'by term_vocabulary' access plugin + */ +function ctools_term_vocabulary_ctools_access_settings($form, &$form_state, $conf) { + $options = array(); + $vocabularies = taxonomy_get_vocabularies(); + foreach ($vocabularies as $voc) { + $options[$voc->machine_name] = check_plain($voc->name); + } + + _ctools_term_vocabulary_ctools_access_map_vids($conf); + + $form['settings']['machine_name'] = array( + '#type' => 'checkboxes', + '#title' => t('Vocabularies'), + '#options' => $options, + '#description' => t('Only the checked vocabularies will be valid.'), + '#default_value' => $conf['machine_name'], + ); + return $form; +} + +/** + * Compress the term_vocabularys allowed to the minimum. + */ +function ctools_term_vocabulary_ctools_access_settings_submit($form, &$form_state) { + $form_state['values']['settings']['machine_name'] = array_filter($form_state['values']['settings']['machine_name']); +} + +/** + * Check for access. + */ +function ctools_term_vocabulary_ctools_access_check($conf, $context) { + // As far as I know there should always be a context at this point, but this + // is safe. + if (empty($context) || empty($context->data) || empty($context->data->vocabulary_machine_name)) { + return FALSE; + } + + _ctools_term_vocabulary_ctools_access_map_vids($conf); + + if (array_filter($conf['machine_name']) && empty($conf['machine_name'][$context->data->vocabulary_machine_name])) { + return FALSE; + } + + return TRUE; +} + +/** + * Provide a summary description based upon the checked term_vocabularys. + */ +function ctools_term_vocabulary_ctools_access_summary($conf, $context) { + if (!isset($conf['type'])) { + $conf['type'] = array(); + } + $vocabularies = taxonomy_get_vocabularies(); + + _ctools_term_vocabulary_ctools_access_map_vids($conf); + + $names = array(); + if (!empty($conf['machine_name'])) { + foreach (array_filter($conf['machine_name']) as $machine_name) { + foreach ($vocabularies as $vocabulary) { + if ($vocabulary->machine_name === $machine_name) { + $names[] = check_plain($vocabulary->name); + continue; + } + } + } + } + + if (empty($names)) { + return t('@identifier is any vocabulary', array('@identifier' => $context->identifier)); + } + + return format_plural(count($names), '@identifier vocabulary is "@machine_names"', '@identifier vocabulary is one of "@machine_names"', array( + '@machine_names' => implode(', ', $names), + '@identifier' => $context->identifier + )); +} + +/** + * Helper function to map the vids from old features to the new machine_name. + * + * Add the machine_name key to $conf if the vids key exist. + * + * @param array $conf + * The configuration of this plugin. + */ +function _ctools_term_vocabulary_ctools_access_map_vids(&$conf) { + if (!empty($conf['vids'])) { + $conf['machine_name'] = array(); + $vocabularies = taxonomy_get_vocabularies(); + foreach ($conf['vids'] as $vid) { + $machine_name = $vocabularies[$vid]->machine_name; + $conf['machine_name'][$machine_name] = $vocabularies[$vid]->machine_name; + } + } +} + + diff --git a/sites/all/modules/ctools/plugins/access/theme.inc b/sites/all/modules/ctools/plugins/access/theme.inc new file mode 100644 index 000000000..4f4be6ded --- /dev/null +++ b/sites/all/modules/ctools/plugins/access/theme.inc @@ -0,0 +1,70 @@ +<?php + +/** + * @file + * Plugin to provide access control based on user themeission strings. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Current theme"), + 'description' => t('Control access by checking which theme is in use.'), + 'callback' => 'ctools_theme_ctools_access_check', + 'default' => array('theme' => variable_get('theme_default', 'garland')), + 'settings form' => 'ctools_theme_ctools_access_settings', + 'summary' => 'ctools_theme_ctools_access_summary', +); + +/** + * Settings form for the 'by theme' access plugin + */ +function ctools_theme_ctools_access_settings($form, &$form_state, $conf) { + $themes = array(); + foreach (list_themes() as $key => $theme) { + $themes[$key] = $theme->info['name']; + } + + $form['settings']['theme'] = array( + '#type' => 'select', + '#options' => $themes, + '#title' => t('Themes'), + '#default_value' => $conf['theme'], + '#description' => t('This will only be accessed if the current theme is the selected theme.'), + ); + return $form; +} + +/** + * Check for access. + */ +function ctools_theme_ctools_access_check($conf, $context) { + if (!empty($GLOBALS['theme'])) { + $theme = $GLOBALS['theme']; + } + else if (!empty($GLOBALS['custom_theme'])) { + $theme = $GLOBALS['custom_theme']; + } + else if (!empty($GLOBALS['user']->theme)) { + $theme = $GLOBALS['user']->theme; + } + else { + $theme = variable_get('theme_default', 'garland'); + } + + return $conf['theme'] == $theme; +} + +/** + * Provide a summary description based upon the checked roles. + */ +function ctools_theme_ctools_access_summary($conf, $context) { + if (!isset($conf['theme'])) { + return t('Error, unset theme'); + } + $themes = list_themes(); + + return t('Current theme is "@theme"', array('@theme' => $themes[$conf['theme']]->info['name'])); +} diff --git a/sites/all/modules/ctools/plugins/arguments/entity_id.inc b/sites/all/modules/ctools/plugins/arguments/entity_id.inc new file mode 100644 index 000000000..3063fefd2 --- /dev/null +++ b/sites/all/modules/ctools/plugins/arguments/entity_id.inc @@ -0,0 +1,147 @@ +<?php + +/** + * @file + * + * Plugin to provide an argument handler for all entity ids. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Entity: ID"), + 'description' => t('Creates an entity context from an entity ID argument.'), + 'context' => 'ctools_argument_entity_id_context', + 'get child' => 'ctools_argument_entity_id_get_child', + 'get children' => 'ctools_argument_entity_id_get_children', + 'default' => array( + 'entity_id' => '', + ), + 'placeholder form' => 'ctools_argument_entity_id_ctools_argument_placeholder', +); + +function ctools_argument_entity_id_get_child($plugin, $parent, $child) { + $plugins = ctools_argument_entity_id_get_children($plugin, $parent); + return $plugins[$parent . ':' . $child]; +} + +function ctools_argument_entity_id_get_children($original_plugin, $parent) { + $entities = entity_get_info(); + $plugins = array(); + foreach ($entities as $entity_type => $entity) { + $plugin = $original_plugin; + $plugin['title'] = t('@entity: ID', array('@entity' => $entity['label'])); + $plugin['keyword'] = $entity_type; + $plugin['description'] = t('Creates @entity context from an ID argument.', array('@entity' => $entity_type)); + $plugin['name'] = $parent . ':' . $entity_type; + $plugin_id = $parent . ':' . $entity_type; + drupal_alter('ctools_entity_context', $plugin, $entity, $plugin_id); + $plugins[$plugin_id] = $plugin; + } + drupal_alter('ctools_entity_contexts', $plugins); + + return $plugins; +} + +/** + * Discover if this argument gives us the entity we crave. + */ +function ctools_argument_entity_id_context($arg = NULL, $conf = NULL, $empty = FALSE) { + $entity_type = explode(':', $conf['name']); + $entity_type = $entity_type[1]; + // If unset it wants a generic, unfilled context. + if ($empty) { + return ctools_context_create_empty('entity:' . $entity_type); + } + + // We can accept either an entity object or a pure id. + if (is_object($arg)) { + return ctools_context_create('entity:' . $entity_type, $arg); + } + + // Trim spaces and other garbage. + $arg = trim($arg); + + if (!is_numeric($arg)) { + $preg_matches = array(); + $match = preg_match('/\[id: (\d+)\]/', $arg, $preg_matches); + if (!$match) { + $match = preg_match('/^id: (\d+)/', $arg, $preg_matches); + } + + if ($match) { + $id = $preg_matches[1]; + } + if (isset($id) && is_numeric($id)) { + return ctools_context_create('entity:' . $entity_type, $id); + } + return FALSE; + } + + $entities = entity_load($entity_type, array($arg)); + if (empty($entities)) { + return FALSE; + } + + return ctools_context_create('entity:' . $entity_type, reset($entities)); +} + +function ctools_argument_entity_id_settings_form(&$form, &$form_state, $conf) { + $plugin = &$form_state['plugin']; + + $form['settings']['entity'] = array( + '#title' => t('Enter the title or ID of a @entity entity', array('@entity' => $plugin['keyword'])), + '#type' => 'textfield', + '#maxlength' => 512, + '#autocomplete_path' => 'ctools/autocomplete/' . $plugin['keyword'], + '#weight' => -10, + ); + + if (!empty($conf['entity_id'])) { + $info = entity_load($plugin['keyword'], array($conf['entity_id'])); + $info = $info[$conf['entity_id']]; + if ($info) { + $entity = entity_get_info($plugin['keyword']); + $uri = entity_uri($plugin['keyword'], $info); + if (is_array($uri) && $entity['entity keys']['label']) { + $link = l(t("'%title' [%type id %id]", array('%title' => $info->{$entity['entity keys']['label']}, '%type' => $plugin['keyword'], '%id' => $conf['entity_id'])), $uri['path'], array('attributes' => array('target' => '_blank', 'title' => t('Open in new window')), 'html' => TRUE)); + } + elseif (is_array($uri)) { + $link = l(t("[%type id %id]", array('%type' => $plugin['keyword'], '%id' => $conf['entity_id'])), $uri['path'], array('attributes' => array('target' => '_blank', 'title' => t('Open in new window')), 'html' => TRUE)); + } + elseif ($entity['entity keys']['label']) { + $link = l(t("'%title' [%type id %id]", array('%title' => $info->{$entity['entity keys']['label']}, '%type' => $plugin['keyword'], '%id' => $conf['entity_id'])), file_create_url($uri), array('attributes' => array('target' => '_blank', 'title' => t('Open in new window')), 'html' => TRUE)); + } + else { + $link = t("[%type id %id]", array('%type' => $plugin['keyword'], '%id' => $conf['entity_id'])); + } + $form['settings']['entity']['#description'] = t('Currently set to !link', array('!link' => $link)); + } + } + + $form['settings']['entity_id'] = array( + '#type' => 'value', + '#value' => isset($conf['entity_id']) ? $conf['entity_id'] : '', + ); + + $form['settings']['entity_type'] = array( + '#type' => 'value', + '#value' => $plugin['keyword'], + ); + + return $form; +} + +function ctools_argument_entity_id_ctools_argument_placeholder($conf) { + $conf = array( + '#title' => t('Enter the title or ID of a @entity entity', array('@entity' => $conf['keyword'])), + '#type' => 'textfield', + '#maxlength' => 512, + '#autocomplete_path' => 'ctools/autocomplete/' . $conf['keyword'], + '#weight' => -10, + ); + + return $conf; +} diff --git a/sites/all/modules/ctools/plugins/arguments/nid.inc b/sites/all/modules/ctools/plugins/arguments/nid.inc new file mode 100644 index 000000000..9aaec0e1f --- /dev/null +++ b/sites/all/modules/ctools/plugins/arguments/nid.inc @@ -0,0 +1,50 @@ +<?php + +/** + * @file + * + * Plugin to provide an argument handler for a node id + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Node: ID"), + 'keyword' => 'node', + 'description' => t('Creates a node context from a node ID argument.'), + 'context' => 'ctools_argument_nid_context', + 'placeholder form' => array( + '#type' => 'textfield', + '#description' => t('Enter the node ID of a node for this argument'), + ), + 'no ui' => TRUE, +); + +/** + * Discover if this argument gives us the node we crave. + */ +function ctools_argument_nid_context($arg = NULL, $conf = NULL, $empty = FALSE) { + // If unset it wants a generic, unfilled context. + if ($empty) { + return ctools_context_create_empty('node'); + } + + // We can accept either a node object or a pure nid. + if (is_object($arg)) { + return ctools_context_create('node', $arg); + } + + if (!is_numeric($arg)) { + return FALSE; + } + + $node = node_load($arg); + if (!$node) { + return FALSE; + } + + return ctools_context_create('node', $node); +} + diff --git a/sites/all/modules/ctools/plugins/arguments/node_add.inc b/sites/all/modules/ctools/plugins/arguments/node_add.inc new file mode 100644 index 000000000..c811311b0 --- /dev/null +++ b/sites/all/modules/ctools/plugins/arguments/node_add.inc @@ -0,0 +1,32 @@ +<?php + +/** + * @file + * + * Plugin to provide an argument handler for a Node add form + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Node add form: node type"), + // keyword to use for %substitution + 'keyword' => 'node_type', + 'description' => t('Creates a node add form context from a node type argument.'), + 'context' => 'ctools_node_add_context', +); + +/** + * Discover if this argument gives us the node we crave. + */ +function ctools_node_add_context($arg = NULL, $conf = NULL, $empty = FALSE) { + // If unset it wants a generic, unfilled context. + if (!isset($arg)) { + return ctools_context_create_empty('node_add_form'); + } + + return ctools_context_create('node_add_form', $arg); +} + diff --git a/sites/all/modules/ctools/plugins/arguments/node_edit.inc b/sites/all/modules/ctools/plugins/arguments/node_edit.inc new file mode 100644 index 000000000..c7cdf29e8 --- /dev/null +++ b/sites/all/modules/ctools/plugins/arguments/node_edit.inc @@ -0,0 +1,51 @@ +<?php + +/** + * @file + * + * Plugin to provide an argument handler for a Node edit form + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Node edit form: node ID"), + // keyword to use for %substitution + 'keyword' => 'node', + 'description' => t('Creates a node edit form context from a node ID argument.'), + 'context' => 'ctools_node_edit_context', + 'placeholder form' => array( + '#type' => 'textfield', + '#description' => t('Enter the node ID of a node for this argument'), + ), +); + +/** + * Discover if this argument gives us the node we crave. + */ +function ctools_node_edit_context($arg = NULL, $conf = NULL, $empty = FALSE) { + // If unset it wants a generic, unfilled context. + if ($empty) { + return ctools_context_create_empty('node_edit_form'); + } + + // We can accept either a node object or a pure nid. + if (is_object($arg)) { + return ctools_context_create('node_edit_form', $arg); + } + + if (!is_numeric($arg)) { + return FALSE; + } + + $node = node_load($arg); + if (!$node) { + return NULL; + } + + // This will perform a node_access check, so we don't have to. + return ctools_context_create('node_edit_form', $node); +} + diff --git a/sites/all/modules/ctools/plugins/arguments/rid.inc b/sites/all/modules/ctools/plugins/arguments/rid.inc new file mode 100644 index 000000000..2661153b2 --- /dev/null +++ b/sites/all/modules/ctools/plugins/arguments/rid.inc @@ -0,0 +1,50 @@ +<?php + +/** + * @file + * + * Plugin to provide an argument handler for a node revision id + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Revision: ID"), + 'keyword' => 'revision', + 'description' => t('Creates a node context from a revision ID argument.'), + 'context' => 'ctools_argument_rid_context', + 'placeholder form' => array( + '#type' => 'textfield', + '#description' => t('Enter the revision ID of a node for this argument'), + ), +); + +/** + * Discover if this argument gives us the node we crave. + */ +function ctools_argument_rid_context($arg = NULL, $conf = NULL, $empty = FALSE) { + // If unset it wants a generic, unfilled context. + if ($empty) { + return ctools_context_create_empty('node'); + } + + // We can accept either a node object or a pure nid. + if (is_object($arg)) { + return ctools_context_create('node', $arg); + } + + if (!is_numeric($arg)) { + return FALSE; + } + + $nid = db_query('SELECT nid FROM {node_revision} WHERE vid = :vid', array(':vid' => $arg))->fetchField(); + $node = node_load($nid, $arg); + if (!$node) { + return FALSE; + } + + return ctools_context_create('node', $node); +} + diff --git a/sites/all/modules/ctools/plugins/arguments/string.inc b/sites/all/modules/ctools/plugins/arguments/string.inc new file mode 100644 index 000000000..ed4ffbb63 --- /dev/null +++ b/sites/all/modules/ctools/plugins/arguments/string.inc @@ -0,0 +1,64 @@ +<?php + +/** + * @file + * + * Plugin to provide an argument handler for a raw string + */ +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("String"), + // keyword to use for %substitution + 'keyword' => 'string', + 'description' => t('A string is a minimal context that simply holds a string that can be used for some other purpose.'), + 'settings form' => 'ctools_string_settings_form', + 'context' => 'ctools_string_context', + 'placeholder form' => array( + '#type' => 'textfield', + '#description' => t('Enter a value for this argument'), + ), + 'path placeholder' => 'ctools_string_path_placeholder', // This is in pagemanager. +); + +/** + * Discover if this argument gives us the term we crave. + */ +function ctools_string_context($arg = NULL, $conf = NULL, $empty = FALSE) { + // If unset it wants a generic, unfilled context. + if ($empty) { + return ctools_context_create_empty('string'); + } + + $context = ctools_context_create('string', $arg); + $context->original_argument = $arg; + + return $context; +} + +/** + * Settings form for the argument + */ +function ctools_string_settings_form(&$form, &$form_state, $conf) { + $form['settings']['use_tail'] = array( + '#title' => t('Get all arguments after this one'), + '#type' => 'checkbox', + '#default_value' => !empty($conf['use_tail']), + '#description' => t('If checked, this string will include all arguments. For example, if the path is "path/%" and the user visits "path/foo/bar", if this is not checked the string will be "foo". If it is checked the string will be "foo/bar".'), + ); +// return $form; +} + +/** + * Switch the placeholder based upon user settings. + */ +function ctools_string_path_placeholder($argument) { + if (empty($argument['settings']['use_tail'])) { + return '%pm_arg'; + } + else { + return '%pm_arg_tail'; + } +}
\ No newline at end of file diff --git a/sites/all/modules/ctools/plugins/arguments/term.inc b/sites/all/modules/ctools/plugins/arguments/term.inc new file mode 100644 index 000000000..868c8aa5e --- /dev/null +++ b/sites/all/modules/ctools/plugins/arguments/term.inc @@ -0,0 +1,163 @@ +<?php + +/** + * @file + * + * Plugin to provide an argument handler for a Taxonomy term + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Taxonomy term: ID"), + // keyword to use for %substitution + 'keyword' => 'term', + 'description' => t('Creates a single taxonomy term from a taxonomy ID or taxonomy term name.'), + 'context' => 'ctools_term_context', + 'default' => array('input_form' => 'tid', 'breadcrumb' => TRUE, 'transform' => FALSE), + 'settings form' => 'ctools_term_settings_form', + 'placeholder form' => 'ctools_term_ctools_argument_placeholder', + 'breadcrumb' => 'ctools_term_breadcrumb', +); + +/** + * Discover if this argument gives us the term we crave. + */ +function ctools_term_context($arg = NULL, $conf = NULL, $empty = FALSE) { + // If unset it wants a generic, unfilled context. + if ($empty) { + return ctools_context_create_empty('entity:taxonomy_term'); + } + + if (is_object($arg)) { + $term = $arg; + } + else { + switch ($conf['input_form']) { + case 'tid': + default: + if (!is_numeric($arg)) { + return FALSE; + } + $term = taxonomy_term_load($arg); + break; + + case 'term': + if (!empty($conf['transform'])) { + $arg = strtr($arg, '-', ' '); + } + + $terms = taxonomy_get_term_by_name($arg); + + $conf['vids'] = is_array($conf['vids']) ? array_filter($conf['vids']) : NULL; + if ((count($terms) > 1) && isset($conf['vids'])) { + foreach ($terms as $potential) { + foreach ($conf['vids'] as $vid => $active) { + if ($active && $potential->vid == $vid) { + $term = $potential; + // break out of the foreaches AND the case + break 3; + } + } + } + } + $term = array_shift($terms); + break; + } + + if (empty($term)) { + return NULL; + } + } + + if (!empty($conf['vids']) && array_filter($conf['vids']) && empty($conf['vids'][$term->vid])) { + return NULL; + } + + $context = ctools_context_create('entity:taxonomy_term', $term); + $context->original_argument = $arg; + return $context; +} + +/** + * Settings form for the argument + */ +function ctools_term_settings_form(&$form, &$form_state, $conf) { + // @todo allow synonym use like Views does. + $form['settings']['input_form'] = array( + '#title' => t('Argument type'), + '#type' => 'radios', + '#options' => array('tid' => t('Term ID'), 'term' => t('Term name')), + '#default_value' => $conf['input_form'], + '#prefix' => '<div class="clearfix">', + '#suffix' => '</div>', + ); + + $vocabularies = taxonomy_get_vocabularies(); + $options = array(); + foreach ($vocabularies as $vid => $vocab) { + $options[$vid] = $vocab->name; + } + $form['settings']['vids'] = array( + '#title' => t('Limit to these vocabularies'), + '#type' => 'checkboxes', + '#options' => $options, + '#default_value' => !empty($conf['vids']) ? $conf['vids'] : array(), + '#description' => t('If no vocabularies are checked, terms from all vocabularies will be accepted.'), + ); + + $form['settings']['breadcrumb'] = array( + '#title' => t('Inject hierarchy into breadcrumb trail'), + '#type' => 'checkbox', + '#default_value' => !empty($conf['breadcrumb']), + '#description' => t('If checked, taxonomy term parents will appear in the breadcrumb trail.'), + ); + + $form['settings']['transform'] = array( + '#title' => t('Transform dashes in URL to spaces in term name filter values'), + '#type' => 'checkbox', + '#default_value' => !empty($conf['transform']), + ); +// return $form; +} + +/** + * Form fragment to get an argument to convert a placeholder for preview. + */ +function ctools_term_ctools_argument_placeholder($conf) { + switch ($conf['input_form']) { + case 'tid': + default: + return array( + '#type' => 'textfield', + '#description' => t('Enter a taxonomy term ID.'), + ); + case 'term': + return array( + '#type' => 'textfield', + '#description' => t('Enter a taxonomy term name.'), + ); + } +} + +/** + * Inject the breadcrumb trail if necessary. + */ +function ctools_term_breadcrumb($conf, $context) { + if (empty($conf['breadcrumb']) || empty($context->data) || empty($context->data->tid)) { + return; + } + + $breadcrumb = array(); + $current = new stdClass(); + $current->tid = $context->data->tid; + while ($parents = taxonomy_get_parents($current->tid)) { + $current = array_shift($parents); + $breadcrumb[] = l($current->name, 'taxonomy/term/' . $current->tid); + } + + $breadcrumb = array_merge(drupal_get_breadcrumb(), array_reverse($breadcrumb)); + drupal_set_breadcrumb($breadcrumb); +} diff --git a/sites/all/modules/ctools/plugins/arguments/terms.inc b/sites/all/modules/ctools/plugins/arguments/terms.inc new file mode 100644 index 000000000..4298ea91d --- /dev/null +++ b/sites/all/modules/ctools/plugins/arguments/terms.inc @@ -0,0 +1,77 @@ +<?php + +/** + * @file + * + * Plugin to provide an argument handler for a Taxonomy term + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Taxonomy term (multiple): ID"), + // keyword to use for %substitution + 'keyword' => 'term', + 'description' => t('Creates a group of taxonomy terms from a list of tids separated by a comma or a plus sign. In general the first term of the list will be used for panes.'), + 'context' => 'ctools_terms_context', + 'default' => array('breadcrumb' => TRUE), + 'settings form' => 'ctools_terms_settings_form', + 'placeholder form' => array( + '#type' => 'textfield', + '#description' => t('Enter a term ID or a list of term IDs separated by a + or a ,'), + ), + 'breadcrumb' => 'ctools_terms_breadcrumb', +); + +/** + * Discover if this argument gives us the term we crave. + */ +function ctools_terms_context($arg = NULL, $conf = NULL, $empty = FALSE) { + // If unset it wants a generic, unfilled context. + if ($empty) { + return ctools_context_create_empty('terms'); + } + + $terms = ctools_break_phrase($arg); + if (empty($terms->value) || !empty($terms->invalid_input)) { + return FALSE; + } + + $context = ctools_context_create('terms', $terms); + $context->original_argument = $arg; + return $context; +} + +/** + * Settings form for the argument + */ +function ctools_terms_settings_form(&$form, &$form_state, $conf) { + $form['settings']['breadcrumb'] = array( + '#title' => t('Inject hierarchy of first term into breadcrumb trail'), + '#type' => 'checkbox', + '#default_value' => !empty($conf['breadcrumb']), + '#description' => t('If checked, taxonomy term parents will appear in the breadcrumb trail.'), + ); +// return $form; +} + +/** + * Inject the breadcrumb trail if necessary. + */ +function ctools_terms_breadcrumb($conf, $context) { + if (empty($conf['breadcrumb'])) { + return; + } + + $current->tid = $context->tids[0]; + $breadcrumb = array(); + while ($parents = taxonomy_get_parents($current->tid)) { + $current = array_shift($parents); + $breadcrumb[] = l($current->name, 'taxonomy/term/' . $current->tid); + } + + $breadcrumb = array_merge(drupal_get_breadcrumb(), array_reverse($breadcrumb)); + drupal_set_breadcrumb($breadcrumb); +} diff --git a/sites/all/modules/ctools/plugins/arguments/uid.inc b/sites/all/modules/ctools/plugins/arguments/uid.inc new file mode 100644 index 000000000..f9d5315cc --- /dev/null +++ b/sites/all/modules/ctools/plugins/arguments/uid.inc @@ -0,0 +1,53 @@ +<?php + +/** + * @file + * + * Plugin to provide an argument handler for a user id + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("User: ID"), + // keyword to use for %substitution + 'keyword' => 'user', + 'description' => t('Creates a user context from a user ID argument.'), + 'context' => 'ctools_argument_uid_context', + 'placeholder form' => array( + '#type' => 'textfield', + '#description' => t('Enter the user ID of a user for this argument'), + ), + 'default' => array('to_arg' => TRUE), + 'path placeholder' => '%pm_uid_arg', // This is in pagemanager. + 'path placeholder to_arg' => TRUE, + 'no ui' => TRUE, +); + +/** + * Discover if this argument gives us the user we crave. + */ +function ctools_argument_uid_context($arg = NULL, $conf = NULL, $empty = FALSE) { + // If unset it wants a generic, unfilled context. + if ($empty) { + return ctools_context_create_empty('user'); + } + + // We can accept either a node object or a pure nid. + if (is_object($arg)) { + return ctools_context_create('user', $arg); + } + + if (!is_numeric($arg)) { + return NULL; + } + + $account = user_load($arg); + if (!$account) { + return NULL; + } + + return ctools_context_create('user', $account); +} diff --git a/sites/all/modules/ctools/plugins/arguments/user_edit.inc b/sites/all/modules/ctools/plugins/arguments/user_edit.inc new file mode 100644 index 000000000..32b2b812a --- /dev/null +++ b/sites/all/modules/ctools/plugins/arguments/user_edit.inc @@ -0,0 +1,47 @@ +<?php + +/** + * @file + * + * Plugin to provide an argument handler for a Taxonomy term + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("User edit form: User ID"), + // keyword to use for %substitution + 'keyword' => 'user', + 'description' => t('Creates a user edit form context from a user ID argument.'), + 'context' => 'ctools_user_edit_context', + 'placeholder form' => array( + '#type' => 'textfield', + '#description' => t('Enter the user ID for this argument.'), + ), +); + +/** + * Discover if this argument gives us the term we crave. + */ +function ctools_user_edit_context($arg = NULL, $conf = NULL, $empty = FALSE) { + // If unset it wants a generic, unfilled context. + if ($empty) { + return ctools_context_create_empty('user_edit_form'); + } + if(is_object($arg)){ + return ctools_context_create('user_edit_form', $arg); + } + if (!is_numeric($arg)) { + return FALSE; + } + + $account= user_load($arg); + if (!$account) { + return NULL; + } + + // This will perform a node_access check, so we don't have to. + return ctools_context_create('user_edit_form', $account); +}
\ No newline at end of file diff --git a/sites/all/modules/ctools/plugins/arguments/user_name.inc b/sites/all/modules/ctools/plugins/arguments/user_name.inc new file mode 100644 index 000000000..f6f3b4635 --- /dev/null +++ b/sites/all/modules/ctools/plugins/arguments/user_name.inc @@ -0,0 +1,47 @@ +<?php + +/** + * @file + * + * Plugin to provide an argument handler for a username + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("User: name"), + // keyword to use for %substitution + 'keyword' => 'user', + 'description' => t('Creates a user context from a user name.'), + 'context' => 'ctools_argument_user_name_context', + 'placeholder form' => array( + '#type' => 'textfield', + '#description' => t('Enter the username of a user for this argument'), + ), +); + +/** + * Discover if this argument gives us the user we crave. + */ +function ctools_argument_user_name_context($arg = NULL, $conf = NULL, $empty = FALSE) { + // If unset it wants a generic, unfilled context. + if ($empty) { + return ctools_context_create_empty('user'); + } + + // We can accept either a node object or a pure nid. + if (is_object($arg)) { + return ctools_context_create('user', $arg); + } + + $account = user_load_by_name($arg); + if (!$account) { + return NULL; + } + return ctools_context_create('user', $account); +} + + + diff --git a/sites/all/modules/ctools/plugins/arguments/vid.inc b/sites/all/modules/ctools/plugins/arguments/vid.inc new file mode 100644 index 000000000..064b22d0a --- /dev/null +++ b/sites/all/modules/ctools/plugins/arguments/vid.inc @@ -0,0 +1,46 @@ +<?php + +/** + * @file + * + * Plugin to provide an argument handler for a vocabulary id + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Vocabulary: ID"), + // keyword to use for %substitution + 'keyword' => 'vocabulary', + 'description' => t('Creates a vocabulary context from a vocabulary ID argument.'), + 'context' => 'ctools_vid_context', + 'placeholder form' => array( + '#type' => 'textfield', + '#description' => t('Enter the vocabulary ID for this argument'), + ), + 'no ui' => TRUE, +); + +/** + * Discover if this argument gives us the vocabulary we crave. + */ +function ctools_vid_context($arg = NULL, $conf = NULL, $empty = FALSE) { + // If unset it wants a generic, unfilled context. + if ($empty) { + return ctools_context_create_empty('entity:taxonomy_vocabulary'); + } + + if (!is_numeric($arg)) { + return NULL; + } + + $vocabulary = taxonomy_vocabulary_load($arg); + if (!$vocabulary) { + return NULL; + } + + return ctools_context_create('vocabulary', $vocabulary); +} + diff --git a/sites/all/modules/ctools/plugins/cache/export_ui.inc b/sites/all/modules/ctools/plugins/cache/export_ui.inc new file mode 100644 index 000000000..53483a535 --- /dev/null +++ b/sites/all/modules/ctools/plugins/cache/export_ui.inc @@ -0,0 +1,39 @@ +<?php + +/** + * @file + * A caching mechanism for use with subsystems that use the export ui. + */ + +$plugin = array( + // cache plugins are the rare plugin types that have no real UI but + // we're providing a title just in case. + 'title' => t('Export UI wizard cache'), + 'cache get' => 'ctools_cache_export_ui_cache_get', + 'cache set' => 'ctools_cache_export_ui_cache_set', + // Some operations use a 'finalize' but that really just means set + // for us, since we're not using temporary storage for subsystems. + 'cache finalize' => 'ctools_cache_export_ui_cache_set', +); + +function ctools_cache_export_ui_cache_get($plugin_name, $key) { + ctools_include('export-ui'); + $plugin = ctools_get_export_ui($plugin_name); + $handler = ctools_export_ui_get_handler($plugin); + if ($handler) { + $item = $handler->edit_cache_get($key); + if (!$item) { + $item = ctools_export_crud_load($handler->plugin['schema'], $key); + } + return $item; + } +} + +function ctools_cache_export_ui_cache_set($plugin_name, $key, $item) { + ctools_include('export-ui'); + $plugin = ctools_get_export_ui($plugin_name); + $handler = ctools_export_ui_get_handler($plugin); + if ($handler) { + return $handler->edit_cache_set_key($item, $key); + } +} diff --git a/sites/all/modules/ctools/plugins/cache/simple.inc b/sites/all/modules/ctools/plugins/cache/simple.inc new file mode 100644 index 000000000..570398ba0 --- /dev/null +++ b/sites/all/modules/ctools/plugins/cache/simple.inc @@ -0,0 +1,51 @@ +<?php + +/** + * @file + * A simple cache indirection mechanism that just uses the basic object cache. + */ + +$plugin = array( + // cache plugins are the rare plugin types that have no real UI but + // we're providing a title just in case. + 'title' => t('Simple'), + 'cache get' => 'ctools_cache_simple_cache_get', + 'cache set' => 'ctools_cache_simple_cache_set', + 'cache clear' => 'ctools_cache_simple_cache_clear', +); + +function ctools_cache_simple_cache_get($data, $key) { + ctools_include('object-cache'); + + // Ensure that if there is somehow no data, we at least don't stomp on other + // people's caches. + if (empty($data)) { + $data = 'simple_cache_plugin'; + } + + return ctools_object_cache_get($data, $key); +} + +function ctools_cache_simple_cache_set($data, $key, $object) { + ctools_include('object-cache'); + + // Ensure that if there is somehow no data, we at least don't stomp on other + // people's caches. + if (empty($data)) { + $data = 'simple_cache_plugin'; + } + + return ctools_object_cache_set($data, $key, $object); +} + +function ctools_cache_simple_cache_clear($data, $key) { + ctools_include('object-cache'); + + // Ensure that if there is somehow no data, we at least don't stomp on other + // people's caches. + if (empty($data)) { + $data = 'simple_cache_plugin'; + } + + return ctools_object_cache_clear($data, $key); +} diff --git a/sites/all/modules/ctools/plugins/content_types/block/block.inc b/sites/all/modules/ctools/plugins/content_types/block/block.inc new file mode 100644 index 000000000..4d4c31c31 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/block.inc @@ -0,0 +1,565 @@ +<?php + +/** + * @file + * Provide Drupal blocks as content. + * + * Since blocks don't provide all of the features we do, we have to do a little + * extra work, including providing icons and categories for core blocks. Blocks + * from contrib modules get to provide their own stuff, or get relegated to + * the old "Miscellaneous" category. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + // And this is just the administrative title. + // All our callbacks are named according to the standard pattern and can be deduced. + 'title' => t('Block'), + 'content type' => 'ctools_block_content_type_content_type', +); + +/** + * Return the block content types with the specified $subtype_id. + */ +function ctools_block_content_type_content_type($subtype_id) { + list($module, $delta) = explode('-', $subtype_id, 2); + $module_blocks = module_invoke($module, 'block_info'); + if (isset($module_blocks[$delta])) { + return _ctools_block_content_type_content_type($module, $delta, $module_blocks[$delta]); + } +} + +/** + * Return all block content types available. + * + * Modules wanting to make special adjustments the way that CTools handles their blocks + * can implement an extension to the hook_block() family, where the function name is + * of the form "$module . '_ctools_block_info'". + */ +function ctools_block_content_type_content_types() { + $types = &drupal_static(__FUNCTION__); + if (isset($types)) { + return $types; + } + + $types = array(); + foreach (module_implements('block_info') as $module) { + $module_blocks = module_invoke($module, 'block_info'); + if ($module_blocks) { + foreach ($module_blocks as $delta => $block) { + $info = _ctools_block_content_type_content_type($module, $delta, $block); + // this check means modules can remove their blocks; particularly useful + // if they offer the block some other way (like we do for views) + if ($info) { + $types["$module-$delta"] = $info; + } + } + } + } + return $types; +} + +/** + * Return an info array for a specific block. + */ +function _ctools_block_content_type_content_type($module, $delta, $block) { + // strip_tags used because it goes through check_plain and that + // just looks bad. + $info = array( + 'title' => strip_tags($block['info']), + ); + + // Ask around for further information by invoking the hook_block() extension. + $function = $module . '_ctools_block_info'; + if (!function_exists($function)) { + $function = 'ctools_default_block_info'; + } + $function($module, $delta, $info); + + return $info; +} + +/** + * Load block info from the database. + * + * This is copied from _block_load_blocks(). It doesn't use that + * function because _block_load_blocks sorts by region, and it + * doesn't cache its results anyway. + */ +function _ctools_block_load_blocks() { + if (!module_exists('block')) { + return array(); + } + + $blocks = &drupal_static(__FUNCTION__, NULL); + if (!isset($blocks)) { + global $theme_key; + + $query = db_select('block', 'b'); + $result = $query + ->fields('b') + ->condition('b.theme', $theme_key) + ->orderBy('b.region') + ->orderBy('b.weight') + ->orderBy('b.module') + ->addTag('block_load') + ->addTag('translatable') + ->execute(); + + $block_info = $result->fetchAllAssoc('bid'); + // Allow modules to modify the block list. + drupal_alter('block_list', $block_info); + + $blocks = array(); + foreach ($block_info as $block) { + $blocks["{$block->module}_{$block->delta}"] = $block; + } + } + + return $blocks; +} + +/** + * Fetch the stored info for a block. + * + * The primary reason to use this is so that modules which perform alters + * can have their alters make it to the block. + */ +function _ctools_get_block_info($module, $delta) { + $blocks = _ctools_block_load_blocks(); + + $key = $module . '_' . $delta; + if (isset($blocks[$key])) { + return $blocks[$key]; + } +} + +/** + * Output function for the 'block' content type. Outputs a block + * based on the module and delta supplied in the configuration. + */ +function ctools_block_content_type_render($subtype, $conf) { + list($module, $delta) = _ctools_block_get_module_delta($subtype, $conf); + + $info = _ctools_get_block_info($module, $delta); + $block = module_invoke($module, 'block_view', $delta); + + if (!empty($info)) { + // Valid PHP function names cannot contain hyphens. + $block_delta = str_replace('-', '_', $delta); + + // Allow modules to modify the block before it is viewed, via either + // hook_block_view_alter() or hook_block_view_MODULE_DELTA_alter(). + drupal_alter(array('block_view', "block_view_{$module}_{$block_delta}"), $block, $info); + } + + if (empty($block)) { + return; + } + + $block = (object) $block; + $block->module = $module; + $block->delta = $delta; + + if (!isset($block->title)) { + if ($module == 'block' && !empty($info) && isset($info->title)) { + $block->title = $info->title; + } + else if (isset($block->subject)) { + $block->title = $block->subject; + } + else { + $block->title = NULL; + } + } + + if (module_exists('block') && user_access('administer blocks')) { + $block->admin_links = array( + array( + 'title' => t('Configure block'), + 'href' => "admin/structure/block/manage/$module/$delta/configure", + 'query' => drupal_get_destination(), + ), + ); + } + + return $block; +} + +/** + * Empty form so we can have the default override title. + */ +function ctools_block_content_type_edit_form($form, &$form_state) { + // Does nothing! + return $form; +} + +/** + * Submit function to fix the subtype for really old panel panes. + */ +function ctools_block_content_type_edit_form_submit($form, &$form_state) { + if (empty($form_state['subtype']) && isset($form_state['pane'])) { + $form_state['pane']->subtype = $form_state['conf']['module'] . '-' . $form_state['conf']['delta']; + unset($form_state['conf']['module']); + unset($form_state['conf']['delta']); + } +} + +/** + * Returns an edit form for a block. + */ +//function ctools_block_content_type_edit_form($id, $parents, $conf) { +// if (user_access('administer advanced pane settings')) { +// $form['block_visibility'] = array( +// '#type' => 'checkbox', +// '#title' => t('Use block visibility settings (see block config)'), +// '#default_value' => !empty($conf['block_visibility']), +// '#description' => t('If checked, the block visibility settings for this block will apply to this block.'), +// ); +// // Module-specific block configurations. +// if ($settings = module_invoke($module, 'block', 'configure', $delta)) { +// // Specifically modify a couple of core block forms. +// if ($module == 'block') { +// unset($settings['submit']); +// $settings['info']['#type'] = 'value'; +// $settings['info']['#value'] = $settings['info']['#default_value']; +// } +// ctools_admin_fix_block_tree($settings); +// $form['block_settings'] = array( +// '#type' => 'fieldset', +// '#title' => t('Block settings'), +// '#description' => t('Settings in this section are global and are for all blocks of this type, anywhere in the system.'), +// '#tree' => FALSE, +// ); +// +// +// $form['block_settings'] += $settings; +// } +// } +// +// return $form; +//} + +//function ctools_admin_submit_block(&$form_values) { +// if (!empty($form_values['block_settings'])) { +// module_invoke($form_values['module'], 'block', 'save', $form_values['delta'], $form_values['block_settings']); +// } +//} +// +///** +// * Because form api cannot collapse just part of a tree, and the block settings +// * assume no tree, we have to collapse the tree ourselves. +// */ +//function ctools_admin_fix_block_tree(&$form, $key = NULL) { +// if ($key) { +// if (!empty($form['#parents'])) { +// $form['#parents'] = array_merge(array('configuration', 'block_settings'), $form['#parents']); +// } +// else if (empty($form['#tree'])) { +// $form['#parents'] = array('configuration', 'block_settings', $key); +// } +// } +// +// if (isset($form['#type']) && $form['#type'] == 'textarea' && !empty($form['#rows']) && $form['#rows'] > 10) { +// $form['#rows'] = 10; +// } +// +// foreach (element_children($form) as $key) { +// ctools_admin_fix_block_tree($form[$key], $key); +// } +//} + +/** + * Returns the administrative title for a type. + */ +function ctools_block_content_type_admin_title($subtype, $conf) { + list($module, $delta) = _ctools_block_get_module_delta($subtype, $conf); + $block = module_invoke($module, 'block_info'); + if (empty($block) || empty($block[$delta])) { + return t('Deleted/missing block @module-@delta', array('@module' => $module, '@delta' => $delta)); + } + + // The block description reported by hook_block() is plain text, but the title + // reported by this hook should be HTML. + $title = check_plain($block[$delta]['info']); + return $title; +} + +/** + * Output function for the 'block' content type. Outputs a block + * based on the module and delta supplied in the configuration. + */ +function ctools_block_content_type_admin_info($subtype, $conf) { + list($module, $delta) = _ctools_block_get_module_delta($subtype, $conf); + $block = (object) module_invoke($module, 'block_view', $delta); + + if (!empty($block)) { + // Sanitize the block because <script> tags can hose javascript up: + if (!empty($block->content)) { + $block->content = filter_xss_admin(render($block->content)); + } + + if (!empty($block->subject)) { + $block->title = $block->subject; + } + elseif (empty($block->title)) { + $block->title = t('No title'); + } + return $block; + } +} + +function _ctools_block_get_module_delta($subtype, $conf) { + if (strpos($subtype, '-')) { + return explode('-', $subtype, 2); + } + else { + return array($conf['module'], $conf['delta']); + } +} + +/** + * Provide default icon and categories for blocks when modules don't do this + * for us. + */ +function ctools_default_block_info($module, $delta, &$info) { + $core_modules = array('aggregator', 'block', 'blog', 'blogapi', 'book', 'color', 'comment', 'contact', 'drupal', 'filter', 'forum', 'help', 'legacy', 'locale', 'menu', 'node', 'path', 'ping', 'poll', 'profile', 'search', 'statistics', 'taxonomy', 'throttle', 'tracker', 'upload', 'user', 'watchdog', 'system'); + + if (in_array($module, $core_modules)) { + $info['icon'] = 'icon_core_block.png'; + $info['category'] = t('Miscellaneous'); + } + else { + $info['icon'] = 'icon_contrib_block.png'; + $info['category'] = t('Miscellaneous'); + } +} + +// These are all on behalf of modules that don't implement ctools but that +// we care about. +function menu_ctools_block_info($module, $delta, &$info) { + $info['icon'] = 'icon_core_block_menu.png'; + $info['category'] = t('Menus'); + if ($delta == 'primary-links' || $delta == 'secondary-links') { + $info['icon'] = 'icon_core_primarylinks.png'; + } +} + +function forum_ctools_block_info($module, $delta, &$info) { + $info['category'] = t('Activity'); + switch ($delta) { + case 'active': + $info['icon'] = 'icon_core_activeforumtopics.png'; + break; + + case 'new': + $info['icon'] = 'icon_core_newforumtopics.png'; + break; + + default: + // safety net + ctools_default_block_info($module, $delta, $info); + } +} + +function profile_ctools_block_info($module, $delta, &$info) { + // Hide the author information block which isn't as rich as what we can + // do with context. + $info = NULL; +} + +function book_ctools_block_info($module, $delta, &$info) { + // Hide the book navigation block which isn't as rich as what we can + // do with context. + $info = NULL; +} + +function blog_ctools_block_info($module, $delta, &$info) { + $info['icon'] = 'icon_core_recentblogposts.png'; + $info['category'] = t('Activity'); +} + +function poll_ctools_block_info($module, $delta, &$info) { + $info['icon'] = 'icon_core_recentpoll.png'; + $info['category'] = t('Activity'); +} + +function comment_ctools_block_info($module, $delta, &$info) { + $info['icon'] = 'icon_core_recentcomments.png'; + $info['category'] = t('Activity'); +} + +function search_ctools_block_info($module, $delta, &$info) { + $info['icon'] = 'icon_core_searchform.png'; + $info['category'] = t('Widgets'); +} + +function node_ctools_block_info($module, $delta, &$info) { + $info['icon'] = 'icon_core_syndicate.png'; + $info['category'] = t('Widgets'); +} + +function aggregator_ctools_block_info($module, $delta, &$info) { + $info['icon'] = 'icon_core_syndicate.png'; + $info['category'] = t('Feeds'); +} + +function block_ctools_block_info($module, $delta, &$info) { + $info['icon'] = 'icon_core_block_empty.png'; + $info['category'] = t('Custom blocks'); + + // The title of custom blocks from the block module is stored in the + // {block} table. Look for it in the default theme as a reasonable + // default value for the title. + $block_info_cache = drupal_static(__FUNCTION__); + if (!isset($block_info_cache)) { + $block_info_cache = db_select('block', 'b') + ->fields('b') + ->condition('b.module', 'block') + ->condition('b.theme', variable_get('theme_default', 'bartik')) + ->addTag('block_load') + ->addTag('translatable') + ->execute() + ->fetchAllAssoc('delta'); + } + + if (isset($block_info_cache[$delta])) { + $info['defaults'] = array( + 'override_title' => TRUE, + 'override_title_text' => $block_info_cache[$delta]->title, + ); + } +} + +function user_ctools_block_info($module, $delta, &$info) { + $info['category'] = t('Activity'); + switch ($delta) { + case 'login': + $info['icon'] = 'icon_core_userlogin.png'; + $info['category'] = t('Widgets'); + // Provide a custom render callback, because the default login block + // will not render on /user, /user/login, or any other URL beginning + // /user (unless it's a user-specific page such as /user/123). + $info['render callback'] = 'ctools_user_login_pane_render'; + break; + + case 'new': + $info['icon'] = 'icon_core_whosnew.png'; + break; + + case 'online': + $info['icon'] = 'icon_core_whosonline.png'; + break; + + default: + // safety net + ctools_default_block_info($module, $delta, $info); + } +} + +function locale_ctools_block_info($module, $delta, &$info) { + $info['icon'] = 'icon_core_languageswitcher.png'; + $info['category'] = t('Widgets'); +} + +function statistics_ctools_block_info($module, $delta, &$info) { + $info['icon'] = 'icon_core_popularcontent.png'; + $info['category'] = t('Activity'); +} + +function system_ctools_block_info($module, $delta, &$info) { + // Remove the main content fake block. + if ($delta == 'main') { + $info = NULL; + return; + } + + $menus = array('main-menu', 'management', 'navigation', 'user-menu'); + + if (in_array($delta, $menus)) { + $info['icon'] = 'icon_core_block_menu.png'; + $info['category'] = t('Menus'); + + if ($delta == 'navigation') { + $info['icon'] = 'icon_core_navigation.png'; + } + + return; + } + + $info['icon'] = 'icon_core_drupal.png'; + if ($delta == 'help') { + $info['category'] = t('Page elements'); + return; + } + + $info['category'] = t('Widgets'); +} + +function ctools_user_login_pane_render($subtype, $conf, $panel_args, $contexts) { + list($module, $delta) = _ctools_block_get_module_delta($subtype, $conf); + + // The login form is only visible to anonymous users. + global $user; + if ($user->uid) { + return; + } + + $info = new stdClass; + $info->module = $module; + $info->delta = $delta; + + $block = array(); + $block['subject'] = t('User login'); + // Manually set the content (rather than invoking block_view) because the + // block implementation won't render on certain URLs. + $block['content'] = drupal_get_form('user_login_block'); + + // Allow modules to modify the block before it is viewed, via either + // hook_block_view_alter() or hook_block_view_MODULE_DELTA_alter(). + drupal_alter(array('block_view', "block_view_{$module}_{$delta}"), $block, $info); + $block = (object) $block; + + if (empty($block)) { + return; + } + + $block->module = $module; + $block->delta = $delta; + + // $block->title is not set for the blocks returned by block_block() (the + // Block module adds the title in block_list() instead), so we look it up + // manually, unless the title is overridden and does not use the %title + // placeholder. + if ($module == 'block') { + $block->title = $info->title; + } + else if (isset($block->subject)) { + $block->title = $block->subject; + } + else { + $block->title = NULL; + } + + if (isset($block->subject)) { + $block->title = $block->subject; + } + else { + $block->title = NULL; + } + + if (user_access('administer blocks')) { + $block->admin_links = array( + array( + 'title' => t('Configure block'), + 'href' => "admin/structure/block/manage/$module/$delta/configure", + 'query' => drupal_get_destination(), + ), + ); + } + + return $block; +} diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_contrib_block.png b/sites/all/modules/ctools/plugins/content_types/block/icon_contrib_block.png Binary files differnew file mode 100644 index 000000000..fa78ec179 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_contrib_block.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_contrib_block_empty.png b/sites/all/modules/ctools/plugins/content_types/block/icon_contrib_block_empty.png Binary files differnew file mode 100644 index 000000000..6d0891b03 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_contrib_block_empty.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_contrib_menu.png b/sites/all/modules/ctools/plugins/content_types/block/icon_contrib_menu.png Binary files differnew file mode 100644 index 000000000..38cf72090 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_contrib_menu.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_contrib_page.png b/sites/all/modules/ctools/plugins/content_types/block/icon_contrib_page.png Binary files differnew file mode 100644 index 000000000..4a2fa51d3 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_contrib_page.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_core_activeforumtopics.png b/sites/all/modules/ctools/plugins/content_types/block/icon_core_activeforumtopics.png Binary files differnew file mode 100644 index 000000000..8414a8f88 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_core_activeforumtopics.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_core_authorinformation.png b/sites/all/modules/ctools/plugins/content_types/block/icon_core_authorinformation.png Binary files differnew file mode 100644 index 000000000..ab248f3f1 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_core_authorinformation.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_core_block.png b/sites/all/modules/ctools/plugins/content_types/block/icon_core_block.png Binary files differnew file mode 100644 index 000000000..b0d9628ad --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_core_block.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_core_block_empty.png b/sites/all/modules/ctools/plugins/content_types/block/icon_core_block_empty.png Binary files differnew file mode 100644 index 000000000..da08c64c6 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_core_block_empty.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_core_block_menu.png b/sites/all/modules/ctools/plugins/content_types/block/icon_core_block_menu.png Binary files differnew file mode 100644 index 000000000..84594431b --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_core_block_menu.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_core_booknavigation.png b/sites/all/modules/ctools/plugins/content_types/block/icon_core_booknavigation.png Binary files differnew file mode 100644 index 000000000..52dfca536 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_core_booknavigation.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_core_languageswitcher.png b/sites/all/modules/ctools/plugins/content_types/block/icon_core_languageswitcher.png Binary files differnew file mode 100644 index 000000000..dc4521fff --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_core_languageswitcher.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_core_navigation.png b/sites/all/modules/ctools/plugins/content_types/block/icon_core_navigation.png Binary files differnew file mode 100644 index 000000000..fb4c1f84f --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_core_navigation.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_core_newforumtopics.png b/sites/all/modules/ctools/plugins/content_types/block/icon_core_newforumtopics.png Binary files differnew file mode 100644 index 000000000..70bbde26b --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_core_newforumtopics.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_core_page.png b/sites/all/modules/ctools/plugins/content_types/block/icon_core_page.png Binary files differnew file mode 100644 index 000000000..f0417cb65 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_core_page.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_core_popularcontent.png b/sites/all/modules/ctools/plugins/content_types/block/icon_core_popularcontent.png Binary files differnew file mode 100644 index 000000000..70bbde26b --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_core_popularcontent.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_core_primarylinks.png b/sites/all/modules/ctools/plugins/content_types/block/icon_core_primarylinks.png Binary files differnew file mode 100644 index 000000000..6dafb99ed --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_core_primarylinks.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_core_recentblogposts.png b/sites/all/modules/ctools/plugins/content_types/block/icon_core_recentblogposts.png Binary files differnew file mode 100644 index 000000000..785207ac4 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_core_recentblogposts.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_core_recentcomments.png b/sites/all/modules/ctools/plugins/content_types/block/icon_core_recentcomments.png Binary files differnew file mode 100644 index 000000000..ba96e32a3 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_core_recentcomments.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_core_recentpoll.png b/sites/all/modules/ctools/plugins/content_types/block/icon_core_recentpoll.png Binary files differnew file mode 100644 index 000000000..c23fa23e6 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_core_recentpoll.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_core_searchform.png b/sites/all/modules/ctools/plugins/content_types/block/icon_core_searchform.png Binary files differnew file mode 100644 index 000000000..3ad1deb65 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_core_searchform.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_core_syndicate.png b/sites/all/modules/ctools/plugins/content_types/block/icon_core_syndicate.png Binary files differnew file mode 100644 index 000000000..27c54bf00 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_core_syndicate.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_core_userlogin.png b/sites/all/modules/ctools/plugins/content_types/block/icon_core_userlogin.png Binary files differnew file mode 100644 index 000000000..dc4521fff --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_core_userlogin.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_core_whosnew.png b/sites/all/modules/ctools/plugins/content_types/block/icon_core_whosnew.png Binary files differnew file mode 100644 index 000000000..51303e7fa --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_core_whosnew.png diff --git a/sites/all/modules/ctools/plugins/content_types/block/icon_core_whosonline.png b/sites/all/modules/ctools/plugins/content_types/block/icon_core_whosonline.png Binary files differnew file mode 100644 index 000000000..a5896e3a5 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/block/icon_core_whosonline.png diff --git a/sites/all/modules/ctools/plugins/content_types/comment/comment_created.inc b/sites/all/modules/ctools/plugins/content_types/comment/comment_created.inc new file mode 100644 index 000000000..62944e712 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/comment/comment_created.inc @@ -0,0 +1,74 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'title' => t('Comment created date'), + 'icon' => 'icon_comment.png', + 'description' => t('The date the referenced comment was created.'), + 'required context' => new ctools_context_required(t('Comment'), 'entity:comment'), + 'category' => t('Comment'), + 'defaults' => array( + 'format' => 'small', + ), +); + +/** + * Render the custom content type. + */ +function ctools_comment_created_content_type_render($subtype, $conf, $panel_args, $context) { + if (empty($context) || empty($context->data)) { + return; + } + + // Get a shortcut to the comment. + $comment = $context->data; + + // Build the content type block. + $block = new stdClass(); + $block->module = 'comment_created'; + $block->title = t('Created date'); + $block->content = format_date($comment->created, $conf['format']); + $block->delta = $comment->cid; + + return $block; +} + +/** + * Returns an edit form for custom type settings. + */ +function ctools_comment_created_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + $date_types = array(); + + foreach (system_get_date_types() as $date_type => $definition) { + $date_types[$date_type] = format_date(REQUEST_TIME, $date_type); + } + $form['format'] = array( + '#title' => t('Date format'), + '#type' => 'select', + '#options' => $date_types, + '#default_value' => $conf['format'], + ); + return $form; +} + +/** + * Submit handler for the custom type settings form. + */ +function ctools_comment_created_content_type_edit_form_submit($form, &$form_state) { + // Copy everything from our defaults. + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +} + +/** + * Returns the administrative title for a type. + */ +function ctools_comment_created_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" created date', array('@s' => $context->identifier)); +} diff --git a/sites/all/modules/ctools/plugins/content_types/comment/comment_links.inc b/sites/all/modules/ctools/plugins/content_types/comment/comment_links.inc new file mode 100644 index 000000000..c8fefccab --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/comment/comment_links.inc @@ -0,0 +1,80 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'title' => t('Comment links'), + 'icon' => 'icon_comment.png', + 'description' => t('Comment links of the referenced comment.'), + 'required context' => new ctools_context_required(t('Comment'), 'entity:comment'), + 'category' => t('Comment'), + 'defaults' => array( + 'override_title' => FALSE, + 'override_title_text' => '', + 'build_mode' => '', + ), +); + +/** + * Output function for the comment links. + */ +function ctools_comment_links_content_type_render($subtype, $conf, $panel_args, $context) { + if (!empty($context) && empty($context->data)) { + return; + } + + $comment = isset($context->data) ? clone($context->data) : NULL; + $block = new stdClass(); + $block->module = 'comment'; + $block->delta = $comment->cid; + + if (empty($comment)) { + $block->delta = 'placeholder'; + $block->subject = t('Comment subject.'); + $block->content = t('Comment links go here.'); + } + else { + $node = node_load($comment->nid); + $block->subject = $comment->subject; + comment_build_content($comment, $node, $conf['build_mode']); + $block->content = $comment->content['links']; + } + return $block; +} + +/** + * Returns an edit form for the custom type. + */ +function ctools_comment_links_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + + $entity = entity_get_info('comment'); + $build_mode_options = array(); + foreach ($entity['view modes'] as $mode => $option) { + $build_mode_options[$mode] = $option['label']; + } + + $form['build_mode'] = array( + '#title' => t('Build mode'), + '#type' => 'select', + '#description' => t('Select a build mode for this comment.'), + '#options' => $build_mode_options, + '#default_value' => $conf['build_mode'], + ); + + return $form; +} + +function ctools_comment_links_content_type_edit_form_submit($form, &$form_state) { + // Copy everything from our defaults. + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +} + +function ctools_comment_links_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" links', array('@s' => $context->identifier)); +} diff --git a/sites/all/modules/ctools/plugins/content_types/comment/comment_reply_form.inc b/sites/all/modules/ctools/plugins/content_types/comment/comment_reply_form.inc new file mode 100644 index 000000000..c05effb60 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/comment/comment_reply_form.inc @@ -0,0 +1,50 @@ +<?php + +/** + * @file + * Ctools content-type plugin to provide a comment-reply form (replying either + * to a node or to another comment). + */ + +// Only provide the plugin in the comment module is enabled. +if (module_exists('comment')) { + $plugin = array( + 'single' => TRUE, + 'title' => t('Comment Reply Form'), + 'icon' => 'icon_comment.png', + 'description' => t('A form to add a new comment reply.'), + 'required context' => array( + new ctools_context_required(t('Node'), 'node'), + new ctools_context_optional(t('Comment'), 'comment'), + ), + 'category' => t('Comment'), + 'render callback' => 'ctools_comment_reply_form_content_type_render', + 'defaults' => array('anon_links' => false), + ); +} + +function ctools_comment_reply_form_content_type_render($subtype, $conf, $panel_args, $context) { + + $comment = ($context[1]->identifier == t('No context')) ? NULL : clone($context[1]->data); + $block = new stdClass(); + $block->module = 'comments'; + if ($comment) $block->delta = $comment->cid; + $block->title = t('Add comment'); + $node = $context[0]->data; + + module_load_include('inc', 'comment', 'comment.pages'); + $block->content = comment_reply($node, ($comment ? $comment->cid : NULL)); + + return $block; +} + +function ctools_comment_reply_form_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" comment form', array('@s' => $context[0]->identifier)); +} + +function ctools_comment_reply_form_content_type_edit_form($form, &$form_state) { + return $form; +} + +function ctools_comment_reply_form_content_type_edit_form_submit($form, &$form_state) { +} diff --git a/sites/all/modules/ctools/plugins/content_types/contact/contact.inc b/sites/all/modules/ctools/plugins/content_types/contact/contact.inc new file mode 100644 index 000000000..63283f598 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/contact/contact.inc @@ -0,0 +1,60 @@ +<?php + +if (module_exists('contact')) { + /** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ + $plugin = array( + 'single' => TRUE, + 'title' => t('Contact form'), + 'icon' => 'icon_contact.png', + 'description' => t('The site contact form that allows users to send a message to site administrators.'), + 'category' => t('Widgets'), + ); +} + +/** + * Render the custom content type. + */ +function ctools_contact_content_type_render($subtype, $conf, $panel_args, $context) { + if (!user_access('access site-wide contact form')) { + return; + } + // Build the content type block. + $block = new stdClass(); + $block->module = 'contact'; + $block->delta = 'form'; + $block->title = t('Contact'); + + module_load_include('inc', 'contact', 'contact.pages'); + $block->content = drupal_get_form('contact_site_form'); + return $block; +} + +/** + * Returns an edit form for custom type settings. + */ +function ctools_contact_content_type_edit_form($form, &$form_state) { + // Empty so that we can have title override. + return $form; +} + +/** + * Submit handler for contact form. + */ +function ctools_contact_content_type_edit_form_submit($form, &$form_state) { + // Copy everything from our defaults. +/* + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +*/ +} + +/** + * Returns the administrative title for a type. + */ +function ctools_contact_content_type_admin_title($subtype, $conf, $context) { + return t('Contact form'); +} diff --git a/sites/all/modules/ctools/plugins/content_types/contact/icon_contact.png b/sites/all/modules/ctools/plugins/content_types/contact/icon_contact.png Binary files differnew file mode 100644 index 000000000..ab248f3f1 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/contact/icon_contact.png diff --git a/sites/all/modules/ctools/plugins/content_types/contact/user_contact.inc b/sites/all/modules/ctools/plugins/content_types/contact/user_contact.inc new file mode 100644 index 000000000..9b3726ab8 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/contact/user_contact.inc @@ -0,0 +1,66 @@ +<?php + +if (module_exists('contact')) { + /** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ + $plugin = array( + 'single' => TRUE, + 'title' => t('User contact form'), + 'icon' => 'icon_contact.png', + 'description' => t('The site contact form that allows users to contact other users.'), + 'category' => t('User'), + 'required context' => new ctools_context_required(t('User'), 'user'), + ); +} + +/** + * Render the custom content type. + */ +function ctools_user_contact_content_type_render($subtype, $conf, $panel_args, $context) { + if (empty($context) || empty($context->data)) { + return; + } + + if (!_contact_personal_tab_access($context->data)) { + return; + } + + // Build the content type block. + $block = new stdClass(); + $block->module = 'contact'; + $block->delta = 'form'; + $block->title = t('Contact @name', array('@name' => $context->data->name)); + + module_load_include('inc', 'contact', 'contact.pages'); + $block->content = drupal_get_form('contact_personal_form', $context->data); + return $block; +} + +/** + * Returns an edit form for custom type settings. + */ +function ctools_user_contact_content_type_edit_form($form, &$form_state) { + // Empty so that we can have title override. + return $form; +} + +/** + * Submit handler for contact form. + */ +function ctools_user_contact_content_type_edit_form_submit(&$form, &$form_state) { + // Copy everything from our defaults. +/* + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +*/ +} + +/** + * Returns the administrative title for a type. + */ +function ctools_user_contact_content_type_admin_title($subtype, $conf, $context) { + return t('User contact form'); +} diff --git a/sites/all/modules/ctools/plugins/content_types/custom/custom.inc b/sites/all/modules/ctools/plugins/content_types/custom/custom.inc new file mode 100644 index 000000000..ac2f2a3ff --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/custom/custom.inc @@ -0,0 +1,434 @@ +<?php + +/** + * @file + * Custom content type. + * + * This content type is nothing more than a title and a body that is entered + * by the user and run through standard filters. The information is stored + * right in the config, so each custom content is unique. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Custom content'), + 'no title override' => TRUE, + 'defaults' => array('admin_title' => '', 'title' => '', 'body' => '', 'format' => filter_default_format(), 'substitute' => TRUE), + 'js' => array('misc/autocomplete.js', 'misc/textarea.js', 'misc/collapse.js'), + // Make sure the edit form is only used for some subtypes. + 'edit form' => '', + 'add form' => '', + 'edit text' => t('Edit'), + 'all contexts' => TRUE, +); + +/** + * Return the custom content types with the specified $subtype_id. + */ +function ctools_custom_content_type_content_type($subtype_id) { + if ($subtype_id == 'custom') { + return _ctools_default_content_type_content_type(); + } + elseif (module_exists('ctools_custom_content')) { + ctools_include('export'); + $content = ctools_export_crud_load('ctools_custom_content', $subtype_id); + if ($content) { + return _ctools_custom_content_type_content_type($content); + } + } +} + +/** + * Return all custom content types available. + */ +function ctools_custom_content_type_content_types() { + $types = &drupal_static(__FUNCTION__); + if (isset($types)) { + return $types; + } + + ctools_include('export'); + $types = array(); + $types['custom'] = _ctools_default_content_type_content_type(); + + if (module_exists('ctools_custom_content')) { + foreach (ctools_export_crud_load_all('ctools_custom_content') as $name => $content) { + $types[$name] = _ctools_custom_content_type_content_type($content); + } + } + + return $types; +} + +/** + * Settings for the default custom content type. + * + * The default is the one that allows the user to actually create a type. + */ +function _ctools_default_content_type_content_type() { + $info = array( + 'name' => 'custom', + 'title' => t('New custom content'), + 'top level' => TRUE, + 'category' => t('Custom'), + 'description' => t('Create a completely custom piece of HTML content.'), + 'edit form' => 'ctools_custom_content_type_edit_form', + 'all contexts' => TRUE, + 'check editable' => 'ctools_custom_content_type_editable', + ); + + return $info; +} + +/** + * Return an info array for a specific custom content type. + */ +function _ctools_custom_content_type_content_type($content) { + $info = array( + 'name' => $content->name, + 'title' => check_plain($content->admin_title), + 'description' => check_plain($content->admin_description), + 'category' => $content->category ? check_plain($content->category) : t('Miscellaneous'), + 'all contexts' => TRUE, + 'icon' => 'icon_block_custom.png', + // Store this here to make it easy to access. + 'content' => $content, + ); + + return $info; +} + +/** + * Given a subtype and a $conf, return the actual settings to use. + * + * The actual settings may be stored directly in the pane or this may + * be a pointer to re-usable content that may be in the database or in + * an export. We have to determine from the subtype whether or not it + * is local or shared custom content. + */ +function ctools_custom_content_type_get_conf($subtype, $conf) { + if ($subtype['name'] != 'custom') { + $settings = $subtype['content']->settings; + $settings['custom_type'] = 'fixed'; + $settings['content'] = $subtype['content']; + } + else { + // This means they created it as custom content and then set it as + // reusable. Since we're not allowed to change the subtype, we're + // still stored as though we are local, but are pointing off to + // non-local. + if (!empty($conf['name']) && module_exists('ctools_custom_content')) { + ctools_include('export'); + $content = ctools_export_crud_load('ctools_custom_content', $conf['name']); + if ($content) { + $settings = $content->settings; + $settings['custom_type'] = 'fixed'; + $settings['content'] = $content; + $settings['admin_title'] = $content->admin_title; + } + else { + $content = ctools_export_crud_new('ctools_custom_content'); + $content->name = $conf['name']; + $settings = array( + 'admin_title' => t('Missing/deleted content'), + 'title' => '', + 'body' => '', + 'format' => filter_default_format(), + 'substitute' => TRUE, + 'custom_type' => 'fixed', + 'content' => $content, + ); + } + } + // This means that it is created as custom and has not been set to + // reusable. + else { + $settings = $conf; + $settings['custom_type'] = 'local'; + } + } + + // Correct for an error that came in because filter format changed. + if (is_array($settings['body'])) { + $settings['format'] = $settings['body']['format']; + $settings['body'] = $settings['body']['value']; + } + + return $settings; +} + +function ctools_custom_content_type_editable($content_type, $subtype, $conf) { + if ($subtype['name'] == 'custom' && !empty($conf['name'])) { + return FALSE; + } + + return TRUE; +} + +/** + * Output function for the 'custom' content type. Outputs a custom + * based on the module and delta supplied in the configuration. + */ +function ctools_custom_content_type_render($subtype, $conf, $args, $contexts) { + $settings = ctools_custom_content_type_get_conf(ctools_custom_content_type_content_type($subtype), $conf); + + static $delta = 0; + + $block = new stdClass(); + $block->subtype = ++$delta; + $block->title = filter_xss_admin($settings['title']); + + // Add keyword substitutions if we were configured to do so. + $content = $settings['body']; + if (!empty($contexts) && !empty($settings['substitute'])) { + $content = ctools_context_keyword_substitute($content, array(), $contexts); + } + + $block->content = check_markup($content, $settings['format']); + if ($settings['custom_type'] == 'fixed' && user_access('administer custom content')) { + $block->admin_links = array( + array( + 'title' => t('Configure content pane'), + 'alt' => t("Configure this pane in administer >> structure >> custom content panes"), + 'href' => 'admin/structure/ctools-content/list/' . $settings['content']->name . '/edit', + 'query' => drupal_get_destination(), + ), + ); + } + + return $block; +} + +/** + * Callback to provide the administrative title of the custom content. + */ +function ctools_custom_content_type_admin_title($subtype, $conf) { + $settings = ctools_custom_content_type_get_conf(ctools_custom_content_type_content_type($subtype), $conf); + + $output = t('Custom'); + $title = !empty($settings['admin_title']) ? $settings['admin_title'] : $settings['title']; + if ($title) { + if ($settings['custom_type'] != 'fixed') { + $output = t('Custom: @title', array('@title' => $title)); + } + else { + $output = $title; + } + } + + return $output; +} + +/** + * Callback to provide administrative info. In this case we'll render the + * content as long as it's not PHP, which is too risky to render here. + */ +function ctools_custom_content_type_admin_info($subtype, $conf) { + $settings = ctools_custom_content_type_get_conf(ctools_custom_content_type_content_type($subtype), $conf); + + $block = new stdClass(); + $block->title = filter_xss_admin($settings['title']); + // We don't want to render php output on preview here, because if something is + // wrong the whole display will be borked. So we check to see if the php + // evaluator filter is being used, and make a temporary change to the filter + // so that we get the printed php, not the eval'ed php. + $php_filter = FALSE; + foreach (filter_list_format($settings['format']) as $filter) { + if ($filter->module == 'php') { + $php_filter = TRUE; + break; + } + } + // If a php filter is active, just print the source, but only if the current + // user has access to the actual filter. + if ($php_filter) { + $filter = filter_format_load($settings['format']); + if (!filter_access($filter)) { + return NULL; + } + $block->content = '<pre>' . check_plain($settings['body']) . '</pre>'; + } + else { + // We also need to filter through XSS admin because <script> tags can + // cause javascript which will interfere with our ajax. + $block->content = filter_xss_admin(check_markup($settings['body'], $settings['format'])); + } + return $block; +} + +/** + * Returns an edit form for the custom type. + */ +function ctools_custom_content_type_edit_form($form, &$form_state) { + $settings = ctools_custom_content_type_get_conf($form_state['subtype'], $form_state['conf']); + $form_state['settings'] = $settings; + + if ($settings['custom_type'] == 'fixed') { + return $form; // no form for this case. + } + + $form['admin_title'] = array( + '#type' => 'textfield', + '#default_value' => isset($settings['admin_title']) ? $settings['admin_title'] : '', + '#title' => t('Administrative title'), + '#description' => t('This title will be used administratively to identify this pane. If blank, the regular title will be used.'), + ); + + $form['title'] = array( + '#type' => 'textfield', + '#default_value' => $settings['title'], + '#title' => t('Title'), + ); + + $form['body'] = array( + '#type' => 'text_format', + '#title' => t('Body'), + '#default_value' => $settings['body'], + '#format' => $settings['format'], + ); + + if (!empty($form_state['contexts'])) { + // Set extended description if both CCK and Token modules are enabled, notifying of unlisted keywords + if (module_exists('content') && module_exists('token')) { + $description = t('If checked, context keywords will be substituted in this content. Note that CCK fields may be used as keywords using patterns like <em>%node:field_name-formatted</em>.'); + } + elseif (!module_exists('token')) { + $description = t('If checked, context keywords will be substituted in this content. More keywords will be available if you install the Token module, see http://drupal.org/project/token.'); + } + else { + $description = t('If checked, context keywords will be substituted in this content.'); + } + + $form['substitute'] = array( + '#type' => 'checkbox', + '#title' => t('Use context keywords'), + '#description' => $description, + '#default_value' => !empty($settings['substitute']), + ); + $form['contexts'] = array( + '#title' => t('Substitutions'), + '#type' => 'fieldset', + '#collapsible' => TRUE, + '#collapsed' => TRUE, + ); + + $rows = array(); + foreach ($form_state['contexts'] as $context) { + foreach (ctools_context_get_converters('%' . check_plain($context->keyword) . ':', $context) as $keyword => $title) { + $rows[] = array( + check_plain($keyword), + t('@identifier: @title', array('@title' => $title, '@identifier' => $context->identifier)), + ); + } + } + $header = array(t('Keyword'), t('Value')); + $form['contexts']['context'] = array('#markup' => theme('table', array('header' => $header, 'rows' => $rows))); + } + + if (!user_access('administer custom content') || !module_exists('ctools_custom_content')) { + return $form; + } + + // Make the other form items dependent upon it. + ctools_include('dependent'); + ctools_add_js('dependent'); + + $form['reusable'] = array( + '#type' => 'checkbox', + '#title' => t('Make this content reusable'), + '#default_value' => FALSE, + ); + + $form['name'] = array( + '#type' => 'textfield', + '#title' => t('Machine name'), + '#description' => t('The machine readable name of this content. It must be unique, and it must contain only alphanumeric characters and underscores. Once created, you will not be able to change this value!'), + '#dependency' => array('edit-reusable' => array(1)), + ); + + $form['category'] = array( + '#type' => 'textfield', + '#title' => t('Category'), + '#description' => t('What category this content should appear in. If left blank the category will be "Miscellaneous".'), + '#dependency' => array('edit-reusable' => array(1)), + ); + + $form['admin_description'] = array( + '#type' => 'textarea', + '#title' => t('Administrative description'), + '#description' => t('A description of what this content is, does or is for, for administrative use.'), + '#dependency' => array('edit-reusable' => array(1)), + ); + return $form; +} + +function _ctools_custom_content_type_edit_save(&$content, $form_state) { + // Apply updates to the content object. + $content->category = $form_state['values']['category']; + $content->admin_title = $form_state['values']['admin_title']; + $content->admin_description = $form_state['values']['admin_description']; + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + if (isset($form_state['values'][$key])) { + $content->settings[$key] = $form_state['values'][$key]; + } + } + + ctools_export_crud_save('ctools_custom_content', $content); +} + +/** + * The validate form to ensure the custom content data is okay. + */ +function ctools_custom_content_type_edit_form_validate(&$form, &$form_state) { + if ($form_state['settings']['custom_type'] != 'fixed' && !empty($form_state['values']['reusable'])) { + if (empty($form_state['values']['name'])) { + form_error($form['name'], t('Name is required.')); + } + + // Check for string identifier sanity + if (!preg_match('!^[a-z0-9_]+$!', $form_state['values']['name'])) { + form_error($form['name'], t('The name can only consist of lowercase letters, underscores, and numbers.')); + return; + } + + if (!module_exists('ctools_custom_content')) { + return; + } + + // Check for name collision + if ($form_state['values']['name'] == 'custom' || (ctools_export_crud_load('ctools_custom_content', $form_state['values']['name']))) { + form_error($form['name'], t('Content with this name already exists. Please choose another name or delete the existing item before creating a new one.')); + } + } +} + +/** + * The submit form stores the data in $conf. + */ +function ctools_custom_content_type_edit_form_submit($form, &$form_state) { + // Because of changes in filter form, these two keys are out of position: + $form_state['values']['format'] = $form_state['values']['body']['format']; + $form_state['values']['body'] = $form_state['values']['body']['value']; + + if ($form_state['settings']['custom_type'] == 'fixed') { + _ctools_custom_content_type_edit_save($form_state['settings']['content'], $form_state); + } + // If the 'reusable' checkbox was checked, we will create a new + // custom content and give it the proper values. + else if (!empty($form_state['values']['reusable'])) { + $content = ctools_export_crud_new('ctools_custom_content'); + $content->name = $form_state['values']['name']; + _ctools_custom_content_type_edit_save($content, $form_state); + $form_state['conf']['name'] = $content->name; + } + else { + // Otherwise, just save values into $conf normally. + + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = isset($form_state['values'][$key]) ? $form_state['values'][$key] : $form_state['plugin']['defaults'][$key]; + } + } +} diff --git a/sites/all/modules/ctools/plugins/content_types/custom/icon_block_custom.png b/sites/all/modules/ctools/plugins/content_types/custom/icon_block_custom.png Binary files differnew file mode 100644 index 000000000..bbde4bd57 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/custom/icon_block_custom.png diff --git a/sites/all/modules/ctools/plugins/content_types/entity_context/entity_field.inc b/sites/all/modules/ctools/plugins/content_types/entity_context/entity_field.inc new file mode 100644 index 000000000..65367a026 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/entity_context/entity_field.inc @@ -0,0 +1,281 @@ +<?php + +/** + * @file + * Handle rendering entity fields as panes. + */ + +$plugin = array( + 'title' => t('Entity field'), + 'defaults' => array('label' => 'title', 'formatter' => '', 'delta_limit' => 0, 'delta_offset' => '0', 'delta_reversed' => FALSE), + 'content type' => 'ctools_entity_field_content_type_content_type', +); + +/** + * Just one subtype. + * + * Ordinarily this function is meant to get just one subtype. However, we are + * using it to deal with the fact that we have changed the subtype names. This + * lets us translate the name properly. + */ +function ctools_entity_field_content_type_content_type($subtype) { + $types = ctools_entity_field_content_type_content_types(); + if (isset($types[$subtype])) { + return $types[$subtype]; + } +} + +/** + * Return all field content types available. + */ +function ctools_entity_field_content_type_content_types() { + $types = &drupal_static(__FUNCTION__, array()); + if (!empty($types)) { + return $types; + } + + $cache_key = 'ctools_entity_field_content_type_content_types'; + if ($cache = cache_get($cache_key)) { + $types = $cache->data; + if (!empty($types)) { + return $types; + } + } + + // This will hold all the individual field content types. + $context_types = array(); + $entities = entity_get_info(); + + $description = t('Field on the referenced entity.'); + $styles = t('Formatter Styles'); + $categories = array(); + foreach ($entities as $entity_type => $entity) { + $category = t(ucfirst($entity_type)); + $categories[$entity_type] = $category; + foreach ($entity['bundles'] as $type => $bundle) { + foreach (field_info_instances($entity_type, $type) as $field_name => $field) { + if (!isset($types[$entity_type . ':' . $field_name])) { + $label = t($field['label']); + $types[$entity_type . ':' . $field_name] = array( + 'category' => $category, + 'icon' => 'icon_field.png', + 'title' => t('Field: @widget_label (@field_name)', array( + '@widget_label' => $label, + '@field_name' => $field_name, + )), + 'description' => $description, + 'edit form' => array( + 'ctools_entity_field_content_type_formatter_options' => array( + 'default' => TRUE, + 'title' => t('Formatter options for: @widget_label (@field_name)', array( + '@widget_label' => $label, + '@field_name' => $field_name, + )), + ), + 'ctools_entity_field_content_type_formatter_styles' => $styles, + ), + ); + } + $context_types[$entity_type . ':' . $field_name]['types'][$type] = $bundle['label']; + } + } + } + + // Create the required context for each field related to the bundle types. + foreach ($types as $key => $field_content_type) { + list($entity_type, $field_name) = explode(':', $key, 2); + $types[$key]['required context'] = new ctools_context_required($categories[$entity_type], $entity_type, array( + 'type' => array_keys($context_types[$key]['types']), + )); + unset($context_types[$key]['types']); + } + + cache_set($cache_key, $types); + + return $types; +} + +/** +* Render the custom content type. +*/ +function ctools_entity_field_content_type_render($subtype, $conf, $panel_args, $context) { + if (empty($context) || empty($context->data)) { + return; + } + + // Get a shortcut to the entity. + $entity = $context->data; + list($entity_type, $field_name) = explode(':', $subtype, 2); + + // Load the entity type's information for this field. + $ids = entity_extract_ids($entity_type, $entity); + $field = field_info_instance($entity_type, $field_name, $ids[2]); + + // Do not render if the entity type does not have this field. + if (empty($field)) { + return; + } + $language = field_language($entity_type, $entity, $field_name); + + if (empty($conf['label']) || $conf['label'] == 'title') { + $label = 'hidden'; + $conf['label'] = 'title'; + } + else { + $label = $conf['label']; + } + + $field_settings = array( + 'label' => $label, + 'type' => $conf['formatter'], + // Pass all entity field panes settings to field display settings. + 'pane_settings' => $conf, + ); + + // Get the field output, and the title. + if (!empty($conf['formatter_settings'])) { + $field_settings['settings'] = $conf['formatter_settings']; + } + + $all_values = field_get_items($entity_type, $entity, $field_name, $language); + if (!is_array($all_values)) { + // Do not render if the field is empty. + return; + } + + // Reverse values. + if (isset($conf['delta_reversed']) && $conf['delta_reversed']) { + $all_values = array_reverse($all_values, TRUE); + } + + if (isset($conf['delta_limit'])) { + $offset = intval($conf['delta_offset']); + $limit = !empty($conf['delta_limit']) ? $conf['delta_limit'] : NULL; + $all_values = array_slice($all_values, $offset, $limit, TRUE); + } + + $clone = clone $entity; + $clone->{$field_name}[$language] = $all_values; + $field_output = field_view_field($entity_type, $clone, $field_name, $field_settings, $language); + + if (!empty($field_output) && !empty($conf['override_title'])) { + $field_output['#title'] = filter_xss_admin($conf['override_title_text']); + } + + // Build the content type block. + $block = new stdClass(); + $block->module = 'entity_field'; + if ($conf['label'] == 'title' && isset($field_output['#title'])) { + $block->title = $field_output['#title']; + } + + $block->content = $field_output; + $block->delta = $ids[0]; + + return $block; +} + +/** +* Returns an edit form for custom type settings. +*/ +function ctools_entity_field_content_type_formatter_options($form, &$form_state) { + if (empty($form_state['conf']['formatter_settings'])) { + $form_state['conf']['formatter_settings'] = array(); + } + $conf = $form_state['conf']; + $subtype = $form_state['subtype_name']; + list($entity_type, $field_name) = explode(':', $subtype, 2); + + $field = field_info_field($field_name); + module_load_include('inc', 'field_ui', 'field_ui.admin'); + $formatter_options = field_ui_formatter_options($field['type']); + + $field_label_options = array( + 'title' => t('Pane title'), + 'above' => t('Above'), + 'inline' => t('Inline'), + 'hidden' => t('Hidden'), + ); + + $form['label'] = array( + '#type' => 'select', + '#title' => t('Label'), + '#options' => $field_label_options, + '#default_value' => $conf['label'], + ); + + $form['formatter'] = array( + '#type' => 'select', + '#title' => t('Select a formatter'), + '#options' => $formatter_options, + '#default_value' => $conf['formatter'], + ); + + return $form; +} + +function ctools_entity_field_content_type_formatter_options_submit($form, &$form_state) { + $form_state['conf']['formatter'] = $form_state['values']['formatter']; + $form_state['conf']['label'] = $form_state['values']['label']; +} + +function ctools_entity_field_content_type_formatter_styles($form, &$form_state) { + if (!$form_state['conf']['formatter_settings']) { + $form_state['conf']['formatter_settings'] = array(); + } + $conf = $form_state['conf']; + $subtype = $form_state['subtype_name']; + list($entity_type, $field_name) = explode(':', $subtype, 2); + $field = field_info_field($field_name); + + ctools_form_include($form_state, 'field_ui.admin', 'field_ui', ''); + ctools_form_include($form_state, 'fields'); + + $form['ctools_field_list'] = array( + '#type' => 'value', + '#value' => array(), + ); + + ctools_fields_get_field_formatter_settings_form($field, $conf['formatter'], $form, $form_state); + return $form; +} + +function ctools_entity_field_content_type_formatter_styles_submit($form, &$form_state) { + $fields = $form_state['values']['ctools_field_list']; + $formatter_info = ctools_fields_get_field_formatter_info($fields); + foreach ($formatter_info as $info) { + if (!empty($info['settings'])) { + foreach ($info['settings'] as $field_name => $value) { + if (isset($form_state['values'][$field_name])) { + $form_state['conf']['formatter_settings'][$field_name] = $form_state['values'][$field_name]; + } + } + } + } + + if (isset($form_state['values']['delta_limit'])) { + $form_state['conf']['delta_limit'] = $form_state['values']['delta_limit']; + $form_state['conf']['delta_offset'] = $form_state['values']['delta_offset']; + $form_state['conf']['delta_reversed'] = $form_state['values']['delta_reversed']; + } +} + +/** + * Returns the administrative title for a type. + */ +function ctools_entity_field_content_type_admin_title($subtype, $conf, $context) { + list($bundle, $field_name) = explode(':', $subtype); + ctools_include('fields'); + if (is_object($context) && isset($context->identifier)) { + $identifier = $context->identifier; + } + else { + $type = 'ctools_entity_field_content_type_admin_title'; + $message = t('Context is missing for field: @name', array('@name' => $subtype)); + $variables = array($subtype, $conf, $context); + watchdog($type, $message, $variables, $severity = WATCHDOG_NOTICE); + $identifier = t('Unknown'); + } + + return t('"@s" @field', array('@s' => $identifier, '@field' => ctools_field_label($field_name))); +} diff --git a/sites/all/modules/ctools/plugins/content_types/entity_context/entity_field_extra.inc b/sites/all/modules/ctools/plugins/content_types/entity_context/entity_field_extra.inc new file mode 100644 index 000000000..6a59ed4c6 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/entity_context/entity_field_extra.inc @@ -0,0 +1,133 @@ +<?php + +$plugin = array( + 'title' => t('Entity extra field'), + 'defaults' => array('view_mode' => NULL), + 'content type' => 'ctools_entity_field_extra_content_type_content_type', +); + +/** + * Just one subtype. + * + * Ordinarily this function is meant to get just one subtype. However, we are + * using it to deal with the fact that we have changed the subtype names. This + * lets us translate the name properly. + */ +function ctools_entity_field_extra_content_type_content_type($subtype) { + $types = ctools_entity_field_extra_content_type_content_types(); + if (isset($types[$subtype])) { + return $types[$subtype]; + } +} + +/** + * Return all extra field content types available. + */ +function ctools_entity_field_extra_content_type_content_types() { + // This will hold all the individual field content types. + $types = &drupal_static(__FUNCTION__); + if (isset($types)) { + return $types; + } + + $types = array(); + $context_types = array(); + $entities = entity_get_info(); + + foreach ($entities as $entity_type => $entity) { + foreach ($entity['bundles'] as $type => $bundle) { + foreach (field_info_extra_fields($entity_type, $type, 'display') as $field_name => $info) { + if (!isset($types[$entity_type . ':' . $field_name])) { + $types[$entity_type . ':' . $field_name] = array( + 'category' => t(ucfirst($entity_type)), + 'icon' => 'icon_field.png', + 'title' => $info['label'], + 'description' => isset($info['description']) ? $info['description'] : '', + ); + } + $context_types[$entity_type . ':' . $field_name]['types'][$type] = $bundle['label']; + } + } + } + + // Create the required context for each field related to the bundle types. + foreach ($types as $key => $field_content_type) { + list($entity_type, $field_name) = explode(':', $key, 2); + $types[$key]['required context'] = new ctools_context_required(t(ucfirst($entity_type)), $entity_type, array( + 'type' => array_keys($context_types[$key]['types']), + )); + unset($context_types[$key]['types']); + } + + return $types; +} + +/** + * Returns an edit form for an extra field. + */ +function ctools_entity_field_extra_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + $subtype = $form_state['subtype_name']; + list($entity_type, $field_name) = explode(':', $subtype, 2); + + $info = entity_get_info($entity_type); + $view_mode_options = array(); + foreach ($info['view modes'] as $mode => $option) { + $view_mode_options[$mode] = $option['label']; + } + + $form['view_mode'] = array( + '#title' => t('View mode'), + '#type' => 'select', + '#description' => t('Select a view mode for this extra field.'), + '#options' => $view_mode_options, + '#default_value' => $conf['view_mode'], + ); + + return $form; +} + +function ctools_entity_field_extra_content_type_edit_form_submit($form, &$form_state) { + $form_state['conf']['view_mode'] = $form_state['values']['view_mode']; +} + +/** + * Render the extra field. + */ +function ctools_entity_field_extra_content_type_render($subtype, $conf, $panel_args, $context) { + if (empty($context) || empty($context->data)) { + return; + } + // Get a shortcut to the entity. + $entity = clone $context->data; + list($entity_type, $field_name) = explode(':', $subtype, 2); + list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity); + $langcode = $GLOBALS['language_content']->language; + + $function = $entity_type . '_view'; + if (in_array($entity_type, array('node', 'taxonomy_term', 'user')) && function_exists($function)) { + // Call known ENTITY_view() to get the extra field. + $entity->content = $function($entity, $conf['view_mode'], $langcode); + } + else { + // Invoke the view-hook to get the extra field. + $entity->content = array(); + + module_invoke_all($entity_type . '_view', $entity, $conf['view_mode'], $langcode); + module_invoke_all('entity_view', $entity, $entity_type, $conf['view_mode'], $langcode); + } + + if (isset($entity->content[$field_name])) { + // Build the content type block. + $block = new stdClass(); + $block->module = 'entity_field_extra'; + $block->content = $entity->content[$field_name]; + $block->delta = $id; + return $block; + } +} + +function ctools_entity_field_extra_content_type_admin_title($subtype, $conf, $context) { + $info = ctools_entity_field_extra_content_type_content_type($subtype); + return t('"@s" @field', array('@s' => $context->identifier, '@field' => $info['title'])); +} diff --git a/sites/all/modules/ctools/plugins/content_types/form/entity_form_field.inc b/sites/all/modules/ctools/plugins/content_types/form/entity_form_field.inc new file mode 100644 index 000000000..582bd785c --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/form/entity_form_field.inc @@ -0,0 +1,167 @@ +<?php + +/** + * @file + * Handle rendering entity fields as panes. + */ + +$plugin = array( + 'title' => t('Entity field'), + 'defaults' => array('label' => '', 'formatter' => ''), + 'content type' => 'ctools_entity_form_field_content_type_content_type', +); + +/** + * Just one subtype. + * + * Ordinarily this function is meant to get just one subtype. However, we are + * using it to deal with the fact that we have changed the subtype names. This + * lets us translate the name properly. + */ +function ctools_entity_form_field_content_type_content_type($subtype) { + $types = ctools_entity_form_field_content_type_content_types(); + if (isset($types[$subtype])) { + return $types[$subtype]; + } +} + +/** + * Return all field content types available. + */ +function ctools_entity_form_field_content_type_content_types() { + // This will hold all the individual field content types. + $types = &drupal_static(__FUNCTION__); + if (isset($types)) { + return $types; + } + + $types = array(); + $content_types = array(); + $entities = entity_get_info(); + + foreach ($entities as $entity_type => $entity) { + foreach ($entity['bundles'] as $type => $bundle) { + foreach (field_info_instances($entity_type, $type) as $field_name => $field) { + if (!isset($types[$entity_type . ':' . $field_name])) { + $types[$entity_type . ':' . $field_name] = array( + 'category' => t('Form'), + 'icon' => 'icon_field.png', + 'title' => t('Field form: @widget_label', array( + '@widget_label' => t($field['label']), + )), + 'description' => t('Field on the referenced entity.'), + ); + } + $content_types[$entity_type . ':' . $field_name]['types'][$type] = $bundle['label']; + } + } + } + + if (module_exists('field_group')) { + foreach ($entities as $entity_type => $entity) { + foreach ($entity['bundles'] as $type => $bundle) { + if ($group_info = field_group_info_groups($entity_type, $type, "form")) { + foreach ($group_info as $group_name => $group) { + if (!isset($types[$entity_type . ':' . $group_name])) { + $types[$entity_type . ':' . $group_name] = array( + 'category' => t('Form'), + 'icon' => 'icon_field.png', + 'title' => t('Group form: @widget_label', array('@widget_label' => $group->label)), + 'description' => t('Field group on the referenced entity.'), + ); + } + $content_types[$entity_type . ':' . $group_name]['types'][$type] = $bundle['label']; + } + } + } + } + } + + // Create the required context for each field related to the bundle types. + foreach ($types as $key => $field_content_type) { + list($entity_type, $field_name) = explode(':', $key, 2); + $types[$key]['required context'] = new ctools_context_required(t(ucfirst($entity_type)), $entity_type, array( + 'form' => array('form'), + 'type' => array_keys($content_types[$key]['types']), + )); + unset($content_types[$key]['types']); + } + return $types; +} + +/** +* Render the custom content type. +*/ +function ctools_entity_form_field_content_type_render($subtype, $conf, $panel_args, $context) { + if (empty($context) || empty($context->data)) { + return; + } + + // Get a shortcut to the entity. + $entity = $context->data; + list($entity_type, $field_name) = explode(':', $subtype, 2); + + // Load the entity type's information for this field. + $ids = entity_extract_ids($entity_type, $entity); + $field = field_info_instance($entity_type, $field_name, $ids[2]); + + // Check for field groups. + if (empty($field) && module_exists('field_group')) { + $groups = field_group_info_groups($entity_type, $entity->type, "form"); + $group = !empty($groups[$field_name]) ? $groups[$field_name] : NULL; + } + + // Do not render if the entity type does not have this field or group. + if (empty($field) && empty($group)) { + return; + } + + $block = new stdClass(); + if (isset($context->form)) { + $block->content = array(); + if (!empty($field)) { + $block->content[$field_name] = $context->form[$field_name]; + unset($context->form[$field_name]); + } + else { + // Pre-render the form to populate field groups. + if (isset($context->form['#pre_render'])) { + foreach ($context->form['#pre_render'] as $function) { + if (function_exists($function)) { + $context->form = $function($context->form); + } + } + unset($context->form['#pre_render']); + } + + $block->content[$field_name] = $context->form[$field_name]; + unset($context->form[$field_name]); + } + } + else { + $block->content = t('Entity info.'); + } + + return $block; +} + +/** +* Returns the administrative title for a type. +*/ +function ctools_entity_form_field_content_type_admin_title($subtype, $conf, $context) { + list($entity_type, $field_name) = explode(':', $subtype, 2); + + if (!empty($context->restrictions)) { + $field = field_info_instance($entity_type, $field_name, $context->restrictions['type'][0]); + } + else { + $field = array('label' => $subtype); + } + + return t('"@s" @field form', array('@s' => $context->identifier, '@field' => $field['label'])); +} + +function ctools_entity_form_field_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to have context setting. + return $form; +} diff --git a/sites/all/modules/ctools/plugins/content_types/form/form.inc b/sites/all/modules/ctools/plugins/content_types/form/form.inc new file mode 100644 index 000000000..73f7c7801 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/form/form.inc @@ -0,0 +1,62 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + // only provides a single content type + 'single' => TRUE, + 'render last' => TRUE, + 'title' => t('General form'), + 'icon' => 'icon_form.png', + 'description' => t('Everything in the form that is not displayed by other content.'), + 'required context' => new ctools_context_required(t('Form'), 'form'), + 'category' => t('Form'), +); + +/** + * Output function for the 'node' content type. Outputs a node + * based on the module and delta supplied in the configuration. + */ +function ctools_form_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = 'form'; + + if (isset($context->form)) { + if (isset($context->form['#pre_render'])) { + foreach ($context->form['#pre_render'] as $function) { + if (function_exists($function)) { + $context->form = $function($context->form); + } + } + unset($context->form['#pre_render']); + } + + $block->title = $context->form_title; + $block->content = array(); + foreach (element_children($context->form) as $element) { + $block->content[$element] = $context->form[$element]; + unset($context->form[$element]); + } + + $block->delta = $context->form_id; + } + else { + $block->title = t('Form'); + $block->content = t('Form goes here.'); + $block->delta = 'unknown'; + } + + return $block; +} + +function ctools_form_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" base form', array('@s' => $context->identifier)); +} + +function ctools_form_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to override title + // and stuff. + return $form; +} diff --git a/sites/all/modules/ctools/plugins/content_types/form/icon_form.png b/sites/all/modules/ctools/plugins/content_types/form/icon_form.png Binary files differnew file mode 100644 index 000000000..f0417cb65 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/form/icon_form.png diff --git a/sites/all/modules/ctools/plugins/content_types/node/icon_node.png b/sites/all/modules/ctools/plugins/content_types/node/icon_node.png Binary files differnew file mode 100644 index 000000000..f0417cb65 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node/icon_node.png diff --git a/sites/all/modules/ctools/plugins/content_types/node/node.inc b/sites/all/modules/ctools/plugins/content_types/node/node.inc new file mode 100644 index 000000000..7e77194c9 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node/node.inc @@ -0,0 +1,251 @@ +<?php + +/** + * @file + * Plugin to handle the 'node' content type which allows individual nodes + * to be embedded into a panel. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Existing node'), + 'single' => TRUE, + 'defaults' => array( + 'nid' => '', + 'links' => TRUE, + 'leave_node_title' => FALSE, + 'identifier' => '', + 'build_mode' => 'teaser', + ), + 'icon' => 'icon_node.png', + 'description' => t('Add a node from your site as content.'), + 'category' => t('Custom'), + 'top level' => TRUE, + 'js' => array('misc/autocomplete.js'), +); + +/** + * Output function for the 'node' content type. + * + * Outputs a node based on the module and delta supplied in the configuration. + */ +function ctools_node_content_type_render($subtype, $conf, $panel_args) { + $nid = $conf['nid']; + $block = new stdClass(); + + foreach (explode('/', $_GET['q']) as $id => $arg) { + $nid = str_replace("%$id", $arg, $nid); + } + + foreach ($panel_args as $id => $arg) { + if (is_string($arg)) { + $nid = str_replace("@$id", $arg, $nid); + } + } + + // Support node translation + if (module_exists('translation')) { + if ($translations = module_invoke('translation', 'node_get_translations', $nid)) { + if (isset($translations[$GLOBALS['language']->language])) { + $nid = $translations[$GLOBALS['language']->language]->nid; + } + } + } + + if (!is_numeric($nid)) { + return; + } + + $node = node_load($nid); + if (!node_access('view', $node)) { + return; + } + + // Don't store viewed node data on the node, this can mess up other + // views of the node. + $node = clone($node); + + $block->module = 'node'; + $block->delta = $node->nid; + + // Set block->title to the plain node title, then additionally set block->title_link to + // the node url if required. The actual link is rendered in ctools_content_render(). + $block->title = check_plain($node->title); + if (!empty($conf['link_node_title'])) { + $block->title_link = 'node/' . $node->nid; + } + + if (empty($conf['leave_node_title'])) { + $node->title = NULL; + } + + if (!empty($conf['identifier'])) { + $node->ctools_template_identifier = $conf['identifier']; + } + + // Handle existing configurations with the deprecated 'teaser' option. + if (isset($conf['teaser'])) { + $conf['build_mode'] = $conf['teaser'] ? 'teaser' : 'full'; + } + + $block->content = node_view($node, $conf['build_mode']); + + // Hide links if they've been suppressed. + if (empty($conf['links'])) { + $block->content['links']['#access'] = FALSE; + } + + return $block; +} + +/** + * The form to add or edit a node as content. + */ +function ctools_node_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + + $form['leave_node_title'] = array( + '#type' => 'checkbox', + '#default_value' => !empty($conf['leave_node_title']), + '#title' => t('Leave node title'), + '#description' => t('Advanced: if checked, do not touch the node title; this can cause the node title to appear twice unless your theme is aware of this.'), + ); + + $form['link_node_title'] = array( + '#type' => 'checkbox', + '#default_value' => !empty($conf['link_node_title']), + '#title' => t('Link the node title to the node'), + '#description' => t('Check this box if you would like your pane title to link to the node.'), + ); + + + if ($form_state['op'] == 'add') { + $form['nid'] = array( + '#prefix' => '<div class="no-float">', + '#title' => t('Enter the title or NID of a node'), + '#description' => t('To use a NID from the URL, you may use %0, %1, ..., %N to get URL arguments. Or use @0, @1, @2, ..., @N to use arguments passed into the panel.'), + '#type' => 'textfield', + '#maxlength' => 512, + '#autocomplete_path' => 'ctools/autocomplete/node', + '#weight' => -10, + '#suffix' => '</div>', + ); + } + else { + $form['nid'] = array( + '#type' => 'value', + '#value' => $conf['nid'], + ); + } + + $form['links'] = array( + '#type' => 'checkbox', + '#default_value' => $conf['links'], + '#title' => t('Include node links for "add comment", "read more" etc.'), + ); + + $form['identifier'] = array( + '#type' => 'textfield', + '#default_value' => !empty($conf['identifier']) ? $conf['identifier'] : '', + '#title' => t('Template identifier'), + '#description' => t('This identifier will be added as a template suggestion to display this node: node--panel--IDENTIFIER.tpl.php. Please see the Drupal theming guide for information about template suggestions.'), + ); + + $entity = entity_get_info('node'); + $build_mode_options = array(); + foreach ($entity['view modes'] as $mode => $option) { + $build_mode_options[$mode] = $option['label']; + } + + // Handle existing configurations with the deprecated 'teaser' option. + // Also remove the teaser key from the form_state. + if (isset($conf['teaser']) || !isset($conf['build_mode'])) { + unset($form_state['conf']['teaser']); + $conf['build_mode'] = $conf['teaser'] ? 'teaser' : 'full'; + } + $form['build_mode'] = array( + '#title' => t('Build mode'), + '#type' => 'select', + '#description' => t('Select a build mode for this node.'), + '#options' => $build_mode_options, + '#default_value' => $conf['build_mode'], + ); + return $form; +} + +/** + * Validate the node selection. + */ +function ctools_node_content_type_edit_form_validate(&$form, &$form_state) { + if ($form_state['op'] != 'add') { + return; + } + + $nid = $form_state['values']['nid']; + $preg_matches = array(); + $match = preg_match('/\[id: (\d+)\]/', $nid, $preg_matches); + if (!$match) { + $match = preg_match('/^id: (\d+)/', $nid, $preg_matches); + } + + if ($match) { + $nid = $preg_matches[1]; + } + if (is_numeric($nid)) { + $node = db_query('SELECT nid, status FROM {node} WHERE nid = :nid', array(':nid' => $nid))->fetchObject(); + } + else { + $node = db_query('SELECT nid, status FROM {node} WHERE LOWER(title) = LOWER(:title)', array(':title' => $nid))->fetchObject(); + } + if ($node) { + $form_state['values']['nid'] = $node->nid; + } + + if (!($node || preg_match('/^[@%]\d+$/', $nid)) || + // Do not allow unpublished nodes to be selected by unprivileged users + (empty($node->status) && !user_access('administer nodes'))) { + form_error($form['nid'], t('Invalid node')); + } +} + +/** + * Validate the node selection. + */ +function ctools_node_content_type_edit_form_submit($form, &$form_state) { + foreach (array('nid', 'links', 'leave_node_title', 'link_node_title', 'identifier', 'build_mode') as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +} + +/** + * Returns the administrative title for a node. + */ +function ctools_node_content_type_admin_title($subtype, $conf) { + if (!is_numeric($conf['nid'])) { + return t('Node loaded from @var', array('@var' => $conf['nid'])); + } + + $node = node_load($conf['nid']); + if ($node) { + if (!empty($node->status) || user_access('administer nodes')) { + return check_plain($node->title); + } + else { + return t('Unpublished node @nid', array('@nid' => $conf['nid'])); + } + } + else { + return t('Deleted/missing node @nid', array('@nid' => $conf['nid'])); + } +} + +/** + * Display the administrative information for a node pane. + */ +function ctools_node_content_type_admin_info($subtype, $conf) { + // Just render the node. + return ctools_node_content_type_render($subtype, $conf, array()); +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_context/icon_node.png b/sites/all/modules/ctools/plugins/content_types/node_context/icon_node.png Binary files differnew file mode 100644 index 000000000..f0417cb65 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_context/icon_node.png diff --git a/sites/all/modules/ctools/plugins/content_types/node_context/node_attachments.inc b/sites/all/modules/ctools/plugins/content_types/node_context/node_attachments.inc new file mode 100644 index 000000000..380e26043 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_context/node_attachments.inc @@ -0,0 +1,44 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'title' => t('Attached files'), + 'icon' => 'icon_node.png', + 'description' => t('A list of files attached to the node.'), + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'category' => t('Node'), +); + +function ctools_node_attachments_content_type_render($subtype, $conf, $panel_args, $context) { + $node = isset($context->data) ? clone($context->data) : NULL; + $block = new stdClass(); + $block->module = 'attachments'; + + $block->title = t('Attached files'); + if ($node) { + if (!empty($node->files)) { + $block->content = theme('upload_attachments', $node->files); + } + $block->delta = $node->nid; + } + else { + $block->content = t('Attached files go here.'); + $block->delta = 'unknown'; + } + + return $block; +} + +function ctools_node_attachments_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" attachments', array('@s' => $context->identifier)); +} + +function ctools_node_attachments_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to have context setting. + return $form; +} + diff --git a/sites/all/modules/ctools/plugins/content_types/node_context/node_author.inc b/sites/all/modules/ctools/plugins/content_types/node_context/node_author.inc new file mode 100644 index 000000000..e98ce5acc --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_context/node_author.inc @@ -0,0 +1,71 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'title' => t('Node author'), + 'icon' => 'icon_node.png', + 'description' => t('The author of the referenced node.'), + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'category' => t('Node'), + 'defaults' => array( + 'link' => TRUE, + ), +); + +/** + * Render the custom content type. + */ +function ctools_node_author_content_type_render($subtype, $conf, $panel_args, $context) { + if (empty($context) || empty($context->data)) { + return; + } + + // Get a shortcut to the node. + $node = $context->data; + $user = user_load($node->uid); + + // Build the content type block. + $block = new stdClass(); + $block->module = 'node_author'; + $block->title = t('Author'); + $block->content = !empty($conf['link']) ? theme('username', array('account' => $user, 'link_path' => 'user/' . $node->uid)) : check_plain(format_username($node)); + $block->delta = $node->nid; + + return $block; +} + +/** + * Returns an edit form for custom type settings. + */ +function ctools_node_author_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + + $form['link'] = array( + '#title' => t('Link to author profile'), + '#type' => 'checkbox', + '#default_value' => $conf['link'], + '#description' => t('Check here to link to the node author profile.'), + ); + return $form; +} + +/** + * Submit handler for the custom type settings form. + */ +function ctools_node_author_content_type_edit_form_submit($form, &$form_state) { + // Copy everything from our defaults. + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +} + +/** + * Returns the administrative title for a type. + */ +function ctools_node_author_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" author', array('@s' => $context->identifier)); +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_context/node_body.inc b/sites/all/modules/ctools/plugins/content_types/node_context/node_body.inc new file mode 100644 index 000000000..3e69560a2 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_context/node_body.inc @@ -0,0 +1,40 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'title' => t('Node body'), + 'icon' => 'icon_node.png', + 'description' => t('The body of the referenced node.'), + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'category' => t('Node'), + 'no ui' => TRUE, +); + +/** + * Render the custom content type. + */ +function ctools_node_body_content_type_render($subtype, $conf, $panel_args, $context) { + $plugin = ctools_get_content_type('entity_field'); + $conf['formatter'] = 'text_default'; + $conf['formatter_settings'] = array(); + return $plugin['render callback']('node:body', $conf, $panel_args, $context); +} + +/** + * Returns an edit form for custom type settings. + */ +function ctools_node_body_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to have context setting. + return $form; +} + +/** + * Returns the administrative title for a type. + */ +function ctools_node_body_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" body', array('@s' => $context->identifier)); +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_context/node_book_children.inc b/sites/all/modules/ctools/plugins/content_types/node_context/node_book_children.inc new file mode 100644 index 000000000..5d017c5cd --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_context/node_book_children.inc @@ -0,0 +1,43 @@ +<?php + +if (module_exists('book')) { + /** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ + $plugin = array( + 'single' => TRUE, + 'title' => t('Book children'), + 'icon' => 'icon_node.png', + 'description' => t('The children menu the book the node belongs to.'), + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'category' => t('Node'), + ); +} + +function ctools_node_book_children_content_type_render($subtype, $conf, $panel_args, $context) { + $node = isset($context->data) ? clone($context->data) : NULL; + $block = new stdClass(); + $block->module = 'book_children'; + + $block->title = t('Book children'); + if ($node) { + $block->content = isset($node->book) ? book_children($node->book) : ''; + $block->delta = $node->nid; + } + else { + $block->content = t('Book children menu goes here.'); + $block->delta = 'unknown'; + } + + return $block; +} + +function ctools_node_book_children_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" book children', array('@s' => $context->identifier)); +} + +function ctools_node_book_children_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to have context setting. + return $form; +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_context/node_book_nav.inc b/sites/all/modules/ctools/plugins/content_types/node_context/node_book_nav.inc new file mode 100644 index 000000000..6c0d50df7 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_context/node_book_nav.inc @@ -0,0 +1,43 @@ +<?php + +if (module_exists('book')) { + /** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ + $plugin = array( + 'single' => TRUE, + 'title' => t('Book navigation'), + 'icon' => 'icon_node.png', + 'description' => t('The navigation menu the book the node belongs to.'), + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'category' => t('Node'), + ); +} + +function ctools_node_book_nav_content_type_render($subtype, $conf, $panel_args, $context) { + $node = isset($context->data) ? clone($context->data) : NULL; + $block = new stdClass(); + $block->module = 'book_nav'; + + $block->title = t('Book navigation'); + if ($node) { + $block->content = isset($node->book) ? theme('book_navigation', array('book_link' => $node->book)) : ''; + $block->delta = $node->nid; + } + else { + $block->content = t('Book navigation goes here.'); + $block->delta = 'unknown'; + } + + return $block; +} + +function ctools_node_book_nav_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" book navigation', array('@s' => $context->identifier)); +} + +function ctools_node_book_nav_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to have context setting. + return $form; +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_context/node_comment_form.inc b/sites/all/modules/ctools/plugins/content_types/node_context/node_comment_form.inc new file mode 100644 index 000000000..c21e7bc7f --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_context/node_comment_form.inc @@ -0,0 +1,79 @@ +<?php + +if (module_exists('comment')) { + /** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ + $plugin = array( + 'single' => TRUE, + 'title' => t('Comment form'), + 'icon' => 'icon_node.png', + 'description' => t('A form to add a new comment.'), + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'category' => t('Node'), + 'defaults' => array('anon_links' => FALSE), + ); +} + +function ctools_node_comment_form_content_type_render($subtype, $conf, $panel_args, $context) { + $node = isset($context->data) ? clone($context->data) : NULL; + $block = new stdClass(); + $block->module = 'comments'; + $block->delta = $node->nid; + + $block->title = t('Add comment'); + + if (empty($node)) { + $block->content = t('Comment form here.'); + } + else if ($node->comment == COMMENT_NODE_OPEN) { + if (user_access('post comments')) { + $comment = new stdClass(); + $comment->nid = $node->nid; + $comment->pid = NULL; + $form_state = array( + 'ctools comment alter' => TRUE, + 'node' => $node, + 'build_info' => array( + 'args' => array( + $comment, + ), + ), + ); + $block->content = drupal_build_form('comment_node_' . $node->type . '_form', $form_state); + } + else if (!empty($conf['anon_links'])) { + $block->content = theme('comment_post_forbidden', array('node' => $node)); + } + } + + return $block; +} + +function ctools_node_comment_form_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" comment form', array('@s' => $context->identifier)); +} + +function ctools_node_comment_form_content_type_edit_form($form, &$form_state) { + $form['anon_links'] = array( + '#type' => 'checkbox', + '#title' => t('Shows links to register or login.'), + '#description' => t('If anonymous comments are not allowed, this will display the register and login links.'), + '#default_value' => $form_state['conf']['anon_links'], + ); + return $form; +} + +function ctools_node_comment_form_content_type_edit_form_submit($form, &$form_state) { + // For each part of the form defined in the 'defaults' array set when you + // defined the content type, copy the value from the form into the array + // of items to be saved. We don't ever want to use + // $form_state['conf'] = $form_state['values'] because values contains + // buttons, form id and other items we don't want stored. CTools will handle + // the actual form submission. + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +} + diff --git a/sites/all/modules/ctools/plugins/content_types/node_context/node_comment_wrapper.inc b/sites/all/modules/ctools/plugins/content_types/node_context/node_comment_wrapper.inc new file mode 100644 index 000000000..8e25429f2 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_context/node_comment_wrapper.inc @@ -0,0 +1,117 @@ +<?php + +if (module_exists('comment')) { + /** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ + $plugin = array( + 'single' => TRUE, + 'title' => t('Comments and comment form.'), + 'icon' => 'icon_node.png', + 'description' => t('The comments and comment form for the referenced node.'), + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'category' => t('Node'), + 'defaults' => array( + 'mode' => variable_get('comment_default_mode', COMMENT_MODE_THREADED), + 'comments_per_page' => variable_get('comment_default_per_page', '50'), + ), + ); +} + +/** + * Render the node comments. + */ +function ctools_node_comment_wrapper_content_type_render($subtype, $conf, $panel_args, $context) { + $node = isset($context->data) ? clone($context->data) : NULL; + $block = new stdClass(); + $block->module = 'comments'; + $block->delta = $node->nid; + + $renderable = array( + '#theme' => 'comment_wrapper__node_' . $node->type, + '#node' => $node, + 'comments' => array(), + 'comment_form' => array(), + ); + + // Add in the comments. + if (($node->comment_count && user_access('access comments')) || user_access('administer comments')) { + $mode = variable_get('comment_default_mode_' . $node->type, COMMENT_MODE_THREADED); + $comments_per_page = variable_get('comment_default_per_page_' . $node->type, 50); + if ($cids = comment_get_thread($node, $mode, $comments_per_page)) { + $comments = comment_load_multiple($cids); + comment_prepare_thread($comments); + $build = comment_view_multiple($comments, $node); + $build['pager']['#theme'] = 'pager'; + $renderable['comments'] = $build; + } + } + + // Stuff in the comment form. + if ($node->comment == COMMENT_NODE_OPEN) { + if (user_access('post comments')) { + $comment = new stdClass(); + $comment->nid = $node->nid; + $comment->pid = NULL; + $form_state = array( + 'ctools comment alter' => TRUE, + 'node' => $node, + 'build_info' => array( + 'args' => array( + $comment, + ), + ), + ); + $renderable['comment_form'] = drupal_build_form('comment_node_' . $node->type . '_form', $form_state); + } + else if (!empty($conf['anon_links'])) { + $renderable['comment_form'] = theme('comment_post_forbidden', array('node' => $node)); + } + } + + $block->content = drupal_render($renderable); + + return $block; +} + +/** + * Returns an edit form for the comment wrapper. + */ +function ctools_node_comment_wrapper_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + $form['mode'] = array( + '#type' => 'select', + '#title' => t('Mode'), + '#default_value' => $conf['mode'], + '#options' => _comment_get_modes(), + '#weight' => 1, + ); + foreach (_comment_per_page() as $i) { + $options[$i] = t('!a comments per page', array('!a' => $i)); + } + $form['comments_per_page'] = array('#type' => 'select', + '#title' => t('Pager'), + '#default_value' => $conf['comments_per_page'], + '#options' => $options, + '#weight' => 3, + ); + return $form; +} + +/** + * Submit handler for the comment wrapper settings form. + */ +function ctools_node_comment_wrapper_content_type_edit_form_submit($form, &$form_state) { + // Copy everything from our defaults. + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +} + +/** + * Returns the administrative title. + */ +function ctools_node_comment_wrapper_content_type_admin_title($subtype, $conf, $context) { + return t('Comments and comment form'); +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_context/node_comments.inc b/sites/all/modules/ctools/plugins/content_types/node_context/node_comments.inc new file mode 100644 index 000000000..0f0033d2a --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_context/node_comments.inc @@ -0,0 +1,98 @@ +<?php + +if (module_exists('comment')) { + /** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ + $plugin = array( + 'single' => TRUE, + 'title' => t('Node comments'), + 'icon' => 'icon_node.png', + 'description' => t('The comments of the referenced node.'), + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'category' => t('Node'), + 'defaults' => array( + 'mode' => variable_get('comment_default_mode', COMMENT_MODE_THREADED), + 'comments_per_page' => variable_get('comment_default_per_page', '50'), + ), + ); +} + +function ctools_node_comments_content_type_render($subtype, $conf, $panel_args, $context) { + $node = isset($context->data) ? clone($context->data) : NULL; + $block = new stdClass(); + $block->module = 'comments'; + $block->delta = $node->nid; + + $block->title = t('Comments'); + if (empty($node)) { + $block->content = t('Node comments go here.'); + } + else if ($node->comment) { + $block->content = ctools_comment_render($node, $conf); + // Update the history table, stating that this user viewed this node. + node_tag_new($node); + } + + return $block; +} + +function ctools_node_comments_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + $form['mode'] = array( + '#type' => 'select', + '#title' => t('Mode'), + '#default_value' => $conf['mode'], + '#options' => _comment_get_modes(), + '#weight' => 1, + ); + foreach (_comment_per_page() as $i) { + $options[$i] = t('!a comments per page', array('!a' => $i)); + } + $form['comments_per_page'] = array('#type' => 'select', + '#title' => t('Pager'), + '#default_value' => $conf['comments_per_page'], + '#options' => $options, + '#weight' => 3, + ); + return $form; +} + +function ctools_node_comments_content_type_edit_form_submit($form, &$form_state) { + // Copy everything from our defaults. + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +} + +function ctools_node_comments_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" comments', array('@s' => $context->identifier)); +} + +/** + * This function is a somewhat stripped down version of comment_render + * that removes a bunch of cruft that we both don't need, and makes it + * difficult to modify this. + */ +function ctools_comment_render($node, $conf) { + $output = ''; + if (!user_access('access comments') || !$node->comment) { + return; + } + + $mode = $conf['mode']; + $comments_per_page = $conf['comments_per_page']; + + $cids = comment_get_thread($node, $mode, $comments_per_page); + $comments = comment_load_multiple($cids); + + if ($comments) { + drupal_add_css(drupal_get_path('module', 'comment') . '/comment.css'); + comment_prepare_thread($comments); + $build = comment_view_multiple($comments, $node); + $build['pager']['#theme'] = 'pager'; + return drupal_render($build); + } + return; +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_context/node_content.inc b/sites/all/modules/ctools/plugins/content_types/node_context/node_content.inc new file mode 100644 index 000000000..38c5b5744 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_context/node_content.inc @@ -0,0 +1,204 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'title' => t('Node content'), + 'icon' => 'icon_node.png', + 'description' => t('The content of the referenced node.'), + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'category' => t('Node'), + 'defaults' => array( + 'links' => TRUE, + 'no_extras' => TRUE, + 'override_title' => FALSE, + 'override_title_text' => '', + 'identifier' => '', + 'link' => TRUE, + 'leave_node_title' => FALSE, + 'build_mode' => 'teaser', + ), +); + +/** + * Render the node content. + */ +function ctools_node_content_content_type_render($subtype, $conf, $panel_args, $context) { + if (!empty($context) && empty($context->data)) { + return; + } + + $node = isset($context->data) ? clone($context->data) : NULL; + $block = new stdClass(); + $block->module = 'node'; + $block->delta = $node->nid; + + if (empty($node)) { + $block->delta = 'placeholder'; + $block->title = t('Node title.'); + $block->content = t('Node content goes here.'); + } + else { + if (!empty($conf['identifier'])) { + $node->ctools_template_identifier = $conf['identifier']; + } + + $block->title = $node->title; + if (empty($conf['leave_node_title'])) { + $node->title = NULL; + } + $block->content = ctools_node_content_render_node($node, $conf); + } + + if (!empty($conf['link']) && $node) { + $block->title_link = "node/$node->nid"; + } + + return $block; +} + +function ctools_node_content_render_node($node, $conf) { + if (empty($node->content)) { + // Copied from node_build_content() so we can fiddle with it as we render. + $node->content = array(); + + // The 'view' hook can be implemented to overwrite the default function + // to display nodes. + if (node_hook($node, 'view')) { + $node = node_invoke($node, 'view', $conf['build_mode']); + } + + // Build fields content. + // In case of a multiple view, node_view_multiple() already ran the + // 'prepare_view' step. An internal flag prevents the operation from running + // twice. + field_attach_prepare_view('node', array($node->nid => $node), $conf['build_mode']); + entity_prepare_view('node', array($node->nid => $node)); + $node->content += field_attach_view('node', $node, $conf['build_mode']); + + // Always display a read more link on teasers because we have no way + // to know when a teaser view is different than a full view. + $links = array(); + if ($conf['build_mode'] == 'teaser') { + $links['node-readmore'] = array( + 'title' => t('Read more'), + 'href' => 'node/' . $node->nid, + 'attributes' => array('rel' => 'tag', 'title' => strip_tags($node->title)) + ); + } + + $node->content['links'] = array( + '#theme' => 'links__node', + '#links' => $links, + '#attributes' => array('class' => array('links', 'inline')), + ); + + if (empty($conf['no_extras'])) { + // Allow modules to make their own additions to the node. + $langcode = $GLOBALS['language_content']->language; + module_invoke_all('node_view', $node, $conf['build_mode'], $langcode); + module_invoke_all('entity_view', $node, 'node', $conf['build_mode'], $langcode); + } + } + + // Set the proper node part, then unset unused $node part so that a bad + // theme can not open a security hole. + $content = $node->content; + + $content += array( + '#theme' => 'node', + '#node' => $node, + '#view_mode' => $conf['build_mode'], + '#language' => NULL, + ); + + // Add contextual links for this node, except when the node is already being + // displayed on its own page. Modules may alter this behavior (for example, + // to restrict contextual links to certain view modes) by implementing + // hook_node_view_alter(). + if (!empty($node->nid) && !($conf['build_mode'] == 'full' && node_is_page($node))) { + $content['#contextual_links']['node'] = array('node', array($node->nid)); + } + + // Allow modules to modify the structured node. + $type = 'node'; + drupal_alter(array('node_view', 'entity_view'), $content, $type); + + // Kill the links if not requested. + if (!$conf['links']) { + $content['links']['#access'] = FALSE; + } + + return $content; +} + +/** + * Returns an edit form for the custom type. + */ +function ctools_node_content_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + + $form['leave_node_title'] = array( + '#type' => 'checkbox', + '#default_value' => !empty($conf['leave_node_title']), + '#title' => t('Leave node title'), + '#description' => t('Advanced: if checked, do not touch the node title; this can cause the node title to appear twice unless your theme is aware of this.'), + ); + + $form['link'] = array( + '#title' => t('Link title to node'), + '#type' => 'checkbox', + '#default_value' => $conf['link'], + '#description' => t('Check here to make the title link to the node.'), + ); + $form['links'] = array( + '#type' => 'checkbox', + '#default_value' => $conf['links'], + '#title' => t('Include node links for "add comment", "read more" etc.'), + ); + + $form['no_extras'] = array( + '#type' => 'checkbox', + '#default_value' => $conf['no_extras'], + '#title' => t('No extras'), + '#description' => t('Check here to disable additions that modules might make to the node, such as file attachments and CCK fields; this should just display the basic teaser or body.'), + ); + + $form['identifier'] = array( + '#type' => 'textfield', + '#default_value' => $conf['identifier'], + '#title' => t('Template identifier'), + '#description' => t('This identifier will be added as a template suggestion to display this node: node--panel--IDENTIFIER.tpl.php. Please see the Drupal theming guide for information about template suggestions.'), + ); + + $entity = entity_get_info('node'); + $build_mode_options = array(); + foreach ($entity['view modes'] as $mode => $option) { + $build_mode_options[$mode] = $option['label']; + } + + $form['build_mode'] = array( + '#title' => t('Build mode'), + '#type' => 'select', + '#description' => t('Select a build mode for this node.'), + '#options' => $build_mode_options, + '#default_value' => $conf['build_mode'], + ); + + return $form; +} + +function ctools_node_content_content_type_edit_form_submit($form, &$form_state) { + // Copy everything from our defaults. + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +} + +function ctools_node_content_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" content', array('@s' => $context->identifier)); +} + diff --git a/sites/all/modules/ctools/plugins/content_types/node_context/node_created.inc b/sites/all/modules/ctools/plugins/content_types/node_context/node_created.inc new file mode 100644 index 000000000..06d14427b --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_context/node_created.inc @@ -0,0 +1,74 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'title' => t('Node created date'), + 'icon' => 'icon_node.png', + 'description' => t('The date the referenced node was created.'), + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'category' => t('Node'), + 'defaults' => array( + 'format' => 'small', + ), +); + +/** + * Render the custom content type. + */ +function ctools_node_created_content_type_render($subtype, $conf, $panel_args, $context) { + if (empty($context) || empty($context->data)) { + return; + } + + // Get a shortcut to the node. + $node = $context->data; + + // Build the content type block. + $block = new stdClass(); + $block->module = 'node_created'; + $block->title = t('Created date'); + $block->content = format_date($node->created, $conf['format']); + $block->delta = $node->nid; + + return $block; +} + +/** + * Returns an edit form for custom type settings. + */ +function ctools_node_created_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + $date_types = array(); + + foreach (system_get_date_types() as $date_type => $definition) { + $date_types[$date_type] = format_date(REQUEST_TIME, $date_type); + } + $form['format'] = array( + '#title' => t('Date format'), + '#type' => 'select', + '#options' => $date_types, + '#default_value' => $conf['format'], + ); + return $form; +} + +/** + * Submit handler for the custom type settings form. + */ +function ctools_node_created_content_type_edit_form_submit($form, &$form_state) { + // Copy everything from our defaults. + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +} + +/** + * Returns the administrative title for a type. + */ +function ctools_node_created_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" created date', array('@s' => $context->identifier)); +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_context/node_links.inc b/sites/all/modules/ctools/plugins/content_types/node_context/node_links.inc new file mode 100644 index 000000000..6096a44fb --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_context/node_links.inc @@ -0,0 +1,105 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'title' => t('Node links'), + 'icon' => 'icon_node.png', + 'description' => t('Node links of the referenced node.'), + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'category' => t('Node'), + 'defaults' => array( + 'override_title' => FALSE, + 'override_title_text' => '', + 'build_mode' => '', + 'identifier' => '', + 'link' => TRUE, + ), +); + +/** + * Output function for the 'node' content type. Outputs a node + * based on the module and delta supplied in the configuration. + */ +function ctools_node_links_content_type_render($subtype, $conf, $panel_args, $context) { + if (!empty($context) && empty($context->data)) { + return; + } + + $node = isset($context->data) ? clone($context->data) : NULL; + $block = new stdClass(); + $block->module = 'node'; + $block->delta = $node->nid; + + if (empty($node)) { + $block->delta = 'placeholder'; + $block->subject = t('Node title.'); + $block->content = t('Node links go here.'); + } + else { + if (!empty($conf['identifier'])) { + $node->panel_identifier = $conf['identifier']; + } + + $block->subject = $node->title; + node_build_content($node, $conf['build_mode']); + $block->content = $node->content['links']; + } + + if (!empty($conf['link']) && $node) { + $block->title_link = "node/$node->nid"; + } + return $block; +} + +/** + * Returns an edit form for the custom type. + */ +function ctools_node_links_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + + $form['link'] = array( + '#title' => t('Link title to node'), + '#type' => 'checkbox', + '#default_value' => $conf['link'], + '#description' => t('Check here to make the title link to the node.'), + ); + + $entity = entity_get_info('node'); + $build_mode_options = array(); + foreach ($entity['view modes'] as $mode => $option) { + $build_mode_options[$mode] = $option['label']; + } + + $form['build_mode'] = array( + '#title' => t('Build mode'), + '#type' => 'select', + '#description' => t('Select a build mode for this node.'), + '#options' => $build_mode_options, + '#default_value' => $conf['build_mode'], + ); + + $form['identifier'] = array( + '#type' => 'textfield', + '#default_value' => $conf['identifier'], + '#title' => t('Identifier'), + '#description' => t('Whatever is placed here will appear in @identifier, to help theme node links displayed on the panel', array('@identifier' => $node->panel_identifier)), + ); + + return $form; +} + +function ctools_node_links_content_type_edit_form_submit($form, &$form_state) { + // Copy everything from our defaults. + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +} + +function ctools_node_links_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" links', array('@s' => $context->identifier)); +} + diff --git a/sites/all/modules/ctools/plugins/content_types/node_context/node_terms.inc b/sites/all/modules/ctools/plugins/content_types/node_context/node_terms.inc new file mode 100644 index 000000000..f6e7aec33 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_context/node_terms.inc @@ -0,0 +1,205 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'title' => t('Node terms'), + 'icon' => 'icon_node.png', + 'description' => t('Taxonomy terms of the referenced node.'), + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'category' => t('Node'), + 'defaults' => array( + 'vid' => 0, + 'term_format' => 'term-links', + 'link' => TRUE, + 'term_delimiter' => ', ', + ), +); + +/** + * Render the node_terms content type. + */ +function ctools_node_terms_content_type_render($subtype, $conf, $panel_args, $context) { + if (empty($context) || empty($context->data)) { + return; + } + + // Get a shortcut to the node. + $node = $context->data; + + // Load all terms for this node from all vocabularies + $query = db_select('taxonomy_index', 't'); + $result = $query + ->fields('t') + ->condition('t.nid', $node->nid) + ->execute(); + + $tids = array(); + foreach ($result AS $term) { + $tids[] = $term->tid; + } + + // Get the real term objects + $term_objects = taxonomy_term_load_multiple($tids); + + $terms = array(); + + if (empty($conf['vid'])) { + // All terms. + foreach ($term_objects AS $term) { + $terms['taxonomy_term_' . $term->tid] = array( + 'title' => check_plain($term->name), + 'href' => 'taxonomy/term/' . $term->tid, + 'attributes' => array('rel' => 'tag', 'title' => strip_tags($term->description)) + ); + } + } + else { + // They want something special and custom, we'll have to do this ourselves. + foreach ($term_objects as $term) { + if ($term->vid == $conf['vid']) { + if ($conf['term_format'] == 'term-links') { + $terms['taxonomy_term_' . $term->tid] = array( + 'title' => $term->name, + 'href' => 'taxonomy/term/' . $term->tid, + 'attributes' => array('rel' => 'tag', 'title' => strip_tags($term->description)), + ); + } + elseif (empty($conf['link'])) { + $terms[] = check_plain($term->name); + } + else { + $terms[] = l($term->name, 'taxonomy/term/' . $term->tid, array('attributes' => array('rel' => 'tag', 'title' => strip_tags($term->description)))); + } + } + } + } + + $formatted_terms = ''; + switch ($conf['term_format']) { + case 'term-links': + drupal_alter('link', $terms, $node); + $formatted_terms = theme('links', array('links' => $terms)); + break; + + case 'ul': + $formatted_terms = theme('item_list', array('items' => $terms)); + break; + + case 'inline-delimited': + $delimiter = isset($conf['term_delimiter']) ? $conf['term_delimiter'] : ', '; + $processed_terms = array(); + foreach ($terms as $key => $term) { + if (is_string($term)) { + $processed_terms[$key] = $term; + } + else { + $terms[$key] = l($term['title'], $term['href'], $term); + } + } + + $formatted_terms = implode($delimiter, $processed_terms); + break; + } + + // Build the content type block. + $block = new stdClass(); + $block->module = 'node_terms'; + $block->delta = $node->nid; + $block->title = t('Terms'); + $block->content = $formatted_terms; + + return $block; +} + +/** + * Returns an edit form for node terms display settings. + * + * The first question is if they want to display all terms or restrict it to a + * specific taxonomy vocabulary. + * + * Then, they're presented with a set of radios to find out how they want the + * terms formatted, which can be either be via theme('links'), a regular item + * list (ul), or inline with a delimiter. Depending on which radio they + * choose, some other settings might appear. If they're doing either the ul or + * inline, we ask if they want the terms to appear as links or not. If they + * want it inline, we ask what delimiter they want to use. + */ +function ctools_node_terms_content_type_edit_form($form, &$form_state) { + ctools_include('dependent'); + + $conf = $form_state['conf']; + + $options = array(); + $options[0] = t('- All vocabularies -'); + foreach (taxonomy_get_vocabularies() as $vid => $vocabulary) { + $options[$vid] = $vocabulary->name; + } + $form['vid'] = array( + '#title' => t('Vocabulary'), + '#type' => 'select', + '#options' => $options, + '#default_value' => $conf['vid'], + '#description' => t('Optionally restrict the terms to a specific vocabulary, or allow terms from all vocabularies.'), + '#prefix' => '<div class="clearfix">', + '#suffix' => '</div>', + ); + + $form['term_format'] = array( + '#type' => 'radios', + '#title' => t('Term formatting'), + '#options' => array( + 'term-links' => t("Taxonomy links (uses theme('links'))"), + 'ul' => t('Unordered list'), + 'inline-delimited' => t('Inline, delimited'), + ), + '#default_value' => $conf['term_format'], + '#prefix' => '<div class="clearfix">', + '#suffix' => '</div>', + ); + + $form['link'] = array( + '#title' => t('Link to terms'), + '#type' => 'checkbox', + '#default_value' => $conf['link'], + '#description' => t('Check here to make the terms link to the term paths.'), + '#dependency' => array('radio:term_format' => array('inline-delimited', 'ul')), + '#prefix' => '<div class="clearfix">', + '#suffix' => '</div>', + ); + + $form['term_delimiter'] = array( + '#type' => 'textfield', + '#title' => t('Term delimiter'), + '#default_value' => $conf['term_delimiter'], + '#size' => 10, + '#dependency' => array('radio:term_format' => array('inline-delimited')), + ); + return $form; +} + +/** + * Submit handler for the custom type settings form. + */ +function ctools_node_terms_content_type_edit_form_submit($form, &$form_state) { + // Copy everything from our defaults. + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +} + +/** + * Returns the administrative title for a type. + */ +function ctools_node_terms_content_type_admin_title($subtype, $conf, $context) { + $placeholders['@s'] = $context->identifier; + if (!empty($conf['vid'])) { + $vocabulary = taxonomy_vocabulary_load($conf['vid']); + $placeholders['@vocabulary'] = $vocabulary->name; + return t('"@s" terms from @vocabulary', $placeholders); + } + return t('"@s" terms', $placeholders); +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_context/node_title.inc b/sites/all/modules/ctools/plugins/content_types/node_context/node_title.inc new file mode 100644 index 000000000..bec898256 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_context/node_title.inc @@ -0,0 +1,120 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'title' => t('Node title'), + 'icon' => 'icon_node.png', + 'description' => t('The title of the referenced node.'), + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'category' => t('Node'), + 'defaults' => array( + 'link' => TRUE, + 'markup' => 'none', + 'id' => '', + 'class' => '', + ), +); + +/** + * Render the custom content type. + */ +function ctools_node_title_content_type_render($subtype, $conf, $panel_args, $context) { + if (empty($context) || empty($context->data)) { + return; + } + + // Get a shortcut to the node. + $node = $context->data; + + // Load information about the node type. + $type = node_type_get_type($node); + + // Generate the title + $content = !empty($conf['link']) ? l($node->title, 'node/' . $node->nid) : check_plain($node->title); + + // Build any surrounding markup if so configured + if (isset($conf['markup']) && $conf['markup'] != 'none') { + $markup = '<' . $conf['markup']; + if (!empty($conf['id'])) { + $markup .= ' id="' . $conf['id'] . '"'; + } + if (!empty($conf['class'])) { + $markup .= ' class="' . $conf['class'] . '"'; + } + $markup .= '>' . $content . '</' . $conf['markup'] . '>' . "\n"; + $content = $markup; + } + + // Build the content type block. + $block = new stdClass(); + $block->module = 'node_title'; + $block->title = $type->title_label; + $block->content = $content; + $block->delta = $node->nid; + + return $block; +} + +/** + * Returns an edit form for custom type settings. + */ +function ctools_node_title_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + + $form['markup'] = array( + '#title' => t('Title tag'), + '#type' => 'select', + '#options' => array( + 'none' => t('- No tag -'), + 'h1' => t('h1'), + 'h2' => t('h2'), + 'h3' => t('h3'), + 'h4' => t('h4'), + 'h5' => t('h5'), + 'h6' => t('h6'), + 'div' => t('div'), + ), + '#default_value' => $conf['markup'], + ); + + $form['id'] = array( + '#title' => t('CSS id to use'), + '#type' => 'textfield', + '#default_value' => $conf['id'], + ); + + $form['class'] = array( + '#title' => t('CSS class to use'), + '#type' => 'textfield', + '#default_value' => $conf['class'], + ); + + $form['link'] = array( + '#title' => t('Link to node'), + '#type' => 'checkbox', + '#default_value' => $conf['link'], + '#description' => t('Check here to make the title link to the node.'), + ); + return $form; +} + +/** + * Submit handler for the custom type settings form. + */ +function ctools_node_title_content_type_edit_form_submit($form, &$form_state) { + // Copy everything from our defaults. + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +} + +/** + * Returns the administrative title for a type. + */ +function ctools_node_title_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" title', array('@s' => $context->identifier)); +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_context/node_type_desc.inc b/sites/all/modules/ctools/plugins/content_types/node_context/node_type_desc.inc new file mode 100644 index 000000000..f2005d08b --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_context/node_type_desc.inc @@ -0,0 +1,47 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'title' => t('Node type description'), + 'icon' => 'icon_node.png', + 'description' => t('Node type description.'), + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'category' => t('Node'), +); + +/** + * Output function for the 'node' content type. Outputs a node + * based on the module and delta supplied in the configuration. + */ +function ctools_node_type_desc_content_type_render($subtype, $conf, $panel_args, $context) { + $node = isset($context->data) ? clone($context->data) : NULL; + $block = new stdClass(); + $block->module = 'node_type'; + + if ($node) { + $type = node_type_get_type($node); + $block->title = $type->name; + $block->content = filter_xss_admin($type->description); + $block->delta = $node->type; + } + else { + $block->title = t('Node type description'); + $block->content = t('Node type description goes here.'); + $block->delta = 'unknown'; + } + + return $block; +} + +function ctools_node_type_desc_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" type description', array('@s' => $context->identifier)); +} + +function ctools_node_type_desc_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to have context setting. + return $form; +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_context/node_updated.inc b/sites/all/modules/ctools/plugins/content_types/node_context/node_updated.inc new file mode 100644 index 000000000..60ac4b545 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_context/node_updated.inc @@ -0,0 +1,75 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'title' => t('Node last updated date'), + 'icon' => 'icon_node.png', + 'description' => t('The date the referenced node was last updated.'), + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'category' => t('Node'), + 'defaults' => array( + 'format' => 'small', + ), +); + +/** + * Render the custom content type. + */ +function ctools_node_updated_content_type_render($subtype, $conf, $panel_args, $context) { + if (empty($context) || empty($context->data) || empty($context->data->nid)) { + return; + } + + // Get a shortcut to the node. + $node = $context->data; + + // Build the content type block. + $block = new stdClass(); + $block->module = 'node_updated'; + $block->title = t('Last updated date'); + $block->content = format_date(!empty($node->changed) ? $node->changed : $node->created, $conf['format']); + $block->delta = $node->nid; + + return $block; +} + +/** + * Returns an edit form for custom type settings. + */ +function ctools_node_updated_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + $date_types = array(); + + foreach (system_get_date_types() as $date_type => $definition) { + $date_types[$date_type] = format_date(REQUEST_TIME, $date_type); + } + + $form['format'] = array( + '#title' => t('Date format'), + '#type' => 'select', + '#options' => $date_types, + '#default_value' => $conf['format'], + ); + return $form; +} + +/** + * Submit handler for the custom type settings form. + */ +function ctools_node_updated_content_type_edit_form_submit($form, &$form_state) { + // Copy everything from our defaults. + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +} + +/** + * Returns the administrative title for a type. + */ +function ctools_node_updated_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" last updated date', array('@s' => $context->identifier)); +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_form/icon_node_form.png b/sites/all/modules/ctools/plugins/content_types/node_form/icon_node_form.png Binary files differnew file mode 100644 index 000000000..f0417cb65 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_form/icon_node_form.png diff --git a/sites/all/modules/ctools/plugins/content_types/node_form/node_form_attachments.inc b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_attachments.inc new file mode 100644 index 000000000..1e248f500 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_attachments.inc @@ -0,0 +1,51 @@ +<?php + +if (module_exists('upload')) { + /** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ + $plugin = array( + 'single' => TRUE, + 'icon' => 'icon_node_form.png', + 'title' => t('Node form file attachments'), + 'description' => t('File attachments on the Node form.'), + 'required context' => new ctools_context_required(t('Form'), 'node_form'), + 'category' => t('Form'), + ); +} + +function ctools_node_form_attachments_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('node_form'); + + $block->title = t('Attach files'); + $block->delta = 'url-path-options'; + + if (isset($context->form)) { + if (isset($context->form['attachments'])) { + $block->content = $context->form['attachments']; + if (isset($block->content['attachments']['#group'])) { + unset($block->content['attachments']['#pre_render']); + unset($block->content['attachments']['#theme_wrappers']); + $block->content['attachments']['#type'] = ''; + } + // Set access to false on the original rather than removing so that + // vertical tabs doesn't clone it. I think this is due to references. + $context->form['attachments']['#access'] = FALSE; + } + } + else { + $block->content = t('Attach files.'); + } + return $block; +} + +function ctools_node_form_attachments_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" node form attach files', array('@s' => $context->identifier)); +} + +function ctools_node_form_attachments_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to have context setting. + return $form; +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_form/node_form_author.inc b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_author.inc new file mode 100644 index 000000000..350df40a9 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_author.inc @@ -0,0 +1,52 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'icon' => 'icon_node_form.png', + 'title' => t('Node form author information'), + 'description' => t('Author information on the Node form.'), + 'required context' => new ctools_context_required(t('Form'), 'node_form'), + 'category' => t('Form'), +); + +function ctools_node_form_author_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('node_form'); + + $block->title = t('Authoring information'); + $block->delta = 'author-options'; + + if (isset($context->form)) { + if (!empty($context->form['author'])) { + $block->content['author'] = $context->form['author']; + if (isset($block->content['author']['#group'])) { + unset($block->content['author']['#pre_render']); + unset($block->content['author']['#theme_wrappers']); + $block->content['author']['#type'] = ''; + $block->content['author']['name']['#size'] /= 2; + $block->content['author']['date']['#size'] /= 2; + } + + // Set access to false on the original rather than removing so that + // vertical tabs doesn't clone it. I think this is due to references. + $context->form['author']['#access'] = FALSE; + } + } + else { + $block->content = t('Authoring information.'); + } + return $block; +} + +function ctools_node_form_author_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" node form author information', array('@s' => $context->identifier)); +} + +function ctools_node_form_author_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to have context setting. + return $form; +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_form/node_form_book.inc b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_book.inc new file mode 100644 index 000000000..ad19590f1 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_book.inc @@ -0,0 +1,50 @@ +<?php + +if (module_exists('book')) { + /** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ + $plugin = array( + 'single' => TRUE, + 'icon' => 'icon_node_form.png', + 'title' => t('Node form book options'), + 'description' => t('Book options for the node.'), + 'required context' => new ctools_context_required(t('Form'), 'node_form'), + 'category' => t('Form'), + ); +} + +function ctools_node_form_book_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('node_form'); + + $block->title = t('Book outline'); + $block->delta = 'book-outline'; + + if (isset($context->form)) { + if (isset($context->form['book'])) { + $block->content['book'] = $context->form['book']; + unset($block->content['book']['#pre_render']); + unset($block->content['book']['#theme_wrappers']); + $block->content['book']['#type'] = ''; + + // Set access to false on the original rather than removing so that + // vertical tabs doesn't clone it. I think this is due to references. + $context->form['book']['#access'] = FALSE; + } + } + else { + $block->content = t('Book options.'); + } + return $block; +} + +function ctools_node_form_book_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" node form book options', array('@s' => $context->identifier)); +} + +function ctools_node_form_book_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to have context setting. + return $form; +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_form/node_form_buttons.inc b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_buttons.inc new file mode 100644 index 000000000..b7ac9841d --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_buttons.inc @@ -0,0 +1,43 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'icon' => 'icon_node_form.png', + 'title' => t('Node form submit buttons'), + 'description' => t('Submit buttons for the node form.'), + 'required context' => new ctools_context_required(t('Form'), 'node_form'), + 'category' => t('Form'), +); + +function ctools_node_form_buttons_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('node_form'); + + $block->title = ''; + $block->delta = 'buttons'; + + if (isset($context->form)) { + $block->content = array(); + foreach (array('actions', 'form_token', 'form_build_id', 'form_id') as $element) { + $block->content[$element] = isset($context->form[$element]) ? $context->form[$element] : NULL; + unset($context->form[$element]); + } + } + else { + $block->content = t('Node form buttons.'); + } + return $block; +} + +function ctools_node_form_buttons_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" node form submit buttons', array('@s' => $context->identifier)); +} + +function ctools_node_form_buttons_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to have context setting. + return $form; +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_form/node_form_comment.inc b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_comment.inc new file mode 100644 index 000000000..d0f137ae7 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_comment.inc @@ -0,0 +1,50 @@ +<?php + +if (module_exists('comment')) { + /** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ + $plugin = array( + 'single' => TRUE, + 'icon' => 'icon_node_form.png', + 'title' => t('Node form comment settings'), + 'description' => t('Comment settings on the Node form.'), + 'required context' => new ctools_context_required(t('Form'), 'node_form'), + 'category' => t('Form'), + ); +} + +function ctools_node_form_comment_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('node_form'); + + $block->title = t('Comment options'); + $block->delta = 'comment-options'; + + if (isset($context->form)) { + if (isset($context->form['comment_settings'])) { + $block->content['comment_settings'] = $context->form['comment_settings']; + unset($block->content['comment_settings']['#pre_render']); + unset($block->content['comment_settings']['#theme_wrappers']); + $block->content['comment_settings']['#type'] = ''; + + // Set access to false on the original rather than removing so that + // vertical tabs doesn't clone it. I think this is due to references. + $context->form['comment_settings']['#access'] = FALSE; + } + } + else { + $block->content = t('Comment options.'); + } + return $block; +} + +function ctools_node_form_comment_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" node form comment settings', array('@s' => $context->identifier)); +} + +function ctools_node_form_comment_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to have context setting. + return $form; +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_form/node_form_language.inc b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_language.inc new file mode 100644 index 000000000..2043c1c52 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_language.inc @@ -0,0 +1,41 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'icon' => 'icon_node_form.png', + 'title' => t('Node form languages'), + 'description' => t('The language selection form.'), + 'required context' => new ctools_context_required(t('Form'), 'node_form'), + 'category' => t('Form'), +); + +function ctools_node_form_language_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('node_form'); + + $block->delta = 'language-options'; + + if (isset($context->form)) { + if (!empty($context->form['language'])) { + $block->content['language'] = $context->form['language']; + unset($context->form['language']); + } + } + else { + $block->content = t('Node language form.'); + } + return $block; +} + +function ctools_node_form_language_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" node form language field', array('@s' => $context->identifier)); +} + +function ctools_node_form_language_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to have context setting. + return $form; +}
\ No newline at end of file diff --git a/sites/all/modules/ctools/plugins/content_types/node_form/node_form_log.inc b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_log.inc new file mode 100644 index 000000000..334ff5400 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_log.inc @@ -0,0 +1,47 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'icon' => 'icon_node_form.png', + 'title' => t('Node form revision log message'), + 'description' => t('Revision log message for the node.'), + 'required context' => new ctools_context_required(t('Form'), 'node_form'), + 'category' => t('Form'), +); + +function ctools_node_form_log_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('node_form'); + $block->title = t('Revision information'); + + if (isset($context->form)) { + if (isset($context->form['revision_information'])) { + $block->content['revision_information'] = $context->form['revision_information']; + unset($block->content['revision_information']['#pre_render']); + unset($block->content['revision_information']['#theme_wrappers']); + $block->content['revision_information']['#type'] = ''; + + // Set access to false on the original rather than removing so that + // vertical tabs doesn't clone it. I think this is due to references. + $context->form['revision_information']['#access'] = FALSE; + } + } + else { + $block->content = t('Revision information.'); + } + + return $block; +} + +function ctools_node_form_log_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" node form revision log', array('@s' => $context->identifier)); +} + +function ctools_node_form_log_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to have context setting. + return $form; +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_form/node_form_menu.inc b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_menu.inc new file mode 100644 index 000000000..906ade4d7 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_menu.inc @@ -0,0 +1,50 @@ +<?php + +if (module_exists('menu')) { + /** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ + $plugin = array( + 'single' => TRUE, + 'icon' => 'icon_node_form.png', + 'title' => t('Node form menu settings'), + 'description' => t('Menu settings on the Node form.'), + 'required context' => new ctools_context_required(t('Form'), 'node_form'), + 'category' => t('Form'), + ); +} + +function ctools_node_form_menu_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('node_form'); + + $block->title = t('Menu options'); + $block->delta = 'menu-options'; + + if (isset($context->form)) { + if (isset($context->form['menu'])) { + $block->content['menu'] = $context->form['menu']; + unset($block->content['menu']['#pre_render']); + unset($block->content['menu']['#theme_wrappers']); + $block->content['menu']['#type'] = ''; + + // Set access to false on the original rather than removing so that + // vertical tabs doesn't clone it. I think this is due to references. + $context->form['menu']['#access'] = FALSE; + } + } + else { + $block->content = t('Menu options.'); + } + return $block; +} + +function ctools_node_form_menu_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" node form menu settings', array('@s' => $context->identifier)); +} + +function ctools_node_form_menu_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to have context setting. + return $form; +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_form/node_form_path.inc b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_path.inc new file mode 100644 index 000000000..a1e3cba03 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_path.inc @@ -0,0 +1,51 @@ +<?php + +if (module_exists('path')) { + /** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ + $plugin = array( + 'single' => TRUE, + 'icon' => 'icon_node_form.png', + 'title' => t('Node form url path settings'), + 'description' => t('Publishing options on the Node form.'), + 'required context' => new ctools_context_required(t('Form'), 'node_form'), + 'category' => t('Form'), + ); +} + +function ctools_node_form_path_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('node_form'); + + $block->title = t('URL path options'); + $block->delta = 'url-path-options'; + + if (isset($context->form)) { + if (isset($context->form['path'])) { + $block->content['path'] = $context->form['path']; + unset($block->content['path']['#pre_render']); + unset($block->content['path']['#theme_wrappers']); + $block->content['path']['#type'] = ''; + $block->content['path']['alias']['#size'] /= 2; + + // Set access to false on the original rather than removing so that + // vertical tabs doesn't clone it. I think this is due to references. + $context->form['path']['#access'] = FALSE; + } + } + else { + $block->content = t('URL Path options.'); + } + return $block; +} + +function ctools_node_form_path_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" node form path options', array('@s' => $context->identifier)); +} + +function ctools_node_form_path_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to have context setting. + return $form; +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_form/node_form_publishing.inc b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_publishing.inc new file mode 100644 index 000000000..e73cff21b --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_publishing.inc @@ -0,0 +1,54 @@ +<?php + +/** + * @file + * Publishing options form for the node. This contains the basic settings + * like published, moderated, node revision, etc. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'title' => t('Node form publishing options'), + 'icon' => 'icon_node_form.png', + 'description' => t('Publishing options on the Node form.'), + 'required context' => new ctools_context_required(t('Form'), 'node_form'), + 'category' => t('Form'), +); + +function ctools_node_form_publishing_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + + $block->title = t('Publishing options'); + $block->module = t('node_form'); + $block->delta = 'publishing-options'; + + if (isset($context->form)) { + if (isset($context->form['options'])) { + $block->content['options'] = $context->form['options']; + unset($block->content['options']['#pre_render']); + unset($block->content['options']['#theme_wrappers']); + $block->content['options']['#type'] = ''; + + // Set access to false on the original rather than removing so that + // vertical tabs doesn't clone it. I think this is due to references. + $context->form['options']['#access'] = FALSE; + } + } + else { + $block->content = t('Publishing options.'); + } + return $block; +} + +function ctools_node_form_publishing_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" node form publishing options', array('@s' => $context->identifier)); +} + +function ctools_node_form_publishing_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to have context setting. + return $form; +} diff --git a/sites/all/modules/ctools/plugins/content_types/node_form/node_form_title.inc b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_title.inc new file mode 100644 index 000000000..f40d274de --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/node_form/node_form_title.inc @@ -0,0 +1,41 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'icon' => 'icon_node_form.png', + 'title' => t('Node form title field'), + 'description' => t('The node title form.'), + 'required context' => new ctools_context_required(t('Form'), 'node_form'), + 'category' => t('Form'), +); + +function ctools_node_form_title_content_type_render($subtype, $conf, $panel_args, &$context) { + $block = new stdClass(); + $block->module = t('node_form'); + + $block->delta = 'title-options'; + + if (isset($context->form)) { + if (!empty($context->form['title'])) { + $block->content['title'] = $context->form['title']; + unset($context->form['title']); + } + } + else { + $block->content = t('Node title form.'); + } + return $block; +} + +function ctools_node_form_title_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" node form title field', array('@s' => $context->identifier)); +} + +function ctools_node_form_title_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to have context setting. + return $form; +} diff --git a/sites/all/modules/ctools/plugins/content_types/page/page_actions.inc b/sites/all/modules/ctools/plugins/content_types/page/page_actions.inc new file mode 100644 index 000000000..c20c40822 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/page/page_actions.inc @@ -0,0 +1,32 @@ +<?php + +/** + * @file + * Plugin to handle the 'page_actions' content type which allows the local + * actions template variables to be embedded into a panel. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Actions'), + 'single' => TRUE, + 'icon' => 'icon_page.png', + 'description' => t('Add the action links (local tasks) as content.'), + 'category' => t('Page elements'), + 'render last' => TRUE, +); + +/** + * Output function for the 'page_actions' content type. + * + * Outputs the actions (local tasks) of the current page. + */ +function ctools_page_actions_content_type_render($subtype, $conf, $panel_args) { + $block = new stdClass(); + $block->content = theme('ctools_menu_local_actions_wrapper', array('links' => menu_local_actions())); + + return $block; +} diff --git a/sites/all/modules/ctools/plugins/content_types/page/page_breadcrumb.inc b/sites/all/modules/ctools/plugins/content_types/page/page_breadcrumb.inc new file mode 100644 index 000000000..f5a060eff --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/page/page_breadcrumb.inc @@ -0,0 +1,32 @@ +<?php + +/** + * @file + * Plugin to handle the 'page_breadcrumb' content type which allows the + * breadcrumb trail of the current page to be embedded into a panel. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Breadcrumb'), + 'single' => TRUE, + 'icon' => 'icon_page.png', + 'description' => t('Add the breadcrumb trail as content.'), + 'category' => t('Page elements'), + 'render last' => TRUE, +); + +/** + * Output function for the 'page_breadcrumb' content type. + * + * Outputs the breadcrumb for the current page. + */ +function ctools_page_breadcrumb_content_type_render($subtype, $conf, $panel_args) { + $block = new stdClass(); + $block->content = theme('breadcrumb', array('breadcrumb' => drupal_get_breadcrumb())); + + return $block; +} diff --git a/sites/all/modules/ctools/plugins/content_types/page/page_feed_icons.inc b/sites/all/modules/ctools/plugins/content_types/page/page_feed_icons.inc new file mode 100644 index 000000000..0dba317d8 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/page/page_feed_icons.inc @@ -0,0 +1,32 @@ +<?php + +/** + * @file + * Plugin to handle the 'page_feed_icons' content type which allows the + * feed_icons statement of the site to be embedded into a panel. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Feed icons'), + 'single' => TRUE, + 'icon' => 'icon_page.png', + 'description' => t('Add the site feed_icons statement as content.'), + 'category' => t('Page elements'), + 'render last' => TRUE, +); + +/** + * Output function for the 'page_feed_icons' content type. + * + * Outputs the feed_icons statement for the site. + */ +function ctools_page_feed_icons_content_type_render($subtype, $conf, $panel_args) { + $block = new stdClass(); + $block->content = drupal_get_feeds(); + + return $block; +} diff --git a/sites/all/modules/ctools/plugins/content_types/page/page_help.inc b/sites/all/modules/ctools/plugins/content_types/page/page_help.inc new file mode 100644 index 000000000..da1abe69f --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/page/page_help.inc @@ -0,0 +1,33 @@ +<?php + +/** + * @file + * Plugin to handle the 'page_help' content type which allows the + * help text of the current page to be embedded into a panel. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Help'), + 'single' => TRUE, + 'icon' => 'icon_page.png', + 'description' => t('Add the help text of the current page as content.'), + 'category' => t('Page elements'), + 'render last' => TRUE, +); + +/** + * Output function for the 'page_help' content type. + * + * Outputs the breadcrumb for the current page. + */ +function ctools_page_help_content_type_render($subtype, $conf, $panel_args) { + $block = new stdClass(); + $block->content = theme('help'); + + return $block; +} + diff --git a/sites/all/modules/ctools/plugins/content_types/page/page_logo.inc b/sites/all/modules/ctools/plugins/content_types/page/page_logo.inc new file mode 100644 index 000000000..c00ca5e88 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/page/page_logo.inc @@ -0,0 +1,37 @@ +<?php + +/** + * @file + * Plugin to handle the 'page_logo' content type which allows the + * logo of the site to be embedded into a panel. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Site logo'), + 'single' => TRUE, + 'icon' => 'icon_page.png', + 'description' => t('Add the logo trail as content.'), + 'category' => t('Page elements'), + 'render last' => TRUE, +); + +/** + * Output function for the 'page_logo' content type. + * + * Outputs the logo for the current page. + */ +function ctools_page_logo_content_type_render($subtype, $conf, $panel_args) { + $logo = theme_get_setting('logo'); + $block = new stdClass(); + + if (!empty($logo)) { + $image = '<img src="' . $logo . '" alt="' . t('Home') . '" />'; + $block->content = l($image, '', array('html' => TRUE, 'attributes' => array('rel' => 'home', 'id' => 'logo', 'title' => t('Home')))); + } + + return $block; +} diff --git a/sites/all/modules/ctools/plugins/content_types/page/page_messages.inc b/sites/all/modules/ctools/plugins/content_types/page/page_messages.inc new file mode 100644 index 000000000..e2fe37b35 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/page/page_messages.inc @@ -0,0 +1,33 @@ +<?php + +/** + * @file + * Plugin to handle the 'page_messages' content type which allows the + * status messages of the current page to be embedded into a panel. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Status messages'), + 'single' => TRUE, + 'icon' => 'icon_page.png', + 'description' => t('Add the status messages of the current page as content.'), + 'category' => t('Page elements'), + 'render last' => TRUE, +); + +/** + * Output function for the 'page_messages' content type. + * + * Outputs the breadcrumb for the current page. + */ +function ctools_page_messages_content_type_render($subtype, $conf, $panel_args) { + $block = new stdClass(); + $block->content = theme('status_messages'); + + return $block; +} + diff --git a/sites/all/modules/ctools/plugins/content_types/page/page_primary_links.inc b/sites/all/modules/ctools/plugins/content_types/page/page_primary_links.inc new file mode 100644 index 000000000..b1e3e0e3d --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/page/page_primary_links.inc @@ -0,0 +1,40 @@ +<?php + +/** + * @file + * Plugin to handle the 'page' content type which allows the standard page + * template variables to be embedded into a panel. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Primary navigation links'), + 'single' => TRUE, + 'icon' => 'icon_page.png', + 'description' => t('Add the primary_links (local tasks) as content.'), + 'category' => t('Page elements'), + 'render last' => TRUE, +); + +/** + * Output function for the 'page_primary_links' content type. + * + * Outputs the primary_links (local tasks) of the current page. + */ +function ctools_page_primary_links_content_type_render($subtype, $conf, $panel_args) { + $block = new stdClass(); + $block->content = theme('links', array('links' => menu_main_menu(), 'attributes' => array('class' => 'links primary-links'))); + + return $block; +} + +/** + * Returns an edit form for custom type settings. + */ +function ctools_page_primary_links_content_type_edit_form($form, &$form_state) { + // Empty so that we can have title override. + return $form; +} diff --git a/sites/all/modules/ctools/plugins/content_types/page/page_secondary_links.inc b/sites/all/modules/ctools/plugins/content_types/page/page_secondary_links.inc new file mode 100644 index 000000000..8c6d4dc9f --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/page/page_secondary_links.inc @@ -0,0 +1,40 @@ +<?php + +/** + * @file + * Plugin to handle the 'page' content type which allows the standard page + * template variables to be embedded into a panel. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Secondary navigation links'), + 'single' => TRUE, + 'icon' => 'icon_page.png', + 'description' => t('Add the secondary_links (local tasks) as content.'), + 'category' => t('Page elements'), + 'render last' => TRUE, +); + +/** + * Output function for the 'page_secondary_links' content type. + * + * Outputs the secondary_links (local tasks) of the current page. + */ +function ctools_page_secondary_links_content_type_render($subtype, $conf, $panel_args) { + $block = new stdClass(); + $block->content = theme('links', array('links' => menu_secondary_menu(), 'attributes' => array('class' => 'links secondary-links'))); + + return $block; +} + +/** + * Returns an edit form for custom type settings. + */ +function ctools_page_secondary_links_content_type_edit_form($form, &$form_state) { + // Empty so that we can have title override. + return $form; +} diff --git a/sites/all/modules/ctools/plugins/content_types/page/page_site_name.inc b/sites/all/modules/ctools/plugins/content_types/page/page_site_name.inc new file mode 100644 index 000000000..3053d451a --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/page/page_site_name.inc @@ -0,0 +1,68 @@ +<?php + +/** + * @file + * Plugin to handle the 'page_site_name' content type which allows the + * site_name of the site to be embedded into a panel. + */ + +/** + * Plugins are described by creating a $plugin array which will be used by the + * system that includes this file. + */ +$plugin = array( + 'title' => t('Site name'), + 'single' => TRUE, + 'icon' => 'icon_page.png', + 'description' => t('The name of the site, optionally links to the front page.'), + 'category' => t('Page elements'), + 'render last' => TRUE, + 'defaults' => array( + 'linked' => FALSE, + ), +); + +/** + * Settings form for the Site Name pane. + */ +function ctools_page_site_name_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + + $form['linked'] = array( + '#title' => t('Linked'), + '#description' => t('Link the site name to the home page.'), + '#type' => 'checkbox', + '#default_value' => isset($conf['linked']) ? $conf['linked'] : FALSE, + ); + + return $form; +} + +/** + * The submit form stores the data in $conf. + */ +function ctools_page_site_name_content_type_edit_form_submit($form, &$form_state) { + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + if (isset($form_state['values'][$key])) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } + } +} + +/** + * Output function for the 'page_site_name' content type. + * + * Outputs the site_name for the current page. + */ +function ctools_page_site_name_content_type_render($subtype, $conf, $panel_args) { + $block = new stdClass(); + + $block->content = filter_xss_admin(variable_get('site_name', 'Drupal')); + + // Optionally link the site name to the homepage. + if (!empty($conf['linked'])) { + $block->content = l($block->content, '<front>'); + } + + return $block; +} diff --git a/sites/all/modules/ctools/plugins/content_types/page/page_slogan.inc b/sites/all/modules/ctools/plugins/content_types/page/page_slogan.inc new file mode 100644 index 000000000..d5cba38b6 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/page/page_slogan.inc @@ -0,0 +1,32 @@ +<?php + +/** + * @file + * Plugin to handle the 'page_slogan' content type which allows the + * slogan of the site to be embedded into a panel. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Site slogan'), + 'single' => TRUE, + 'icon' => 'icon_page.png', + 'description' => t("Add the site's slogan as content."), + 'category' => t('Page elements'), + 'render last' => TRUE, +); + +/** + * Output function for the 'page_slogan' content type. + * + * Outputs the slogan for the current page. + */ +function ctools_page_slogan_content_type_render($subtype, $conf, $panel_args) { + $block = new stdClass(); + $block->content = filter_xss_admin(variable_get('site_slogan', '')); + + return $block; +} diff --git a/sites/all/modules/ctools/plugins/content_types/page/page_tabs.inc b/sites/all/modules/ctools/plugins/content_types/page/page_tabs.inc new file mode 100644 index 000000000..e88acd54f --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/page/page_tabs.inc @@ -0,0 +1,89 @@ +<?php + +/** + * @file + * Plugin to handle the 'page' content type which allows the standard page + * template variables to be embedded into a panel. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Tabs'), + 'single' => TRUE, + 'icon' => 'icon_page.png', + 'description' => t('Add the tabs (local tasks) as content.'), + 'category' => t('Page elements'), + 'render last' => TRUE, + 'defaults' => array( + 'type' => 'both', + 'id' => 'tabs', + ), +); + +/** + * Output function for the 'page_tabs' content type. + * + * Outputs the tabs (local tasks) of the current page. + */ +function ctools_page_tabs_content_type_render($subtype, $conf, $panel_args) { + $block = new stdClass(); + $menus = menu_local_tabs(); + + if (empty($menus['#secondary']) && empty($menus['#primary'])) { + return; + } + + switch ($conf['type']) { + case 'primary': + unset($menus['#secondary']); + break; + case 'secondary': + unset($menus['#primary']); + break; + } + if ($conf['id']) { + $menus['#theme_wrappers'][] = 'container'; + $menus['#attributes']['id'] = $conf['id']; + } + + $block->content = $menus; + + return $block; +} + + +function ctools_page_tabs_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + + $form['type'] = array( + '#title' => t('Tabs type'), + '#type' => 'select', + '#options' => array( + 'both' => t('Primary and secondary'), + 'primary' => t('Primary'), + 'secondary' => t('Secondary'), + ), + '#default_value' => $conf['type'], + ); + + $form['id'] = array( + '#title' => t('CSS id to use'), + '#type' => 'textfield', + '#default_value' => $conf['id'], + ); + return $form; +} + +/** + * The submit form stores the data in $conf. + */ +function ctools_page_tabs_content_type_edit_form_submit($form, &$form_state) { + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + if (isset($form_state['values'][$key])) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } + } +} diff --git a/sites/all/modules/ctools/plugins/content_types/page/page_title.inc b/sites/all/modules/ctools/plugins/content_types/page/page_title.inc new file mode 100644 index 000000000..cc091ab23 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/page/page_title.inc @@ -0,0 +1,121 @@ +<?php + +/** + * @file + * Plugin to handle the 'page' content type which allows the standard page + * template variables to be embedded into a panel. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'title' => t('Page title'), + 'icon' => 'icon_page.png', + 'description' => t('Add the page title as content.'), + 'category' => t('Page elements'), + 'defaults' => array( + 'markup' => 'h1', + 'class' => '', + 'id' => '', + ), +); + +/** + * Output function for the 'page_title' content type. + * + * Outputs the page title of the current page. + */ +function ctools_page_title_content_type_render($subtype, $conf, $panel_args) { + if (!drupal_get_title()) { + return; + } + // TODO: This should have a setting or something for the markup. + if (empty($conf['markup'])) { + $conf['markup'] = 'h1'; + } + + if (empty($conf['class'])) { + $conf['class'] = ''; + } + + if (empty($conf['id'])) { + $conf['id'] = ''; + } + + $token = ctools_set_callback_token('title', array('ctools_page_title_content_type_token', $conf['markup'], $conf['id'], $conf['class'])); + + $block = new stdClass(); + if ($token) { + $block->content = $token; + } + + return $block; +} + +function ctools_page_title_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + + $form['markup'] = array( + '#title' => t('Title tag'), + '#type' => 'select', + '#options' => array( + 'none' => t('- No tag -'), + 'h1' => t('h1'), + 'h2' => t('h2'), + 'h3' => t('h3'), + 'h4' => t('h4'), + 'h5' => t('h5'), + 'h6' => t('h6'), + 'div' => t('div'), + ), + '#default_value' => empty($conf['markup']) ? 'h1' : $conf['markup'], + ); + + $form['id'] = array( + '#title' => t('CSS id to use'), + '#type' => 'textfield', + '#default_value' => empty($conf['id']) ? '' : $conf['id'], + ); + + $form['class'] = array( + '#title' => t('CSS class to use'), + '#type' => 'textfield', + '#default_value' => empty($conf['class']) ? '' : $conf['class'], + ); + return $form; +} + +/** + * The submit form stores the data in $conf. + */ +function ctools_page_title_content_type_edit_form_submit($form, &$form_state) { + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + if (isset($form_state['values'][$key])) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } + } +} + +/** + * Variable token callback to properly render the page title, with markup. + */ +function ctools_page_title_content_type_token(&$variables, $tag, $id, $class) { + if ($tag == 'none') { + return drupal_get_title(); + } + + $output = '<' . $tag; + if ($id) { + $output .= ' id="' . $id . '"'; + } + + if ($class) { + $output .= ' class="' . $class . '"'; + } + + $output .= '>' . drupal_get_title() . '</' . $tag . '>' . "\n"; + return $output; +} diff --git a/sites/all/modules/ctools/plugins/content_types/search/icon_search.png b/sites/all/modules/ctools/plugins/content_types/search/icon_search.png Binary files differnew file mode 100644 index 000000000..3ad1deb65 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/search/icon_search.png diff --git a/sites/all/modules/ctools/plugins/content_types/search/search_form.inc b/sites/all/modules/ctools/plugins/content_types/search/search_form.inc new file mode 100644 index 000000000..2b6a322b1 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/search/search_form.inc @@ -0,0 +1,156 @@ +<?php + +if (module_exists('search')) { + /** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ + $plugin = array( + 'single' => TRUE, + 'title' => t('Advanced search form'), + 'icon' => 'icon_search.png', + 'description' => t('A search form with advanced options.'), + 'required context' => new ctools_context_optional(t('Keywords'), 'string'), + 'category' => t('Widgets'), + 'defaults' => array( + 'type' => 'node', + 'form' => 'advanced', + 'path_type' => 'default', + 'path' => '', + 'override_prompt' => FALSE, + 'prompt' => '', + ), + ); +} + +/** + * Render the custom content type. + */ +function ctools_search_form_content_type_render($subtype, $conf, $panel_args, $context) { + if (empty($context) || empty($context->data)) { + $keys = ''; + } + else { + $keys = $context->data; + } + + // Build the content type block. + $block = new stdClass(); + $block->module = 'search'; + $block->delta = 'form'; + $block->title = ''; + + switch ($conf['path_type']) { + default: + case 'default': + $path = 'search/' . $conf['type']; + break; + case 'same': + $path = $_GET['q']; + $path = str_replace($keys, '', $path); + break; + case 'custom': + $path = $conf['path']; + break; + } + + $prompt = $conf['override_prompt'] ? $conf['prompt'] : NULL; + + $form_state = array( + 'build_info' => array( + 'args' => array($path, $keys, $conf['type'], $prompt), + ), + ); + + module_load_include('inc', 'search', 'search.pages'); + + $block->content = drupal_build_form('search_form', $form_state); + if ($conf['form'] == 'simple' && isset($block->content['advanced'])) { + $block->content['advanced']['#access'] = FALSE; + } + + return $block; +} + +/** + * Returns an edit form for custom type settings. + */ +function ctools_search_form_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + + $types = array(); + foreach (search_get_info() as $module => $info) { + $types[$module] = $info['title']; + } + + $form['type'] = array( + '#type' => 'select', + '#title' => t('Search type'), + '#options' => $types, + '#default_value' => $conf['type'], + ); + + $form['form'] = array( + '#type' => 'select', + '#title' => t('Search form'), + '#options' => array( + 'simple' => t('Simple'), + 'advanced' => t('Advanced'), + ), + '#default_value' => $conf['form'], + '#description' => t('The advanced form may have additional options based upon the search type. For example the advanced content (node) search form will allow searching by node type and taxonomy term.'), + ); + + $form['path_type'] = array( + '#prefix' => '<div class="container-inline">', + '#type' => 'select', + '#title' => t('Path'), + '#options' => array( + 'default' => t('Default'), + 'same' => t('Same page'), + 'custom' => t('Custom'), + ), + '#default_value' => $conf['path_type'], + ); + + $form['path'] = array( + '#type' => 'textfield', + '#default_value' => $conf['path'], + '#dependency' => array('edit-path-type' => array('custom')), + '#suffix' => '</div>', + ); + + $form['override_prompt'] = array( + '#prefix' => '<div class="container-inline">', + '#type' => 'checkbox', + '#default_value' => $conf['override_prompt'], + '#title' => t('Override default prompt'), + ); + + $form['prompt'] = array( + '#type' => 'textfield', + '#default_value' => $conf['prompt'], + '#dependency' => array('edit-override-prompt' => array(1)), + '#suffix' => '</div>', + ); + return $form; +} + +/** + * Submit handler for search form. + */ +function ctools_search_form_content_type_edit_form_submit($form, &$form_state) { + // Copy everything from our defaults. + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +} + +/** + * Returns the administrative title for a type. + */ +function ctools_search_form_content_type_admin_title($subtype, $conf, $context) { + $info = search_get_info(); + $type = isset($info[$conf['type']]['title']) ? $info[$conf['type']]['title'] : t('Missing/broken type'); + return t('@type search form', array('@type' => $type)); +} diff --git a/sites/all/modules/ctools/plugins/content_types/search/search_result.inc b/sites/all/modules/ctools/plugins/content_types/search/search_result.inc new file mode 100644 index 000000000..32037bdf5 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/search/search_result.inc @@ -0,0 +1,204 @@ +<?php + +if (module_exists('search')) { + /** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ + $plugin = array( + 'single' => TRUE, + 'title' => t('Search results'), + 'icon' => 'icon_search.png', + 'description' => t('The results of a search using keywords.'), + 'required context' => new ctools_context_required(t('Keywords'), 'string'), + 'category' => t('Widgets'), + 'defaults' => array( + 'type' => 'node', + 'log' => TRUE, + 'override_empty' => FALSE, + 'empty_title' => '', + 'empty' => '', + 'empty_format' => filter_fallback_format(), + 'override_no_key' => FALSE, + 'no_key_title' => '', + 'no_key' => '', + 'no_key_format' => filter_fallback_format(), + ), + ); +} + +/** + * Render the custom content type. + */ +function ctools_search_result_content_type_render($subtype, $conf, $panel_args, $context) { + $search_info = search_get_info(); + if (empty($search_info[$conf['type']])) { + return; + } + $info = $search_info[$conf['type']]; + + $keys = NULL; + if (!empty($context) && isset($context->data)) { + $keys = $context->data; + } + + $conditions = NULL; + if (isset($info['conditions_callback']) && function_exists($info['conditions_callback'])) { + // Build an optional array of more search conditions. + $conditions = $info['conditions_callback']($keys); + } + + // Display nothing at all if no keywords were entered. + if (empty($keys) && empty($conditions)) { + if (!empty($conf['override_no_key'])) { + $block->title = $conf['no_key_title']; + $block->content = check_markup($conf['no_key'], $conf['no_key_format'], FALSE); + return $block; + } + return; + } + + // Build the content type block. + $block = new stdClass(); + $block->module = 'search'; + $block->delta = 'result'; + + $results = ''; + + // Only search if there are keywords or non-empty conditions. + if ($keys || !empty($conditions)) { + + // Collect the search results. + $results = search_data($keys, $info['module'], $conditions); + + // A workaround for ApacheSolr. + // @todo see http://drupal.org/node/1343142#comment-5495248 + // This workaround is to be removed when a better one can be written. + if (!empty($results['search_results']['#results'])) { + $results['#results'] = $results['search_results']['#results']; + } + } + + if (!empty($conf['log'])) { + // Log the search keys: + watchdog('search', 'Searched %type for %keys.', array('%keys' => $keys, '%type' => $info['title']), WATCHDOG_NOTICE, l(t('results'), $_GET['q'])); + } + + if (!empty($results['#results'])) { + $output = "<ol class=\"search-results $conf[type]-results\">\n"; + foreach ($results['#results'] as $result) { + $output .= theme('search_result', array('result' => $result, 'module' => $conf['type'])); + } + $output .= "</ol>\n"; + $output .= theme('pager', array('tags' => NULL)); + + $block->title = t('Search results'); + $block->content = $output; + } + else { + if (empty($conf['override_empty'])) { + $block->title = t('Your search yielded no results'); + $block->content = search_help('search#noresults', drupal_help_arg()); + } + else { + $block->title = $conf['empty_title']; + $block->content = check_markup($conf['empty'], $conf['empty_format'], FALSE); + } + } + + return $block; +} + +/** + * Returns an edit form for custom type settings. + */ +function ctools_search_result_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + + $types = array(); + foreach (search_get_info() as $module => $info) { + $types[$module] = $info['title']; + } + + $form['type'] = array( + '#type' => 'select', + '#title' => t('Search type'), + '#options' => $types, + '#default_value' => $conf['type'], + ); + + $form['log'] = array( + '#type' => 'checkbox', + '#default_value' => $conf['log'], + '#title' => t('Record a watchdog log entry when searches are made'), + ); + + $form['override_empty'] = array( + '#type' => 'checkbox', + '#default_value' => $conf['override_empty'], + '#title' => t('Override "no result" text'), + ); + + $form['empty_title'] = array( + '#title' => t('Title'), + '#type' => 'textfield', + '#default_value' => $conf['empty_title'], + '#dependency' => array('edit-override-empty' => array(1)), + ); + + $form['empty_field'] = array( + '#type' => 'text_format', + '#title' => t('No result text'), + '#default_value' => $conf['empty'], + '#format' => $conf['empty_format'], + '#dependency' => array('edit-override-empty' => array(1)), + ); + + $form['override_no_key'] = array( + '#type' => 'checkbox', + '#default_value' => $conf['override_no_key'], + '#title' => t('Display text if no search keywords were submitted'), + ); + + + $form['no_key_title'] = array( + '#title' => t('Title'), + '#type' => 'textfield', + '#default_value' => $conf['no_key_title'], + '#dependency' => array('edit-override-no-key' => array(1)), + ); + + $form['no_key_field'] = array( + '#type' => 'text_format', + '#title' => t('No result text'), + '#default_value' => $conf['no_key'], + '#format' => $conf['no_key_format'], + '#dependency' => array('edit-override-no-key' => array(1)), + ); + + return $form; +} + +/** + * Submit handler for search form. + */ +function ctools_search_result_content_type_edit_form_submit($form, &$form_state) { + // Copy the text_format values over to where we normally store them. + $form_state['values']['empty'] = $form_state['values']['empty_field']['value']; + $form_state['values']['empty_format'] = $form_state['values']['empty_field']['format']; + $form_state['values']['no_key'] = $form_state['values']['no_key_field']['value']; + $form_state['values']['no_key_format'] = $form_state['values']['no_key_field']['format']; + // Copy everything from our defaults. + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +} + +/** + * Returns the administrative title for a type. + */ +function ctools_search_result_content_type_admin_title($subtype, $conf, $context) { + $info = search_get_info(); + $type = isset($info[$conf['type']]['title']) ? $info[$conf['type']]['title'] : t('Missing/broken type'); + return t('@type search result', array('@type' => $type)); +} diff --git a/sites/all/modules/ctools/plugins/content_types/term_context/icon_term.png b/sites/all/modules/ctools/plugins/content_types/term_context/icon_term.png Binary files differnew file mode 100644 index 000000000..f0417cb65 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/term_context/icon_term.png diff --git a/sites/all/modules/ctools/plugins/content_types/term_context/term_description.inc b/sites/all/modules/ctools/plugins/content_types/term_context/term_description.inc new file mode 100644 index 000000000..f95c4f547 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/term_context/term_description.inc @@ -0,0 +1,51 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'title' => t('Term description'), + 'icon' => 'icon_term.png', + 'description' => t('Term description.'), + 'required context' => new ctools_context_required(t('Term'), array('term', 'taxonomy_term')), + 'category' => t('Taxonomy term'), +); + +function ctools_term_description_content_type_render($subtype, $conf, $panel_args, $context) { + $term = isset($context->data) ? clone($context->data) : NULL; + $block = new stdClass(); + $block->module = 'node_type'; + + if (!empty($term)) { + $block->title = $term->name; + $block->content = check_markup($term->description, $term->format, '', TRUE); + $block->delta = $term->tid; + + if (user_access('administer taxonomy')) { + $block->admin_links['update'] = array( + 'title' => t('Edit term'), + 'alt' => t("Edit this term"), + 'href' => "taxonomy/term/$term->tid/edit", + 'query' => drupal_get_destination(), + ); + } + } + else { + $block->title = ''; + $block->content = t('Term description goes here.'); + $block->delta = 'unknown'; + } + + return $block; +} + +function ctools_term_description_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" term description', array('@s' => $context->identifier)); +} + +function ctools_term_description_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to have context setting. + return $form; +} diff --git a/sites/all/modules/ctools/plugins/content_types/term_context/term_list.inc b/sites/all/modules/ctools/plugins/content_types/term_context/term_list.inc new file mode 100644 index 000000000..7c609fb43 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/term_context/term_list.inc @@ -0,0 +1,172 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'title' => t('List of related terms'), + 'icon' => 'icon_term.png', + 'description' => t('Terms related to an existing term; may be child, siblings or top level.'), + 'required context' => new ctools_context_required(t('Term'), array('term', 'taxonomy_term')), + 'category' => t('Taxonomy term'), + 'defaults' => array( + 'title' => '', + 'type' => 'child', + 'include_current_term' => FALSE, + 'list_type' => 'ul', + 'path' => 'taxonomy/term', + ), +); + +function ctools_term_list_content_type_render($subtype, $conf, $panel_args, $context) { + $term = isset($context->data) ? clone($context->data) : NULL; + $block = new stdClass(); + $block->module = 'term-list'; + $path = empty($conf['path']) ? 'taxonomy/term/%tid' : $conf['path']; + if (strpos($path, '%tid') === FALSE) { + if (substr($path, -1) != '/') { + $path .= '/'; + } + $path .= '%tid'; + } + + $options = ctools_admin_term_list_options(); + $skip = array(); + + if ($term) { + $block->title = $options[$conf['type']]; + $block->delta = $conf['type']; + switch ($conf['type']) { + case 'related': + // FIXME this no longer exists, must be done with Field API + // $terms = taxonomy_get_related($term->tid); + break; + + case 'child': + default: + if (!empty($conf['include_current_term'])) { + $terms[] = $term; + } + $terms = taxonomy_get_children($term->tid); + break; + + case 'top': + $terms = taxonomy_get_tree($term->vid, 0, 1); + break; + + case 'parent': + $terms = taxonomy_get_parents($term->tid); + if (!empty($conf['include_current_term'])) { + $terms[] = $term; + } + $block->title = count($terms) == 1 ? t('Parent term') : t('Parent terms'); + break; + + case 'sibling': + $parent = db_query('SELECT parent FROM {taxonomy_term_hierarchy} WHERE tid = :tid', array(':tid' => $term->tid))->fetchField(); + if ($parent) { + $terms = taxonomy_get_children($parent, $term->vid); + } + else { + $terms = taxonomy_get_tree($term->vid, 0, 1); + } + + $skip[$term->tid] = $term->tid; + break; + + case 'synonyms': + // FIXME this no longer exists, must be done with Field API +// $terms = taxonomy_get_synonyms($term->tid); + break; + } + + if (!empty($terms)) { + foreach ($terms as $related) { + if (empty($skip[$related->tid])) { + $items[] = l($related->name, str_replace('%tid', $related->tid, $path), array('rel' => 'tag', 'title' => strip_tags($related->description))); + } + } + + if (!empty($items)) { + $block->content = theme('item_list', array('items' => $items, 'type' => $conf['list_type'])); + } + } + } + else { + $block->content = t('Term description goes here.'); + $block->delta = 'unknown'; + } + + return $block; +} + +function ctools_admin_term_list_options() { + return array( + 'child' => t('Child terms'), + 'related' => t('Related terms (does not work in D7)'), + 'sibling' => t('Sibling terms'), + 'top' => t('Top level terms'), + 'synonyms' => t('Term synonyms (does not work in D7)'), + 'parent' => t('Parent term(s)'), + ); +} + +/** + * Returns an edit form for the custom type. + */ +function ctools_term_list_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + + $form['type'] = array( + '#type' => 'radios', + '#title' => t('Which terms'), + '#options' => ctools_admin_term_list_options(), + '#default_value' => $conf['type'], + '#prefix' => '<div class="clearfix no-float">', + '#suffix' => '</div>', + ); + + $form['include_current_term'] = array( + '#type' => 'checkbox', + '#title' => t('Include the current term in the list'), + '#default_value' => !empty($conf['include_current_term']), + '#prefix' => '<div class="clearfix no-float">', + '#suffix' => '</div>', + '#states' => array( + 'invisible' => array( + ':input[name="type"], unique1' => array('!value' => 'child'), + ':input[name="type"], unique2' => array('!value' => 'parent'), + ), + ), + ); + + $form['list_type'] = array( + '#type' => 'select', + '#title' => t('List type'), + '#options' => array('ul' => t('Unordered'), 'ol' => t('Ordered')), + '#default_value' => $conf['list_type'], + ); + + $form['path'] = array( + '#type' => 'textfield', + '#title' => t('Path'), + '#default_value' => empty($conf['path']) ? 'taxonomy/term/%tid' : $conf['path'], + '#description' => t('The path to use for the terms. You may use %tid to place the term id as part of the path; if let off, it will be appended to the end.'), + ); + return $form; +} + +function ctools_term_list_content_type_admin_title($subtype, $conf, $context) { + $options = ctools_admin_term_list_options(); + return t('"@s" @type', array('@s' => $context->identifier, '@type' => drupal_strtolower($options[$conf['type']]))); +} + +function ctools_term_list_content_type_edit_form_submit($form, &$form_state) { + // Copy everything from our defaults. + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +} + diff --git a/sites/all/modules/ctools/plugins/content_types/term_context/term_name.inc b/sites/all/modules/ctools/plugins/content_types/term_context/term_name.inc new file mode 100644 index 000000000..a9a88764f --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/term_context/term_name.inc @@ -0,0 +1,121 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'title' => t('Term name'), + 'icon' => 'icon_term.png', + 'description' => t('The name of this taxonomy term.'), + 'required context' => new ctools_context_required(t('Term'), array('term', 'taxonomy_term')), + 'category' => t('Taxonomy term'), + 'defaults' => array( + 'link' => TRUE, + 'markup' => 'none', + 'id' => '', + 'class' => '', + ), +); + + +/** + * Render the custom content type. + */ +function ctools_term_name_content_type_render($subtype, $conf, $panel_args, $context) { + if (empty($context) || empty($context->data)) { + return; + } + + // Get a shortcut to the term. + $term = $context->data; + + // Load the vocabulary. + $vocab = taxonomy_vocabulary_load($term->vid); + + // Generate the title + $content = !empty($conf['link']) ? l($term->name, 'taxonomy/term/' . $term->tid) : check_plain($term->name); + + // Build any surrounding markup if so configured + if (isset($conf['markup']) && $conf['markup'] != 'none') { + $markup = '<' . $conf['markup']; + if (!empty($conf['id'])) { + $markup .= ' id="' . $conf['id'] . '"'; + } + if (!empty($conf['class'])) { + $markup .= ' class="' . $conf['class'] . '"'; + } + $markup .= '>' . $content . '</' . $conf['markup'] . '>' . "\n"; + $content = $markup; + } + + // Build the content type block. + $block = new stdClass(); + $block->module = 'term_name'; + $block->title = t('Name'); + $block->content = $content; + $block->delta = $term->tid; + + return $block; +} + +/** + * Returns an edit form for custom type settings. + */ +function ctools_term_name_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + + $form['markup'] = array( + '#title' => t('Title tag'), + '#type' => 'select', + '#options' => array( + 'none' => t('- No tag -'), + 'h1' => t('h1'), + 'h2' => t('h2'), + 'h3' => t('h3'), + 'h4' => t('h4'), + 'h5' => t('h5'), + 'h6' => t('h6'), + 'div' => t('div'), + ), + '#default_value' => $conf['markup'], + ); + + $form['id'] = array( + '#title' => t('CSS id to use'), + '#type' => 'textfield', + '#default_value' => $conf['id'], + ); + + $form['class'] = array( + '#title' => t('CSS class to use'), + '#type' => 'textfield', + '#default_value' => $conf['class'], + ); + + $form['link'] = array( + '#title' => t('Link to term'), + '#type' => 'checkbox', + '#default_value' => $conf['link'], + '#description' => t('Check here to make the name link to the term page.'), + ); + return $form; +} + +/** + * Submit handler for the custom type settings form. + */ +function ctools_term_name_content_type_edit_form_submit($form, &$form_state) { + // Copy everything from our defaults. + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +} + +/** + * Returns the administrative title for a type. + */ +function ctools_term_name_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" name', array('@s' => $context->identifier)); +} diff --git a/sites/all/modules/ctools/plugins/content_types/token/icon_token.png b/sites/all/modules/ctools/plugins/content_types/token/icon_token.png Binary files differnew file mode 100644 index 000000000..f0417cb65 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/token/icon_token.png diff --git a/sites/all/modules/ctools/plugins/content_types/token/token.inc b/sites/all/modules/ctools/plugins/content_types/token/token.inc new file mode 100644 index 000000000..7b6f7fcd5 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/token/token.inc @@ -0,0 +1,122 @@ +<?php + +/** + * @file + * Plugin automatically declare 'tokens' as plugins. + */ + +/** + * Plugin decleration. + */ +$plugin = array( + 'title' => t('Tokens'), + 'content type' => 'ctools_token_content_type_content_type', + 'defaults' => array('sanitize' => TRUE), +); + +/** + * Just one subtype. + * + * Ordinarily this function is meant to get just one subtype. However, we are + * using it to deal with the fact that we have changed the subtype names. This + * lets us translate the name properly. + */ +function ctools_token_content_type_content_type($subtype) { + $types = ctools_token_content_type_content_types(); + if (isset($types[$subtype])) { + return $types[$subtype]; + } +} + +/** + * Return all field content types available. + */ +function ctools_token_content_type_content_types() { + // This will hold all the properties. + $types = &drupal_static(__FUNCTION__); + if (isset($types)) { + return $types; + } + + $types = array(); + $info = token_info(); + + foreach ($info['tokens'] as $entity_type => $tokens) { + $category = t('@entity (tokens)', array('@entity' => ucfirst($entity_type))); + $context = new ctools_context_required(t(ucfirst($entity_type)), $entity_type); + foreach ($tokens as $name => $token) { + if (!empty($token['name'])) { + $token += array('description' => ''); + $types[$entity_type . ':' . $name] = array( + 'category' => $category, + 'icon' => 'icon_token.png', + 'title' => $token['name'], + 'description' => $token['description'], + 'required context' => $context, + ); + } + } + } + + return $types; +} + +/** +* Render the custom content type. +*/ +function ctools_token_content_type_render($subtype, $conf, $panel_args, $context) { + if (empty($context) || empty($context->data)) { + return FALSE; + } + + $sanitize = $conf['sanitize']; + + $entity = $context->data; + list($entity_type, $name) = explode(':', $subtype, 2); + + $info = token_info(); + $values = token_generate($entity_type, array($name => $name), array($entity_type => $entity), array('sanitize' => $sanitize)); + if (!isset($values[$name])) { + return; + } + + // Build the content type block. + $block = new stdClass(); + $block->module = 'ctools'; + $block->title = $info['tokens'][$entity_type][$name]['name']; + $block->content = $values[$name]; + $block->delta = str_replace('_', '-', $entity_type . '-' . $name); + + return $block; +} + +/** +* Returns an edit form for custom type settings. +*/ +function ctools_token_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + + $form['sanitize'] = array( + '#type' => 'checkbox', + '#default_value' => !empty($conf['sanitize']), + '#title' => t('Sanitize'), + '#description' => t('When enabled that output of the token will be stripped from dangerous HTML.'), + ); + + return $form; +} + +/** + * Validate the node selection. + */ +function ctools_token_content_type_edit_form_submit($form, &$form_state) { + $form_state['conf']['sanitize'] = $form_state['values']['sanitize']; +} + + +/** +* Returns the administrative title for a type. +*/ +function ctools_token_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" @name', array('@s' => $context->identifier, '@name' => $subtype)); +} diff --git a/sites/all/modules/ctools/plugins/content_types/user_context/icon_user.png b/sites/all/modules/ctools/plugins/content_types/user_context/icon_user.png Binary files differnew file mode 100644 index 000000000..ab248f3f1 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/user_context/icon_user.png diff --git a/sites/all/modules/ctools/plugins/content_types/user_context/profile_fields.inc b/sites/all/modules/ctools/plugins/content_types/user_context/profile_fields.inc new file mode 100644 index 000000000..55d5593db --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/user_context/profile_fields.inc @@ -0,0 +1,129 @@ +<?php + +if (module_exists('profile') && !(defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'update') && !is_null(profile_user_categories())) { + /** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ + $plugin = array( + 'single' => TRUE, + 'title' => t('Profile category'), + 'icon' => 'icon_user.png', + 'description' => t('Contents of a single profile category.'), + 'required context' => new ctools_context_required(t('User'), 'user'), + 'category' => t('User'), + 'defaults' => array('category' => '', 'empty' => ''), + 'hook theme' => 'ctools_profile_fields_content_type_theme', + ); +} + +/** + * 'Render' callback for the 'profile fields' content type. + */ +function ctools_profile_fields_content_type_render($subtype, $conf, $panel_args, $context) { + $account = isset($context->data) ? clone($context->data) : NULL; + $block = new stdClass(); + $block->module = 'profile fields'; + + if ($account) { + // Get the category from the options + $category = str_replace("_", " ", $conf['category']); + + // Set the subject to the name of the category + $block->subject = $category; + + // Put all the fields in the category into an array + profile_view_profile($account); + + if (is_array($account->content[$category])) { + foreach ($account->content[$category] as $field) { + if (is_array($field['#attributes'])) { + // @todo 'class' is *always* an array now. 04/10/2009 sun + $vars[$field['#attributes']['class']]['title'] = $field['#title']; + $vars[$field['#attributes']['class']]['value'] = $field['#value']; + } + } + } + + if (count($vars) == 0) { + // Output the given empty text + $output = $conf['empty']; + } + else { + // Call the theme function with the field vars + $output = theme('profile_fields_pane', $category, $vars); + } + + $block->content = $output; + $block->delta = $account->uid; + } + else { + $block->subject = $conf['category']; + $block->content = t('Profile content goes here.'); + $block->delta = 'unknown'; + } + + return $block; +} +/** + * Helper function : build the list of categories for the 'edit' form. + */ +function _ctools_profile_fields_options() { + $cat_list = array(); + + $categories = profile_categories(); + foreach ($categories as $key => $value) { + $cat_list[str_replace(" ", "_", $value['name'])] = $value['title']; + } + + return $cat_list; +} + +/** + * 'Edit' callback for the 'profile fields' content type. + */ +function ctools_profile_fields_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + $form['category'] = array( + '#type' => 'radios', + '#title' => t('Which category'), + '#options' => _ctools_profile_fields_options(), + '#default_value' => $conf['category'], + '#prefix' => '<div class="clearfix no-float">', + '#suffix' => '</div>', + ); + + $form['empty'] = array( + '#type' => 'textarea', + '#title' => 'Empty text', + '#description' => t('Text to display if category has no data. Note that title will not display unless overridden.'), + '#rows' => 5, + '#default_value' => $conf['empty'], + '#prefix' => '<div class="clearfix no-float">', + '#suffix' => '</div>', + ); + + return $form; +} + +function ctools_profile_fields_content_type_edit_form_submit($form, &$form_state) { + // Copy everything from our defaults. + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +} + +/** + * 'Title' callback for the 'profile fields' content type. + */ +function ctools_profile_fields_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" profile fields', array('@s' => $conf['category'])); +} + +function ctools_profile_fields_content_type_theme(&$theme, $plugin) { + $theme['profile_fields_pane'] = array( + 'variables' => array('category' => NULL, 'vars' => NULL), + 'path' => $plugin['path'], + 'template' => 'profile_fields_pane', + ); +} diff --git a/sites/all/modules/ctools/plugins/content_types/user_context/profile_fields_pane.tpl.php b/sites/all/modules/ctools/plugins/content_types/user_context/profile_fields_pane.tpl.php new file mode 100644 index 000000000..373681213 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/user_context/profile_fields_pane.tpl.php @@ -0,0 +1,16 @@ +<?php +/** + * @file + * Display profile fields. + * + * @todo Need definition of what variables are available here. + */ +?> +<?php if (is_array($vars)): ?> + <?php foreach ($vars as $class => $field): ?> + <dl class="profile-category"> + <dt class="profile-<?php print $class; ?>"><?php print $field['title']; ?></dt> + <dd class="profile-<?php print $class; ?>"><?php print $field['value']; ?></dd> + </dl> + <?php endforeach; ?> +<?php endif; ?> diff --git a/sites/all/modules/ctools/plugins/content_types/user_context/user_links.inc b/sites/all/modules/ctools/plugins/content_types/user_context/user_links.inc new file mode 100644 index 000000000..4a93621d7 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/user_context/user_links.inc @@ -0,0 +1,84 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'title' => t('User links'), + 'icon' => 'icon_user.png', + 'description' => t('User links of the referenced user.'), + 'required context' => new ctools_context_required(t('User'), 'user'), + 'category' => t('User'), + 'defaults' => array( + 'override_title' => FALSE, + 'override_title_text' => '', + 'build_mode' => '', + ), +); + +/** + * Output function for the user links. + */ +function ctools_user_links_content_type_render($subtype, $conf, $panel_args, $context) { + if (!empty($context) && empty($context->data)) { + return; + } + + $account = clone $context->data; + $block = new stdClass(); + $block->module = 'user'; + $block->delta = $account->uid; + + if (empty($account)) { + $block->delta = 'placeholder'; + $block->subject = t('User name.'); + $block->content = t('User links go here.'); + } + else { + $block->subject = $account->name; + user_build_content($account, $conf['build_mode']); + if (!empty($account->content['links'])) { + $block->content = $account->content['links']; + } + else { + $block->content = ''; + } + } + return $block; +} + +/** + * Returns an edit form for the custom type. + */ +function ctools_user_links_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + + $entity = entity_get_info('user'); + $build_mode_options = array(); + foreach ($entity['view modes'] as $mode => $option) { + $build_mode_options[$mode] = $option['label']; + } + + $form['build_mode'] = array( + '#title' => t('Build mode'), + '#type' => 'select', + '#description' => t('Select a build mode for this user.'), + '#options' => $build_mode_options, + '#default_value' => $conf['build_mode'], + ); + + return $form; +} + +function ctools_user_links_content_type_edit_form_submit($form, &$form_state) { + // Copy everything from our defaults. + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +} + +function ctools_user_links_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" links', array('@s' => $context->identifier)); +} diff --git a/sites/all/modules/ctools/plugins/content_types/user_context/user_picture.inc b/sites/all/modules/ctools/plugins/content_types/user_context/user_picture.inc new file mode 100644 index 000000000..0934c20a5 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/user_context/user_picture.inc @@ -0,0 +1,54 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'title' => t('User picture'), + 'icon' => 'icon_user.png', + 'description' => t('The picture of a user.'), + 'required context' => new ctools_context_required(t('User'), 'user'), + 'category' => t('User'), +); + +function ctools_user_picture_content_type_render($subtype, $conf, $panel_args, $context) { + global $user; + + if (empty($context->data)) { + return; + } + + $account = clone $context->data; + + // Check if user has permissions to access the user + if ($user->uid != $account->uid && (!user_access('access user profiles') && !user_access('administer users'))) { + return; + } + + $block = new stdClass(); + $block->module = 'user-profile'; + $block->title = check_plain($account->name); + + $element['user_picture'] = array( + '#theme' => 'user_picture', + '#account' => $account, + ); + + + $block->content = $element; + return $block; +} + +/** + * Display the administrative title for a panel pane in the drag & drop UI + */ +function ctools_user_picture_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" user picture', array('@s' => $context->identifier)); +} + +function ctools_user_picture_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to have context setting. + return $form; +} diff --git a/sites/all/modules/ctools/plugins/content_types/user_context/user_profile.inc b/sites/all/modules/ctools/plugins/content_types/user_context/user_profile.inc new file mode 100644 index 000000000..6c41882ff --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/user_context/user_profile.inc @@ -0,0 +1,87 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'single' => TRUE, + 'title' => t('User profile'), + 'icon' => 'icon_user.png', + 'description' => t('The profile of a user.'), + 'required context' => new ctools_context_required(t('User'), 'user'), + 'category' => t('User'), + 'defaults' => array( + 'view_mode' => 'full', + ), +); + +/** + * Render the user profile content type. + */ +function ctools_user_profile_content_type_render($subtype, $conf, $panel_args, $context) { + $account = isset($context->data) ? clone($context->data) : NULL; + if (!$account) { + return NULL; + } + + // Retrieve all profile fields and attach to $account->content. + if (!isset($account->content)) { + user_build_content($account, isset($conf['view_mode']) ? $conf['view_mode'] : 'full'); + } + + $build = $account->content; + // We don't need duplicate rendering info in account->content. + unset($account->content); + + $build += array( + '#theme' => 'user_profile', + '#account' => $account, + // @todo support view mode + '#view_mode' => isset($conf['view_mode']) ? $conf['view_mode'] : 'full', + // @todo do we need to support this? + '#language' => NULL, + ); + + // Allow modules to modify the structured user. + $type = 'user'; + drupal_alter(array('user_view', 'entity_view'), $build, $type); + + $block = new stdClass(); + $block->module = 'user-profile'; + $block->title = check_plain(format_username($account)); + $block->content = $build; + + return $block; +} + +/** + * Display the administrative title for a panel pane in the drag & drop UI. + */ +function ctools_user_profile_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" user profile', array('@s' => $context->identifier)); +} + +function ctools_user_profile_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + $entity = entity_get_info('user'); + $view_mode_options = array(); + foreach ($entity['view modes'] as $mode => $option) { + $view_mode_options[$mode] = $option['label']; + } + + $form['view_mode'] = array( + '#title' => t('View mode'), + '#type' => 'select', + '#description' => t('Select a build mode for this user.'), + '#options' => $view_mode_options, + '#default_value' => isset($conf['view_mode']) ? $conf['view_mode'] : 'full', + ); + + return $form; +} + +function ctools_user_profile_content_type_edit_form_submit($form, &$form_state) { + $form_state['conf']['view_mode'] = $form_state['values']['view_mode']; +} + diff --git a/sites/all/modules/ctools/plugins/content_types/user_context/user_signature.inc b/sites/all/modules/ctools/plugins/content_types/user_context/user_signature.inc new file mode 100644 index 000000000..ca7550b25 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/user_context/user_signature.inc @@ -0,0 +1,43 @@ +<?php + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('User signature'), + 'icon' => 'icon_user.png', + 'description' => t('The signature of a user.'), + 'required context' => new ctools_context_required(t('User'), 'user'), + 'category' => t('User'), +); + +function ctools_user_signature_content_type_render($subtype, $conf, $panel_args, $context) { + $account = isset($context->data) ? clone($context->data) : NULL; + $block = new stdClass(); + $block->module = 'user-signature'; + + if ($account === FALSE || ($account->access == 0 && !user_access('administer users'))) { + return; + } + + $element['user_signature'] = array( + '#theme' => 'user_signature', + '#signature' => check_markup($account->signature, $account->signature_format), + ); + + $block->content = $element; + return $block; +} + +/** + * Display the administrative title for a panel pane in the drag & drop UI + */ +function ctools_user_signature_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" user signature', array('@s' => $context->identifier)); +} + +function ctools_user_signature_content_type_edit_form($form, &$form_state) { + // provide a blank form so we have a place to have context setting. + return $form; +} diff --git a/sites/all/modules/ctools/plugins/content_types/vocabulary_context/icon_vocabulary.png b/sites/all/modules/ctools/plugins/content_types/vocabulary_context/icon_vocabulary.png Binary files differnew file mode 100644 index 000000000..f0417cb65 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/vocabulary_context/icon_vocabulary.png diff --git a/sites/all/modules/ctools/plugins/content_types/vocabulary_context/vocabulary_terms.inc b/sites/all/modules/ctools/plugins/content_types/vocabulary_context/vocabulary_terms.inc new file mode 100644 index 000000000..5f33a0381 --- /dev/null +++ b/sites/all/modules/ctools/plugins/content_types/vocabulary_context/vocabulary_terms.inc @@ -0,0 +1,100 @@ +<?php + +if (module_exists('taxonomy')) { + /** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ + $plugin = array( + 'single' => TRUE, + 'title' => t('Vocabulary terms'), + 'icon' => 'icon_vocabulary.png', + 'description' => t('All the terms in a vocabulary.'), + 'required context' => new ctools_context_required(t('Vocabulary'), 'entity:taxonomy_vocabulary'), + 'category' => t('Vocabulary'), + 'defaults' => array('max_depth' => 0, 'tree' => 1), + ); +} + +/** + * Output function for the 'vocabulary terms' content type. Outputs a + * list of terms for the input vocabulary. + */ +function ctools_vocabulary_terms_content_type_render($subtype, $conf, $panel_args, $context) { + $vocab = isset($context->data) ? clone($context->data) : NULL; + $max_depth = (!empty($conf['max_depth']) ? (int)$conf['max_depth'] : NULL); + if ($conf['tree'] == FALSE) { + $terms = taxonomy_get_tree($vocab->vid, 0, $max_depth); + $items = array(); + foreach ($terms as $term) { + $items[] = l($term->name, 'taxonomy/term/' . $term->tid); + } + $output = theme('item_list', array('items' => $items)); + } + else { + $output = theme('item_list', array('items' => _ctools_content_vocabulary_terms($vocab->vid, $max_depth))); + } + + $block = new stdClass(); + $block->module = 'node_type'; + $block->title = check_plain($vocab->name); + $block->content = $output; + $block->delta = $vocab->vid; + + return $block; +} + +function _ctools_content_vocabulary_terms($vid, $max_depth, $depth = -1, $tid = 0) { + $depth++; + if ($max_depth != NULL && $depth == $max_depth) { + return array(); + } + $return = array(); + $query = db_select('taxonomy_term_data', 't')->fields('t', array('tid')); + $query->join('taxonomy_term_hierarchy', 'h', ' t.tid = h.tid'); + $query->condition('t.vid', $vid) + ->condition('h.parent', $tid) + ->orderBy('t.weight') + ->orderBy('t.name'); + $tids = $query->execute()->fetchCol(); + $terms = taxonomy_term_load_multiple($tids); + foreach ($terms as $term) { + $return[] = array( + 'data' => l($term->name, 'taxonomy/term/' . $term->tid), + 'children' => _ctools_content_vocabulary_terms($vid, $max_depth, $depth, $term->tid), + ); + } + return $return; +} + +function ctools_vocabulary_terms_content_type_admin_title($subtype, $conf, $context) { + return t('"@s" terms', array('@s' => $context->identifier)); +} + +function ctools_vocabulary_terms_content_type_edit_form($form, &$form_state) { + $conf = $form_state['conf']; + $form['max_depth'] = array( + '#type' => 'select', + '#title' => t('Maximum depth'), + '#options' => array_merge(array(t('unlimited')), range(1, 9)), + '#default_value' => $conf['max_depth'], + '#description' => t('Define the maximum depth of terms being displayed.'), + ); + + $form['tree'] = array( + '#type' => 'checkbox', + '#title' => t('Display as tree'), + '#default_value' => $conf['tree'], + '#description' => t('If checked, the terms are displayed in a tree, otherwise in a flat list.'), + ); + + return $form; +} + +function ctools_vocabulary_terms_content_type_edit_form_submit($form, &$form_state) { + // Copy everything from our defaults. + foreach (array_keys($form_state['plugin']['defaults']) as $key) { + $form_state['conf'][$key] = $form_state['values'][$key]; + } +} + diff --git a/sites/all/modules/ctools/plugins/contexts/entity.inc b/sites/all/modules/ctools/plugins/contexts/entity.inc new file mode 100644 index 000000000..b214aa06b --- /dev/null +++ b/sites/all/modules/ctools/plugins/contexts/entity.inc @@ -0,0 +1,273 @@ +<?php + +/** + * @file + * + * Plugin to provide a node context. A node context is a node wrapped in a + * context object that can be utilized by anything that accepts contexts. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Entity"), + 'description' => t('Entity object.'), + 'context' => 'ctools_context_create_entity', + 'edit form' => 'ctools_context_entity_settings_form', + 'defaults' => array('entity_id' => ''), + 'convert list' => 'ctools_context_entity_convert_list', + 'convert' => 'ctools_context_entity_convert', + 'placeholder form' => array( + '#type' => 'textfield', + '#description' => t('Enter the ID of an entity for this context.'), + ), + 'get child' => 'ctools_context_entity_get_child', + 'get children' => 'ctools_context_entity_get_children', +); + +function ctools_context_entity_get_child($plugin, $parent, $child) { + $plugins = ctools_context_entity_get_children($plugin, $parent); + return $plugins[$parent . ':' . $child]; +} + +function ctools_context_entity_get_children($plugin, $parent) { + $entities = entity_get_info(); + $plugins = array(); + foreach ($entities as $entity_type => $entity) { + $child_plugin = $plugin; + $child_plugin['title'] = $entity['label']; + $child_plugin['keyword'] = $entity_type; + $child_plugin['context name'] = $entity_type; + $child_plugin['name'] = $parent . ':' . $entity_type; + $child_plugin['description'] = t('Creates @entity context from an entity ID.', array('@entity' => $entity_type)); + $child_plugin_id = $parent . ':' . $entity_type; + drupal_alter('ctools_entity_context', $child_plugin, $entity, $child_plugin_id); + $plugins[$child_plugin_id] = $child_plugin; + } + drupal_alter('ctools_entity_contexts', $plugins); + return $plugins; +} + +/** + * It's important to remember that $conf is optional here, because contexts + * are not always created from the UI. + */ +function ctools_context_create_entity($empty, $data = NULL, $conf = FALSE, $plugin) { + $entity_type = $plugin['keyword']; + $entity = entity_get_info($entity_type); + $context = new ctools_context(array('entity:' . $entity_type, 'entity', $entity_type)); + $context->plugin = $plugin['name']; + $context->keyword = $entity_type; + + if ($empty) { + return $context; + } + + // Attempt to retain compatibility with broken id: + if (is_array($data) && !isset($data['entity_id']) && isset($data['id'])) { + $id = $data['id']; + } + elseif (is_array($data) && isset($data['entity_id'])) { + $id = $data['entity_id']; + } + elseif (is_object($data)) { + $ids = entity_extract_ids($entity_type, $data); + $id = $ids[0]; + } + elseif (is_numeric($data)) { + $id = $data; + $data = entity_load($entity_type, array($id)); + $data = !empty($data[$id]) ? $data[$id] : FALSE; + } + + if (is_array($data)) { + $data = entity_load($entity_type, array($id)); + $data = !empty($data[$id]) ? $data[$id] : FALSE; + } + + if (!empty($data)) { + $context->data = $data; + if (!empty($entity['entity keys']['label'])) { + $context->title = $data->{$entity['entity keys']['label']}; + } + $context->argument = $id; + + if ($entity['entity keys']['bundle']) { + $context->restrictions['type'] = array($data->{$entity['entity keys']['bundle']}); + } + return $context; + } +} + +function ctools_context_entity_settings_form($form, &$form_state) { + $conf = &$form_state['conf']; + $plugin = &$form_state['plugin']; + + $form['entity'] = array( + '#title' => t('Enter the title or ID of a @entity entity', array('@entity' => $plugin['keyword'])), + '#type' => 'textfield', + '#maxlength' => 512, + '#autocomplete_path' => 'ctools/autocomplete/' . $plugin['keyword'], + '#weight' => -10, + ); + + if (!empty($conf['entity_id'])) { + $info = entity_load($plugin['keyword'], array($conf['entity_id'])); + $info = $info[$conf['entity_id']]; + if ($info) { + $entity = entity_get_info($plugin['keyword']); + $uri = entity_uri($plugin['keyword'], $info); + if (is_array($uri) && $entity['entity keys']['label']) { + $link = l(t("'%title' [%type id %id]", array('%title' => $info->{$entity['entity keys']['label']}, '%type' => $plugin['keyword'], '%id' => $conf['entity_id'])), $uri['path'], array('attributes' => array('target' => '_blank', 'title' => t('Open in new window')), 'html' => TRUE)); + } + elseif (is_array($uri)) { + $link = l(t("[%type id %id]", array('%type' => $plugin['keyword'], '%id' => $conf['entity_id'])), $uri['path'], array('attributes' => array('target' => '_blank', 'title' => t('Open in new window')), 'html' => TRUE)); + } + elseif ($entity['entity keys']['label']) { + $link = l(t("'%title' [%type id %id]", array('%title' => $info->{$entity['entity keys']['label']}, '%type' => $plugin['keyword'], '%id' => $conf['entity_id'])), file_create_url($uri), array('attributes' => array('target' => '_blank', 'title' => t('Open in new window')), 'html' => TRUE)); + } + else { + $link = t("[%type id %id]", array('%type' => $plugin['keyword'], '%id' => $conf['entity_id'])); + } + $form['entity']['#description'] = t('Currently set to !link', array('!link' => $link)); + } + } + + $form['entity_id'] = array( + '#type' => 'value', + '#value' => $conf['entity_id'], + ); + + $form['entity_type'] = array( + '#type' => 'value', + '#value' => $plugin['keyword'], + ); + + $form['set_identifier'] = array( + '#type' => 'checkbox', + '#default_value' => FALSE, + '#title' => t('Reset identifier to entity label'), + '#description' => t('If checked, the identifier will be reset to the entity label of the selected entity.'), + ); + + return $form; +} + +/** + * Validate a node. + */ +function ctools_context_entity_settings_form_validate($form, &$form_state) { + // Validate the autocomplete + if (empty($form_state['values']['entity_id']) && empty($form_state['values']['entity'])) { + form_error($form['entity'], t('You must select an entity.')); + return; + } + + if (empty($form_state['values']['entity'])) { + return; + } + + $id = $form_state['values']['entity']; + $preg_matches = array(); + $match = preg_match('/\[id: (\d+)\]/', $id, $preg_matches); + if (!$match) { + $match = preg_match('/^id: (\d+)/', $id, $preg_matches); + } + + if ($match) { + $id = $preg_matches[1]; + } + if (is_numeric($id)) { + $entity = entity_load($form_state['values']['entity_type'], array($id)); + $entity = $entity[$id]; + } + else { + $entity_info = entity_get_info($form_state['values']['entity_type']); + $field = $entity_info['entity keys']['label']; + $entity = entity_load($form_state['values']['entity_type'], FALSE, array($field => $id)); + } + + // Do not allow unpublished nodes to be selected by unprivileged users + // || (empty($node->status) && !(user_access('administer nodes'))) need a new sanity check at some point. + if (!$entity) { + form_error($form['entity'], t('Invalid entity selected.')); + } + else { + $entity_id = entity_extract_ids($form_state['values']['entity_type'], $entity); + form_set_value($form['entity_id'], $entity_id[0], $form_state); + } +} + +function ctools_context_entity_settings_form_submit($form, &$form_state) { + if ($form_state['values']['set_identifier']) { + $entity_info = entity_get_info($form_state['values']['entity_type']); + $entity = entity_load($form_state['values']['entity_type'], array($form_state['values']['entity_id'])); + $entity = $entity[$form_state['values']['entity_id']]; + $form_state['values']['identifier'] = $entity->{$entity_info['entity keys']['label']}; + } + + // This will either be the value set previously or a value set by the + // validator. + $form_state['conf']['entity_id'] = $form_state['values']['entity_id']; +} + +/** + * Provide a list of ways that this context can be converted to a string. + */ +function ctools_context_entity_convert_list($plugin) { + $list = array(); + + $entity = entity_get_info($plugin['context name']); + if (isset($entity['token type'])) { + $token = $entity['token type']; + } + else { + $token = $plugin['context name']; + } + + // Hack: we need either token.module or a core fix for this to work right, + // until then, we just muscle it. + if ($token == 'taxonomy_term') { + $token = 'term'; + } + + $tokens = token_info(); + if (isset($tokens['tokens'][$token])) { + foreach ($tokens['tokens'][$token] as $id => $info) { + if (!isset($list[$id])) { + $list[$id] = $info['name']; + } + } + } + return $list; +} + +/** + * Convert a context into a string. + */ +function ctools_context_entity_convert($context, $type, $options = array()) { + $entity_type = $context->type[2]; + $entity = entity_get_info($entity_type); + + if (isset($entity['token type'])) { + $token = $entity['token type']; + } + else { + $token = $entity_type; + } + + // Hack: we need either token.module or a core fix for this to work right, + // until then, we just muscle it. + if ($token == 'taxonomy_term') { + $token = 'term'; + } + + $tokens = token_info(); + + $values = token_generate($token, array($type => $type), array($token => $context->data), $options); + if (isset($values[$type])) { + return $values[$type]; + } +} diff --git a/sites/all/modules/ctools/plugins/contexts/node.inc b/sites/all/modules/ctools/plugins/contexts/node.inc new file mode 100644 index 000000000..997cd1365 --- /dev/null +++ b/sites/all/modules/ctools/plugins/contexts/node.inc @@ -0,0 +1,181 @@ +<?php + +/** + * @file + * + * Plugin to provide a node context. A node context is a node wrapped in a + * context object that can be utilized by anything that accepts contexts. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Node"), + 'description' => t('A node object.'), + 'context' => 'ctools_context_create_node', + 'edit form' => 'ctools_context_node_settings_form', + 'defaults' => array('nid' => ''), + 'keyword' => 'node', + 'context name' => 'node', + 'convert list' => 'ctools_context_node_convert_list', + 'convert' => 'ctools_context_node_convert', + 'placeholder form' => array( + '#type' => 'textfield', + '#description' => t('Enter the node ID of a node for this context.'), + ), + // This context is deprecated and should not be usable in the UI. + 'no ui' => TRUE, + 'no required context ui' => TRUE, + 'superceded by' => 'entity:node', +); + +/** + * It's important to remember that $conf is optional here, because contexts + * are not always created from the UI. + */ +function ctools_context_create_node($empty, $data = NULL, $conf = FALSE) { + $context = new ctools_context('node'); + $context->plugin = 'node'; + + if ($empty) { + return $context; + } + + if ($conf) { + $nid = is_array($data) && isset($data['nid']) ? $data['nid'] : (is_object($data) ? $data->nid : 0); + + if (module_exists('translation')) { + if ($translation = module_invoke('translation', 'node_nid', $nid, $GLOBALS['language']->language)) { + $nid = $translation; + $reload = TRUE; + } + } + + if (is_array($data) || !empty($reload)) { + $data = node_load($nid); + } + } + + if (!empty($data)) { + $context->data = $data; + $context->title = $data->title; + $context->argument = $data->nid; + + $context->restrictions['type'] = array($data->type); + return $context; + } +} + +function ctools_context_node_settings_form($form, &$form_state) { + $conf = &$form_state['conf']; + + $form['node'] = array( + '#title' => t('Enter the title or NID of a node'), + '#type' => 'textfield', + '#maxlength' => 512, + '#autocomplete_path' => 'ctools/autocomplete/node', + '#weight' => -10, + ); + + if (!empty($conf['nid'])) { + $info = db_query('SELECT * FROM {node} WHERE nid = :nid', array(':nid' => $conf['nid']))->fetchObject(); + if ($info) { + $link = l(t("'%title' [node id %nid]", array('%title' => $info->title, '%nid' => $info->nid)), "node/$info->nid", array('attributes' => array('target' => '_blank', 'title' => t('Open in new window')), 'html' => TRUE)); + $form['node']['#description'] = t('Currently set to !link', array('!link' => $link)); + } + } + + $form['nid'] = array( + '#type' => 'value', + '#value' => $conf['nid'], + ); + + $form['set_identifier'] = array( + '#type' => 'checkbox', + '#default_value' => FALSE, + '#title' => t('Reset identifier to node title'), + '#description' => t('If checked, the identifier will be reset to the node title of the selected node.'), + ); + + return $form; +} + +/** + * Validate a node. + */ +function ctools_context_node_settings_form_validate($form, &$form_state) { + // Validate the autocomplete + if (empty($form_state['values']['nid']) && empty($form_state['values']['node'])) { + form_error($form['node'], t('You must select a node.')); + return; + } + + if (empty($form_state['values']['node'])) { + return; + } + + $nid = $form_state['values']['node']; + $preg_matches = array(); + $match = preg_match('/\[id: (\d+)\]/', $nid, $preg_matches); + if (!$match) { + $match = preg_match('/^id: (\d+)/', $nid, $preg_matches); + } + + if ($match) { + $nid = $preg_matches[1]; + } + if (is_numeric($nid)) { + $node = db_query('SELECT nid, status FROM {node} WHERE nid = :nid', array(':nid' => $nid))->fetchObject(); + } + else { + $node = db_query('SELECT nid, status FROM {node} WHERE LOWER(title) = LOWER(:title)', array(':title' => $nid))->fetchObject(); + } + + // Do not allow unpublished nodes to be selected by unprivileged users + if (!$node || (empty($node->status) && !(user_access('administer nodes')))) { + form_error($form['node'], t('Invalid node selected.')); + } + else { + form_set_value($form['nid'], $node->nid, $form_state); + } +} + +function ctools_context_node_settings_form_submit($form, &$form_state) { + if ($form_state['values']['set_identifier']) { + $node = node_load($form_state['values']['nid']); + $form_state['values']['identifier'] = $node->title; + } + + // This will either be the value set previously or a value set by the + // validator. + $form_state['conf']['nid'] = $form_state['values']['nid']; +} + +/** + * Provide a list of ways that this context can be converted to a string. + */ +function ctools_context_node_convert_list() { + $tokens = token_info(); + foreach ($tokens['tokens']['node'] as $id => $info) { + if (!isset($list[$id])) { + $list[$id] = $info['name']; + } + } + + return $list; +} + +/** + * Convert a context into a string. + */ +function ctools_context_node_convert($context, $type) { + $tokens = token_info(); + if (isset($tokens['tokens']['node'][$type])) { + $values = token_generate('node', array($type => $type), array('node' => $context->data)); + if (isset($values[$type])) { + return $values[$type]; + } + } +} diff --git a/sites/all/modules/ctools/plugins/contexts/node_add_form.inc b/sites/all/modules/ctools/plugins/contexts/node_add_form.inc new file mode 100644 index 000000000..f10944c24 --- /dev/null +++ b/sites/all/modules/ctools/plugins/contexts/node_add_form.inc @@ -0,0 +1,124 @@ +<?php + +/** + * @file + * + * Plugin to provide a node_add_form context + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Node add form'), + 'description' => t('A node add form.'), + 'context' => 'ctools_context_create_node_add_form', + 'edit form' => 'ctools_context_node_add_form_settings_form', + 'defaults' => array('type' => ''), + 'keyword' => 'node_add', + 'context name' => 'node_add_form', + 'convert list' => array('type' => t('Node type')), + 'convert' => 'ctools_context_node_add_form_convert', + 'placeholder form' => array( + '#type' => 'textfield', + '#description' => t('Enter the node type this context.'), + ), +); + +/** + * It's important to remember that $conf is optional here, because contexts + * are not always created from the UI. + */ +function ctools_context_create_node_add_form($empty, $data = NULL, $conf = FALSE) { + static $creating = FALSE; + $context = new ctools_context(array('form', 'node_add', 'node_form', 'node', 'entity:node')); + $context->plugin = 'node_add_form'; + + if ($empty || ($creating)) { + return $context; + } + $creating = TRUE; + + if ($conf && (isset($data['types']) || isset($data['type']))) { + // Holdover from typo'd config. + $data = isset($data['types']) ? $data['types'] : $data['type']; + } + + if (!empty($data)) { + $types = node_type_get_types(); + $type = str_replace('-', '_', $data); + + // Validate the node type exists. + if (isset($types[$type]) && node_access('create', $type)) { + // Initialize settings: + global $user; + $node = (object) array( + 'uid' => $user->uid, + 'name' => (isset($user->name) ? $user->name : ''), + 'type' => $type, + 'language' => LANGUAGE_NONE, + ); + + $form_id = $type . '_node_form'; + + $form_state = array( + 'want form' => TRUE, + 'build_info' => array( + 'args' => array($node) + ) + ); + + // Use module_load_include so that caches and stuff can know to load this. + form_load_include($form_state, 'inc', 'node', 'node.pages'); + + $form = drupal_build_form($form_id, $form_state); + + // In a form, $data is the object being edited. + $context->data = $node; + $context->title = $types[$type]->name; + $context->argument = $type; + + // These are specific pieces of data to this form. + // All forms should place the form here. + $context->form = $form; + $context->form_id = $form_id; + $context->form_title = t('Submit @name', array('@name' => $types[$type]->name)); + $context->node_type = $type; + $context->restrictions['type'] = array($type); + $context->restrictions['form'] = array('form'); + + $creating = FALSE; + return $context; + } + } + $creating = FALSE; +} + +function ctools_context_node_add_form_settings_form($form, &$form_state) { + $conf = $form_state['conf']; + + $form['type'] = array( + '#title' => t('Node type'), + '#type' => 'select', + '#options' => node_type_get_names(), + '#default_value' => $conf['type'], + '#description' => t('Select the node type for this form.'), + ); + + return $form; +} + +function ctools_context_node_add_form_settings_form_submit($form, &$form_state) { + $form_state['conf']['type'] = $form_state['values']['type']; +} + +/** + * Convert a context into a string. + */ +function ctools_context_node_add_form_convert($context, $type) { + switch ($type) { + case 'type': + return $context->data->type; + } +} diff --git a/sites/all/modules/ctools/plugins/contexts/node_edit_form.inc b/sites/all/modules/ctools/plugins/contexts/node_edit_form.inc new file mode 100644 index 000000000..7565f5c8f --- /dev/null +++ b/sites/all/modules/ctools/plugins/contexts/node_edit_form.inc @@ -0,0 +1,192 @@ +<?php + +/** + * @file + * + * Plugin to provide a node_edit_form context + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Node edit form"), + 'description' => t('A node edit form.'), + 'context' => 'ctools_context_create_node_edit_form', + 'edit form' => 'ctools_context_node_edit_form_settings_form', + 'defaults' => array('nid' => ''), + 'keyword' => 'node_edit', + 'context name' => 'node_edit_form', + 'convert list' => 'ctools_context_node_edit_convert_list', + 'convert' => 'ctools_context_node_edit_convert', + 'placeholder form' => array( + '#type' => 'textfield', + '#description' => t('Enter the node ID of a node for this argument:'), + ), +); + +/** + * It's important to remember that $conf is optional here, because contexts + * are not always created from the UI. + */ +function ctools_context_create_node_edit_form($empty, $node = NULL, $conf = FALSE) { + static $creating = FALSE; + $context = new ctools_context(array('form', 'node_edit', 'node_form', 'node_edit_form', 'node', 'entity:node')); + $context->plugin = 'node_edit_form'; + + if ($empty || ($creating)) { + return $context; + } + $creating = TRUE; + + if ($conf) { + // In this case, $node is actually our $conf array. + $nid = is_array($node) && isset($node['nid']) ? $node['nid'] : (is_object($node) ? $node->nid : 0); + + if (module_exists('translation')) { + if ($translation = module_invoke('translation', 'node_nid', $nid, $GLOBALS['language']->language)) { + $nid = $translation; + $reload = TRUE; + } + } + + if (is_array($node) || !empty($reload)) { + $node = node_load($nid); + } + } + + if (!empty($node)) { + $form_id = $node->type . '_node_form'; + + $form_state = array('want form' => TRUE, 'build_info' => array('args' => array($node))); + + $file = drupal_get_path('module', 'node') . '/node.pages.inc'; + require_once DRUPAL_ROOT . '/' . $file; + // This piece of information can let other modules know that more files + // need to be included if this form is loaded from cache: + $form_state['build_info']['files'] = array($file); + + $form = drupal_build_form($form_id, $form_state); + + // Fill in the 'node' portion of the context + $context->data = $node; + $context->title = isset($node->title) ? $node->title : ''; + $context->argument = isset($node->nid) ? $node->nid : $node->type; + + $context->form = $form; + $context->form_state = &$form_state; + $context->form_id = $form_id; + $context->form_title = isset($node->title) ? $node->title : ''; + $context->node_type = $node->type; + $context->restrictions['type'] = array($node->type); + $context->restrictions['form'] = array('form'); + + $creating = FALSE; + return $context; + } + $creating = FALSE; +} + +function ctools_context_node_edit_form_settings_form($form, &$form_state) { + $conf = &$form_state['conf']; + + $form['node'] = array( + '#title' => t('Enter the title or NID of a node'), + '#type' => 'textfield', + '#maxlength' => 512, + '#autocomplete_path' => 'ctools/autocomplete/node', + '#weight' => -10, + ); + + if (!empty($conf['nid'])) { + $info = db_query('SELECT * FROM {node} WHERE nid = :nid', array(':nid' => $conf['nid']))->fetchObject(); + if ($info) { + $link = l(t("'%title' [node id %nid]", array('%title' => $info->title, '%nid' => $info->nid)), "node/$info->nid", array('attributes' => array('target' => '_blank', 'title' => t('Open in new window')), 'html' => TRUE)); + $form['node']['#description'] = t('Currently set to !link', array('!link' => $link)); + } + } + + $form['nid'] = array( + '#type' => 'value', + '#value' => $conf['nid'], + ); + + $form['set_identifier'] = array( + '#type' => 'checkbox', + '#default_value' => FALSE, + '#title' => t('Reset identifier to node title'), + '#description' => t('If checked, the identifier will be reset to the node title of the selected node.'), + ); + + return $form; +} + +/** + * Validate a node. + */ +function ctools_context_node_edit_form_settings_form_validate($form, &$form_state) { + // Validate the autocomplete + if (empty($form_state['values']['nid']) && empty($form_state['values']['node'])) { + form_error($form['node'], t('You must select a node.')); + return; + } + + if (empty($form_state['values']['node'])) { + return; + } + + $nid = $form_state['values']['node']; + $preg_matches = array(); + $match = preg_match('/\[id: (\d+)\]/', $nid, $preg_matches); + if (!$match) { + $match = preg_match('/^id: (\d+)/', $nid, $preg_matches); + } + + if ($match) { + $nid = $preg_matches[1]; + } + if (is_numeric($nid)) { + $node = db_query('SELECT nid, status FROM {node} WHERE nid = :nid', array(':nid' => $nid))->fetchObject(); + } + else { + $node = db_query('SELECT nid, status FROM {node} WHERE LOWER(title) = LOWER(:title)', array(':title' => $nid))->fetchObject(); + } + + // Do not allow unpublished nodes to be selected by unprivileged users + if (!$node || (empty($node->status) && !(user_access('administer nodes')))) { + form_error($form['node'], t('Invalid node selected.')); + } + else { + form_set_value($form['nid'], $node->nid, $form_state); + } +} + +function ctools_context_node_edit_form_settings_form_submit($form, &$form_state) { + if ($form_state['values']['set_identifier']) { + $node = node_load($form_state['values']['nid']); + $form_state['values']['identifier'] = $node->title; + } + + // This will either be the value set previously or a value set by the + // validator. + $form_state['conf']['nid'] = $form_state['values']['nid']; +} + +/** + * Provide a list of ways that this context can be converted to a string. + */ +function ctools_context_node_edit_convert_list() { + // Pass through to the "node" context convert list. + $plugin = ctools_get_context('node'); + return ctools_context_node_convert_list(); +} + +/** + * Convert a context into a string. + */ +function ctools_context_node_edit_convert($context, $type) { + // Pass through to the "node" context convert list. + $plugin = ctools_get_context('node'); + return ctools_context_node_convert($context, $type); +} diff --git a/sites/all/modules/ctools/plugins/contexts/string.inc b/sites/all/modules/ctools/plugins/contexts/string.inc new file mode 100644 index 000000000..e731ab74b --- /dev/null +++ b/sites/all/modules/ctools/plugins/contexts/string.inc @@ -0,0 +1,90 @@ +<?php + +/** + * @file + * + * Plugin to provide a string context + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('String'), + 'description' => t('A context that is just a string.'), + 'context' => 'ctools_context_create_string', + 'edit form' => 'ctools_context_string_settings_form', + 'defaults' => '', + 'keyword' => 'string', + 'no ui' => FALSE, + 'context name' => 'string', + 'convert list' => array( + 'raw' => t('Raw string'), + 'html_safe' => t('HTML-safe string'), + 'uppercase_words_html_safe' => t('Uppercase words HTML-safe string'), + ), + 'convert' => 'ctools_context_string_convert', + 'placeholder form' => array( + '#type' => 'textfield', + '#description' => t('Enter the string for this context.'), + ), +); + +/** + * It's important to remember that $conf is optional here, because contexts + * are not always created from the UI. + */ +function ctools_context_create_string($empty, $data = NULL, $conf = FALSE) { + // The input is expected to be an object as created by ctools_break_phrase + // which contains a group of string. + + $context = new ctools_context('string'); + $context->plugin = 'string'; + + if ($empty) { + return $context; + } + + if ($data !== FALSE ) { + // Support the array storage from the settings form but also handle direct input from arguments. + $context->data = is_array($data) ? $data['string'] : $data; + $context->title = ($conf) ? check_plain($data['identifier']) : check_plain($data); + return $context; + } +} + +/** + * Convert a context into a string. + */ +function ctools_context_string_convert($context, $type) { + switch ($type) { + case 'raw': + return $context->data; + case 'html_safe': + return check_plain($context->data); + case 'uppercase_words_html_safe': + return ucwords(str_replace('-', ' ', check_plain($context->data))); + } +} + +/** + * String settings form. + */ +function ctools_context_string_settings_form($form, &$form_state) { + $conf = &$form_state['conf']; + + $form['string'] = array( + '#title' => t('Enter the string'), + '#type' => 'textfield', + '#maxlength' => 512, + '#weight' => -10, + '#default_value' => $conf['string'], + ); + + return $form; +} + +function ctools_context_string_settings_form_submit($form, &$form_state) { + $form_state['conf']['string'] = $form_state['values']['string']; +} diff --git a/sites/all/modules/ctools/plugins/contexts/term.inc b/sites/all/modules/ctools/plugins/contexts/term.inc new file mode 100644 index 000000000..1d6d48e6f --- /dev/null +++ b/sites/all/modules/ctools/plugins/contexts/term.inc @@ -0,0 +1,166 @@ +<?php + +/** + * @file + * + * Plugin to provide a term context + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Taxonomy term"), + 'description' => t('A single taxonomy term object.'), + 'context' => 'ctools_context_create_term', + 'edit form' => 'ctools_context_term_settings_form', + 'defaults' => array( + 'vid' => '', + 'tid' => '', + ), + 'keyword' => 'term', + 'context name' => 'term', + 'convert list' => array( + 'tid' => t('Term ID'), + 'name' => t('Term name'), + 'name_dashed' => t('Term name, lowercased and spaces converted to dashes'), + 'description' => t('Term Description'), + 'vid' => t('Vocabulary ID'), + ), + 'convert' => 'ctools_context_term_convert', + // This context is deprecated and should not be usable in the UI. + 'no ui' => TRUE, + 'no required context ui' => TRUE, +); + +/** + * It's important to remember that $conf is optional here, because contexts + * are not always created from the UI. + */ +function ctools_context_create_term($empty, $data = NULL, $conf = FALSE) { + $context = new ctools_context('term'); + $context->plugin = 'term'; + + if ($empty) { + return $context; + } + + if ($conf && isset($data['tid'])) { + $data = taxonomy_term_load($data['tid']); + } + + if (!empty($data)) { + $context->data = $data; + $context->title = $data->name; + $context->argument = $data->tid; + $context->description = $data->description; + return $context; + } +} + +function ctools_context_term_settings_form($form, &$form_state) { + $conf = $form_state['conf']; + + $form['vid'] = array( + '#title' => t('Vocabulary'), + '#type' => 'select', + '#options' => array(), + '#description' => t('Select the vocabulary for this form.'), + '#id' => 'ctools-select-vid', + '#default_value' => $conf['vid'], + ); + + $description = ''; + if (!empty($conf['tid'])) { + $info = db_query('SELECT * FROM {taxonomy_term_data} WHERE tid = :tid', array(':tid' => $conf['tid']))->fetchObject(); + if ($info) { + $description = ' ' . t('Currently set to @term. Enter another term if you wish to change the term.', array('@term' => $info->name)); + } + } + + ctools_include('dependent'); + $options = array(); + + $form['taxonomy']['#tree'] = TRUE; + + foreach (taxonomy_get_vocabularies() as $vid => $vocabulary) { + $options[$vid] = $vocabulary->name; + $form['taxonomy'][$vocabulary->vid] = array( + '#type' => 'textfield', + '#description' => t('Select a term from @vocabulary.', array('@vocabulary' => $vocabulary->name)) . $description, + '#autocomplete_path' => 'taxonomy/autocomplete/' . $vocabulary->vid, + '#dependency' => array('ctools-select-vid' => array($vocabulary->vid)), + ); + + } + + $form['vid']['#options'] = $options; + + $form['tid'] = array( + '#type' => 'value', + '#value' => $conf['tid'], + ); + + $form['set_identifier'] = array( + '#type' => 'checkbox', + '#default_value' => FALSE, + '#title' => t('Reset identifier to term title'), + '#description' => t('If checked, the identifier will be reset to the term name of the selected term.'), + ); + + return $form; +} + +/** + * Validate a term. + */ +function ctools_context_term_settings_form_validate($form, &$form_state) { + // Validate the autocomplete + $vid = $form_state['values']['vid']; + if (empty($form_state['values']['tid']) && empty($form_state['values']['taxonomy'][$vid])) { + form_error($form['taxonomy'][$vid], t('You must select a term.')); + return; + } + + if (empty($form_state['values']['taxonomy'][$vid])) { + return; + } + + $term = db_query('SELECT tid FROM {taxonomy_term_data} WHERE LOWER(name) = LOWER(:name) AND vid = :vid', array(':name' => $form_state['values']['taxonomy'][$vid], ':vid' => $vid))->fetchObject(); + + if (!$term) { + form_error($form['taxonomy'][$vid], t('Invalid term selected.')); + } + else { + form_set_value($form['tid'], $term->tid, $form_state); + } +} + +function ctools_context_term_settings_form_submit($form, &$form_state) { + if ($form_state['values']['set_identifier']) { + $term = db_query('SELECT tid, name FROM {taxonomy_term_data} WHERE LOWER(tid) = :tid', array(':tid' => $form_state['values']['tid']))->fetchObject(); + $form_state['values']['identifier'] = $term->name; + } + + $form_state['conf']['tid'] = $form_state['values']['tid']; + $form_state['conf']['vid'] = $form_state['values']['vid']; +} + +/** + * Convert a context into a string. + */ +function ctools_context_term_convert($context, $type) { + switch ($type) { + case 'tid': + return $context->data->tid; + case 'name': + return $context->data->name; + case 'name_dashed': + return drupal_strtolower(str_replace(' ', '-', $context->data->name)); + case 'vid': + return $context->data->vid; + case 'description': + return $context->data->description; + } +} diff --git a/sites/all/modules/ctools/plugins/contexts/terms.inc b/sites/all/modules/ctools/plugins/contexts/terms.inc new file mode 100644 index 000000000..6c3ab3611 --- /dev/null +++ b/sites/all/modules/ctools/plugins/contexts/terms.inc @@ -0,0 +1,98 @@ +<?php + +/** + * @file + * + * Plugin to provide a terms context + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Taxonomy terms"), + 'description' => t('Multiple taxonomy terms, as a group.'), + 'context' => 'ctools_context_create_terms', + 'keyword' => 'terms', + // This context is deprecated and should not be usable in the UI. + 'no ui' => TRUE, + 'context name' => 'terms', + 'convert list' => array( + 'tid' => t('Term ID of first term'), + 'tids' => t('Term ID of all term, separated by + or ,'), + 'name' => t('Term name of first term'), + 'name_dashed' => t('Term name of first term, lowercased and spaces converted to dashes'), + 'names' => t('Term name of all terms, separated by + or ,'), + 'names_dashed' => t('Term name of all terms, separated by + or , and lowercased and spaces converted to dashes'), + 'vid' => t('Vocabulary ID of first term'), + ), + 'convert' => 'ctools_context_terms_convert', +); + +/** + * It's important to remember that $conf is optional here, because contexts + * are not always created from the UI. + */ +function ctools_context_create_terms($empty, $data = NULL, $conf = FALSE) { + // The input is expected to be an object as created by ctools_break_phrase + // which contains a group of terms. + + $context = new ctools_context(array('terms', 'entity:taxonomy_term')); + $context->plugin = 'terms'; + + if ($empty) { + return $context; + } + + if (!empty($data) && is_object($data)) { + $context->operator = $data->operator; + $context->tids = $data->value; + if (!isset($data->term)) { + // load the first term: + reset($context->tids); + $data->term = taxonomy_term_load(current($context->tids)); + } + $context->data = $data->term; + $context->title = $data->term->name; + $context->argument = implode($context->operator == 'or' ? '+' : ',', array_unique($context->tids)); + return $context; + } +} + +/** + * Convert a context into a string. + */ +function ctools_context_terms_convert($context, $type) { + switch ($type) { + case 'tid': + return $context->data->tid; + case 'tids': + return $context->argument; + case 'name': + return $context->data->name; + case 'name_dashed': + return drupal_strtolower(str_replace(' ', '-', $context->data->name)); + case 'names': + case 'names_dashed': + // We only run this query if this item was requested: + if (!isset($context->names)) { + if (empty($context->tids)) { + $context->names = ''; + } + else { + $result = db_query('SELECT tid, name FROM {taxonomy_term_data} WHERE tid IN (:tids)', array(':tids' => $context->tids)); + foreach ($result as $term) { + $names[$term->tid] = $term->name; + if ($type == 'names_dashed') { + $names[$term->tid] = drupal_strtolower(str_replace(' ', '-', $names[$term->tid])); + } + } + $context->names = implode($context->operator == 'or' ? ' + ' : ', ', $names); + } + } + return $context->names; + case 'vid': + return $context->data->vid; + } +} diff --git a/sites/all/modules/ctools/plugins/contexts/token.inc b/sites/all/modules/ctools/plugins/contexts/token.inc new file mode 100644 index 000000000..044557691 --- /dev/null +++ b/sites/all/modules/ctools/plugins/contexts/token.inc @@ -0,0 +1,62 @@ +<?php + +/** + * @file + * Provide a global context to allow for token support. + */ + +$plugin = array( + 'title' => t('Token'), + 'description' => t('A context that contains token replacements from token.module.'), + 'context' => 'ctools_context_create_token', // func to create context + 'context name' => 'token', + 'keyword' => 'token', + 'convert list' => 'ctools_context_token_convert_list', + 'convert' => 'ctools_context_token_convert', +); + +/** + * Create a context from manual configuration. + */ +function ctools_context_create_token($empty, $data = NULL, $conf = FALSE) { + $context = new ctools_context('token'); + $context->plugin = 'token'; + + return $context; +} + +/** + * Implementation of hook_ctools_context_convert_list(). + */ +function ctools_context_token_convert_list() { + $tokens = token_info(); + foreach ($tokens['types'] as $type => $type_info) { + if (empty($type_info['needs-data'])) { + $real_type = isset($type_info['type']) ? $type_info['type'] : $type; + foreach ($tokens['tokens'][$real_type] as $id => $info) { + $key = "$type:$id"; + if (!isset($list[$key])) { + $list[$key] = $type_info['name'] . ': ' . $info['name']; + } + } + } + } + + return $list; +} + +/** + * Implementation of hook_ctools_context_converter_alter(). + */ +function ctools_context_token_convert($context, $token) { + $tokens = token_info(); + list($type, $token) = explode(':', $token, 2); + $parts = explode(':', $token, 2); + $real_type = isset($tokens['types'][$type]['type']) ? $tokens['types'][$type]['type'] : $type; + if (isset($tokens['tokens'][$real_type][$parts[0]])) { + $values = token_generate($type, array($token => $token)); + if (isset($values[$token])) { + return $values[$token]; + } + } +} diff --git a/sites/all/modules/ctools/plugins/contexts/user.inc b/sites/all/modules/ctools/plugins/contexts/user.inc new file mode 100644 index 000000000..18781c760 --- /dev/null +++ b/sites/all/modules/ctools/plugins/contexts/user.inc @@ -0,0 +1,176 @@ +<?php + +/** + * @file + * + * Plugin to provide a user context + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("User"), + 'description' => t('A single user object.'), + 'context' => 'ctools_context_create_user', + 'edit form' => 'ctools_context_user_settings_form', + 'defaults' => array('type' => 'select', 'uid' => ''), + 'keyword' => 'user', + 'context name' => 'user', + 'convert list' => 'ctools_context_user_convert_list', + 'convert' => 'ctools_context_user_convert', + 'convert default' => 'name', + + // This context is deprecated and should not be usable in the UI. + 'no ui' => TRUE, + 'no required context ui' => TRUE, +); + +/** + * It's important to remember that $conf is optional here, because contexts + * are not always created from the UI. + */ +function ctools_context_create_user($empty, $data = NULL, $conf = FALSE) { + $context = new ctools_context(array('entity:user', 'entity', 'user')); + $context->plugin = 'user'; + + if ($empty) { + return $context; + } + + if ($conf) { + if ($data['type'] == 'current') { + global $user; + $data = user_load($user->uid); + if (user_is_logged_in()) { + $data->logged_in_user = TRUE; + } + } + else { + $data = user_load($data['uid']); + } + } + // Load entity if the data provided is a numeric value. This kind of data is + // passed by some relationships. + if (is_numeric($data)) { + $data = user_load($data); + } + + if (!empty($data)) { + $context->data = $data; + $context->title = isset($data->name) ? $data->name : t('Anonymous'); + $context->argument = $data->uid; + return $context; + } +} + +function ctools_context_user_settings_form($form, &$form_state) { + $conf = $form_state['conf']; + + ctools_include('dependent'); + $form['type'] = array( + '#title' => t('Enter the context type'), + '#type' => 'radios', + '#options' => array( + 'select' => t('Select a user'), + 'current' => t('Logged in user'), + ), + '#default_value' => $conf['type'], + ); + + $form['user'] = array( + '#title' => t('Enter a user name'), + '#type' => 'textfield', + '#maxlength' => 512, + '#autocomplete_path' => 'user/autocomplete', + '#dependency' => array('radio:type' => array('select')), + ); + + if (!empty($conf['uid'])) { + $info = user_load($conf['uid']); + if ($info) { + $form['user']['#description'] = t('Currently set to !link', array('!link' => theme('username', array('account' => $info)))); + } + } + + $form['uid'] = array( + '#type' => 'value', + '#value' => $conf['uid'], + ); + + $form['set_identifier'] = array( + '#type' => 'checkbox', + '#default_value' => FALSE, + '#title' => t('Reset identifier to username'), + '#description' => t('If checked, the identifier will be reset to the user name of the selected user.'), + '#dependency' => array('radio:context[context_settings][type]' => array('select')), + ); + + return $form; +} + +/** + * Validate a user. + */ +function ctools_context_user_settings_form_validate($form, &$form_state) { + if ($form_state['values']['type'] != 'select') { + return; + } + + // Validate the autocomplete + if (empty($form_state['values']['uid']) && empty($form_state['values']['user'])) { + form_error($form['user'], t('You must select a user.')); + return; + } + + if (empty($form_state['values']['user'])) { + return; + } + + $account = user_load_by_name($form_state['values']['user']); + + if (!$account) { + form_error($form['user'], t('Invalid user selected.')); + } + else { + form_set_value($form['uid'], $account->uid, $form_state); + } +} + +function ctools_context_user_settings_form_submit($form, &$form_state) { + if ($form_state['values']['set_identifier']) { + $account = user_load($form_state['values']['uid']); + $form_state['values']['identifier'] = $account->name; + } + + $form_state['conf']['type'] = $form_state['values']['type']; + $form_state['conf']['uid'] = $form_state['values']['uid']; +} + +/** + * Provide a list of replacements. + */ +function ctools_context_user_convert_list() { + $tokens = token_info(); + foreach ($tokens['tokens']['user'] as $id => $info) { + if (!isset($list[$id])) { + $list[$id] = $info['name']; + } + } + + return $list; +} + +/** + * Convert a context into a string. + */ +function ctools_context_user_convert($context, $type) { + $tokens = token_info(); + if (isset($tokens['tokens']['user'][$type])) { + $values = token_generate('user', array($type => $type), array('user' => $context->data)); + if (isset($values[$type])) { + return $values[$type]; + } + } +} diff --git a/sites/all/modules/ctools/plugins/contexts/user_edit_form.inc b/sites/all/modules/ctools/plugins/contexts/user_edit_form.inc new file mode 100644 index 000000000..a28c5990c --- /dev/null +++ b/sites/all/modules/ctools/plugins/contexts/user_edit_form.inc @@ -0,0 +1,192 @@ +<?php +/** + * @file + * + * Plugin to provide a user_edit_form context + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('User edit form'), + 'description' => t('A user edit form.'), + 'context' => 'ctools_context_create_user_edit_form', + 'edit form' => 'ctools_context_user_edit_form_settings_form', + 'defaults' => array('uid' => ''), + 'keyword' => 'user_edit', + 'context name' => 'user_edit_form', + 'convert list' => 'ctools_context_user_edit_convert_list', + 'convert' => 'ctools_context_user_edit_convert', + 'placeholder form' => array( + '#type' => 'textfield', + '#description' => t('Enter the user ID of a user for this argument:'), + ), +); + +/** + * It's important to remember that $conf is optional here, because contexts + * are not always created from the UI. + */ +function ctools_context_create_user_edit_form($empty, $user = NULL, $conf = FALSE) { + // Determine the user category. + $category = !empty($conf['category']) ? $conf['category'] : FALSE; + unset($conf['category']); + + // If no category was specified, use the default 'account'. + if (!$category) { + $category = 'account'; + } + // Return previously created contexts, per category. + static $created = array(); + if (!empty($created[$category])) { + return $created[$category]; + } + + $context = new ctools_context(array('form', 'user_edit', 'user_form', 'user_edit_form', 'user', 'entity:user')); + // Store this context for later. + $created[$category] = $context; + $context->plugin = 'user_edit_form'; + if ($empty) { + return $context; + } + + if (!empty($conf)) { + // In this case, $user is actually our $conf array. + $uid = is_array($user) && isset($user['uid']) ? $user['uid'] : (is_object($user) ? $user->uid : 0); + + if (module_exists('translation')) { + if ($translation = module_invoke('translation', 'user_uid', $uid, $GLOBALS['language']->language)) { + $uid = $translation; + $reload = TRUE; + } + } + + if (is_array($user) || !empty($reload)) { + $user = user_load($uid); + } + } + + if (!empty($user)) { + $form_id = 'user_profile_form'; + + $form_state = array('want form' => TRUE, 'build_info' => array('args' => array($user, $category))); + + $file = drupal_get_path('module', 'user') . '/user.pages.inc'; + require_once DRUPAL_ROOT . '/' . $file; + // This piece of information can let other modules know that more files + // need to be included if this form is loaded from cache: + $form_state['build_info']['files'] = array($file); + + $form = drupal_build_form($form_id, $form_state); + + // Fill in the 'node' portion of the context + $context->data = $user; + $context->title = isset($user->name) ? $user->name : ''; + $context->argument = $user->uid; + + $context->form = $form; + $context->form_state = &$form_state; + $context->form_id = $form_id; + $context->form_title = isset($user->name) ? $user->name : ''; + $context->restrictions['form'] = array('form'); + return $context; + } +} + +function ctools_context_user_edit_form_settings_form($form, &$form_state) { + $conf = &$form_state['conf']; + + $form['user'] = array( + '#title' => t('Enter the name or UID of a node'), + '#type' => 'textfield', + '#maxlength' => 512, + '#autocomplete_path' => 'ctools/autocomplete/user', + '#weight' => -10, + ); + + if (!empty($conf['uid'])) { + $info = db_query('SELECT * FROM {users} WHERE uid = :uid', array(':uid' => $conf['uid']))->fetchObject(); + if ($info) { + $link = l(t("'%name' [user id %uid]", array('%name' => $info->name, '%uid' => $info->uid)), "user/$info->uid", array('attributes' => array('target' => '_blank', 'title' => t('Open in new window')), 'html' => TRUE)); + $form['user']['#description'] = t('Currently set to !link', array('!link' => $link)); + } + } + + $form['uid'] = array( + '#type' => 'value', + '#value' => $conf['uid'], + ); + + $form['set_identifier'] = array( + '#type' => 'checkbox', + '#default_value' => FALSE, + '#title' => t('Reset identifier to user name'), + '#description' => t('If checked, the identifier will be reset to the user name of the selected user.'), + ); + + return $form; +} + +/** + * Validate a node. + */ +function ctools_context_user_edit_form_settings_form_validate($form, &$form_state) { + // Validate the autocomplete + if (empty($form_state['values']['uid']) && empty($form_state['values']['user'])) { + form_error($form['user'], t('You must select a user.')); + return; + } + + if (empty($form_state['values']['user'])) { + return; + } + + $uid = $form_state['values']['user']; + $preg_matches = array(); + $match = preg_match('/\[id: (\d+)\]/', $uid, $preg_matches); + if (!$match) { + $match = preg_match('/^id: (\d+)/', $uid, $preg_matches); + } + + if ($match) { + $uid = $preg_matches[1]; + } + if (is_numeric($uid)) { + $user = db_query('SELECT uid FROM {users} WHERE uid = :uid', array(':uid' => $uid))->fetchObject(); + } + else { + $user = db_query('SELECT uid FROM {users} WHERE LOWER(name) = LOWER(:name)', array(':name' => $uid))->fetchObject(); + } + + form_set_value($form['uid'], $user->uid, $form_state); +} +function ctools_context_user_edit_form_settings_form_submit($form, &$form_state) { + if ($form_state['values']['set_identifier']) { + $user = user_load($form_state['values']['uid']); + $form_state['values']['identifier'] = $user->name; + } + + // This will either be the value set previously or a value set by the + // validator. + $form_state['conf']['uid'] = $form_state['values']['uid']; +} + +/** + * Provide a list of ways that this context can be converted to a string. + */ +function ctools_context_user_edit_convert_list() { + // Pass through to the "node" context convert list. + $plugin = ctools_get_context('user'); + return ctools_context_user_convert_list(); +} + +/** + * Convert a context into a string. + */ +function ctools_context_user_edit_convert($context, $type) { + // Pass through to the "node" context convert list. + $plugin = ctools_get_context('user'); + return ctools_context_user_convert($context, $type); +} diff --git a/sites/all/modules/ctools/plugins/contexts/vocabulary.inc b/sites/all/modules/ctools/plugins/contexts/vocabulary.inc new file mode 100644 index 000000000..9c5d4cf79 --- /dev/null +++ b/sites/all/modules/ctools/plugins/contexts/vocabulary.inc @@ -0,0 +1,72 @@ +<?php + +/** + * @file + * + * Plugin to provide a vocabulary context + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t("Taxonomy vocabulary"), + 'description' => t('A single taxonomy vocabulary object.'), + 'context' => 'ctools_context_create_vocabulary', + 'edit form' => 'ctools_context_vocabulary_settings_form', + 'defaults' => array('vid' => ''), + 'keyword' => 'vocabulary', + 'context name' => 'vocabulary', + // This context is deprecated and should not be usable in the UI. + 'no ui' => TRUE, + 'no required context ui' => TRUE, + 'superceded by' => 'entity:taxonomy_vocabulary', +); + +/** + * It's important to remember that $conf is optional here, because contexts + * are not always created from the UI. + */ +function ctools_context_create_vocabulary($empty, $data = NULL, $conf = FALSE) { + $context = new ctools_context('vocabulary'); + $context->plugin = 'vocabulary'; + + if ($empty) { + return $context; + } + + if ($conf && isset($data['vid'])) { + $data = taxonomy_vocabulary_load($data['vid']); + } + + if (!empty($data)) { + $context->data = $data; + $context->title = $data->name; + $context->argument = $data->vid; + return $context; + } +} + +function ctools_context_vocabulary_settings_form($form, &$form_state) { + $conf = $form_state['conf']; + + $options = array(); + foreach (taxonomy_get_vocabularies() as $vid => $vocabulary) { + $options[$vid] = $vocabulary->name; + } + + $form['vid'] = array( + '#title' => t('Vocabulary'), + '#type' => 'select', + '#options' => $options, + '#default_value' => $conf['vid'], + '#description' => t('Select the vocabulary for this form.'), + ); + + return $form; +} + +function ctools_context_vocabulary_settings_form_submit($form, &$form_state) { + $form_state['conf']['vid'] = $form_state['values']['vid']; +} diff --git a/sites/all/modules/ctools/plugins/export_ui/ctools_export_ui.class.php b/sites/all/modules/ctools/plugins/export_ui/ctools_export_ui.class.php new file mode 100644 index 000000000..60c1dc288 --- /dev/null +++ b/sites/all/modules/ctools/plugins/export_ui/ctools_export_ui.class.php @@ -0,0 +1,1537 @@ +<?php + +/** + * Base class for export UI. + */ +class ctools_export_ui { + var $plugin; + var $name; + var $options = array(); + + /** + * Fake constructor -- this is easier to deal with than the real + * constructor because we are retaining PHP4 compatibility, which + * would require all child classes to implement their own constructor. + */ + function init($plugin) { + ctools_include('export'); + + $this->plugin = $plugin; + } + + /** + * Get a page title for the current page from our plugin strings. + */ + function get_page_title($op, $item = NULL) { + if (empty($this->plugin['strings']['title'][$op])) { + return; + } + + // Replace %title that might be there with the exportable title. + $title = $this->plugin['strings']['title'][$op]; + if (!empty($item)) { + $export_key = $this->plugin['export']['key']; + $title = (str_replace('%title', check_plain($item->{$export_key}), $title)); + } + + return $title; + } + + /** + * Called by ctools_export_ui_load to load the item. + * + * This can be overridden for modules that want to be able to export + * items currently being edited, for example. + */ + function load_item($item_name) { + $item = ctools_export_crud_load($this->plugin['schema'], $item_name); + return empty($item) ? FALSE : $item; + } + + // ------------------------------------------------------------------------ + // Menu item manipulation + + /** + * hook_menu() entry point. + * + * Child implementations that need to add or modify menu items should + * probably call parent::hook_menu($items) and then modify as needed. + */ + function hook_menu(&$items) { + // During upgrades, the schema can be empty as this is called prior to + // actual update functions being run. Ensure that we can cope with this + // situation. + if (empty($this->plugin['schema'])) { + return; + } + + $prefix = ctools_export_ui_plugin_base_path($this->plugin); + + if (isset($this->plugin['menu']['items']) && is_array($this->plugin['menu']['items'])) { + $my_items = array(); + foreach ($this->plugin['menu']['items'] as $item) { + // Add menu item defaults. + $item += array( + 'file' => 'export-ui.inc', + 'file path' => drupal_get_path('module', 'ctools') . '/includes', + ); + + $path = !empty($item['path']) ? $prefix . '/' . $item['path'] : $prefix; + unset($item['path']); + $my_items[$path] = $item; + } + $items += $my_items; + } + } + + /** + * Menu callback to determine if an operation is accessible. + * + * This function enforces a basic access check on the configured perm + * string, and then additional checks as needed. + * + * @param $op + * The 'op' of the menu item, which is defined by 'allowed operations' + * and embedded into the arguments in the menu item. + * @param $item + * If an op that works on an item, then the item object, otherwise NULL. + * + * @return + * TRUE if the current user has access, FALSE if not. + */ + function access($op, $item) { + if (!user_access($this->plugin['access'])) { + return FALSE; + } + + // More fine-grained access control: + if ($op == 'add' && !user_access($this->plugin['create access'])) { + return FALSE; + } + + // More fine-grained access control: + if (($op == 'revert' || $op == 'delete') && !user_access($this->plugin['delete access'])) { + return FALSE; + } + + // If we need to do a token test, do it here. + if (!empty($this->plugin['allowed operations'][$op]['token']) && (!isset($_GET['token']) || !drupal_valid_token($_GET['token'], $op))) { + return FALSE; + } + + switch ($op) { + case 'import': + return user_access('use ctools import'); + case 'revert': + return ($item->export_type & EXPORT_IN_DATABASE) && ($item->export_type & EXPORT_IN_CODE); + case 'delete': + return ($item->export_type & EXPORT_IN_DATABASE) && !($item->export_type & EXPORT_IN_CODE); + case 'disable': + return empty($item->disabled); + case 'enable': + return !empty($item->disabled); + default: + return TRUE; + } + } + + // ------------------------------------------------------------------------ + // These methods are the API for generating the list of exportable items. + + /** + * Master entry point for handling a list. + * + * It is unlikely that a child object will need to override this method, + * unless the listing mechanism is going to be highly specialized. + */ + function list_page($js, $input) { + $this->items = ctools_export_crud_load_all($this->plugin['schema'], $js); + + // Respond to a reset command by clearing session and doing a drupal goto + // back to the base URL. + if (isset($input['op']) && $input['op'] == t('Reset')) { + unset($_SESSION['ctools_export_ui'][$this->plugin['name']]); + if (!$js) { + drupal_goto($_GET['q']); + } + // clear everything but form id, form build id and form token: + $keys = array_keys($input); + foreach ($keys as $id) { + if (!in_array($id, array('form_id', 'form_build_id', 'form_token'))) { + unset($input[$id]); + } + } + $replace_form = TRUE; + } + + // If there is no input, check to see if we have stored input in the + // session. + if (!isset($input['form_id'])) { + if (isset($_SESSION['ctools_export_ui'][$this->plugin['name']]) && is_array($_SESSION['ctools_export_ui'][$this->plugin['name']])) { + $input = $_SESSION['ctools_export_ui'][$this->plugin['name']]; + } + } + else { + $_SESSION['ctools_export_ui'][$this->plugin['name']] = $input; + unset($_SESSION['ctools_export_ui'][$this->plugin['name']]['q']); + } + + // This is where the form will put the output. + $this->rows = array(); + $this->sorts = array(); + + $form_state = array( + 'plugin' => $this->plugin, + 'input' => $input, + 'rerender' => TRUE, + 'no_redirect' => TRUE, + 'object' => &$this, + ); + if (!isset($form_state['input']['form_id'])) { + $form_state['input']['form_id'] = 'ctools_export_ui_list_form'; + } + + // If we do any form rendering, it's to completely replace a form on the + // page, so don't let it force our ids to change. + if ($js && isset($_POST['ajax_html_ids'])) { + unset($_POST['ajax_html_ids']); + } + + $form = drupal_build_form('ctools_export_ui_list_form', $form_state); + $form = drupal_render($form); + + $output = $this->list_header($form_state) . $this->list_render($form_state) . $this->list_footer($form_state); + + if (!$js) { + $this->list_css(); + return $form . $output; + } + + $commands = array(); + $commands[] = ajax_command_replace('#ctools-export-ui-list-items', $output); + if (!empty($replace_form)) { + $commands[] = ajax_command_replace('#ctools-export-ui-list-form', $form); + } + print ajax_render($commands); + ajax_footer(); + } + + /** + * Create the filter/sort form at the top of a list of exports. + * + * This handles the very default conditions, and most lists are expected + * to override this and call through to parent::list_form() in order to + * get the base form and then modify it as necessary to add search + * gadgets for custom fields. + */ + function list_form(&$form, &$form_state) { + // This forces the form to *always* treat as submitted which is + // necessary to make it work. + $form['#token'] = FALSE; + if (empty($form_state['input'])) { + $form["#post"] = TRUE; + } + + // Add the 'q' in if we are not using clean URLs or it can get lost when + // using this kind of form. + if (!variable_get('clean_url', FALSE)) { + $form['q'] = array( + '#type' => 'hidden', + '#value' => $_GET['q'], + ); + } + + $all = array('all' => t('- All -')); + + $form['top row'] = array( + '#prefix' => '<div class="ctools-export-ui-row ctools-export-ui-top-row clearfix">', + '#suffix' => '</div>', + ); + + $form['bottom row'] = array( + '#prefix' => '<div class="ctools-export-ui-row ctools-export-ui-bottom-row clearfix">', + '#suffix' => '</div>', + ); + + $form['top row']['storage'] = array( + '#type' => 'select', + '#title' => t('Storage'), + '#options' => $all + array( + t('Normal') => t('Normal'), + t('Default') => t('Default'), + t('Overridden') => t('Overridden'), + ), + '#default_value' => 'all', + ); + + $form['top row']['disabled'] = array( + '#type' => 'select', + '#title' => t('Enabled'), + '#options' => $all + array( + '0' => t('Enabled'), + '1' => t('Disabled') + ), + '#default_value' => 'all', + ); + + $form['top row']['search'] = array( + '#type' => 'textfield', + '#title' => t('Search'), + ); + + $form['bottom row']['order'] = array( + '#type' => 'select', + '#title' => t('Sort by'), + '#options' => $this->list_sort_options(), + '#default_value' => 'disabled', + ); + + $form['bottom row']['sort'] = array( + '#type' => 'select', + '#title' => t('Order'), + '#options' => array( + 'asc' => t('Up'), + 'desc' => t('Down'), + ), + '#default_value' => 'asc', + ); + + $form['bottom row']['submit'] = array( + '#type' => 'submit', + '#id' => 'ctools-export-ui-list-items-apply', + '#value' => t('Apply'), + '#attributes' => array('class' => array('use-ajax-submit ctools-auto-submit-click')), + ); + + $form['bottom row']['reset'] = array( + '#type' => 'submit', + '#id' => 'ctools-export-ui-list-items-apply', + '#value' => t('Reset'), + '#attributes' => array('class' => array('use-ajax-submit')), + ); + + $form['#prefix'] = '<div class="clearfix">'; + $form['#suffix'] = '</div>'; + $form['#attached']['js'] = array(ctools_attach_js('auto-submit')); + $form['#attached']['library'][] = array('system', 'drupal.ajax'); + $form['#attached']['library'][] = array('system', 'jquery.form'); + $form['#attributes'] = array('class' => array('ctools-auto-submit-full-form')); + } + + /** + * Validate the filter/sort form. + * + * It is very rare that a filter form needs validation, but if it is + * needed, override this. + */ + function list_form_validate(&$form, &$form_state) { } + + /** + * Submit the filter/sort form. + * + * This submit handler is actually responsible for building up all of the + * rows that will later be rendered, since it is doing the filtering and + * sorting. + * + * For the most part, you should not need to override this method, as the + * fiddly bits call through to other functions. + */ + function list_form_submit(&$form, &$form_state) { + // Filter and re-sort the pages. + $plugin = $this->plugin; + + $prefix = ctools_export_ui_plugin_base_path($plugin); + + foreach ($this->items as $name => $item) { + // Call through to the filter and see if we're going to render this + // row. If it returns TRUE, then this row is filtered out. + if ($this->list_filter($form_state, $item)) { + continue; + } + + $operations = $this->build_operations($item); + + $this->list_build_row($item, $form_state, $operations); + } + + // Now actually sort + if ($form_state['values']['sort'] == 'desc') { + arsort($this->sorts); + } + else { + asort($this->sorts); + } + + // Nuke the original. + $rows = $this->rows; + $this->rows = array(); + // And restore. + foreach ($this->sorts as $name => $title) { + $this->rows[$name] = $rows[$name]; + } + } + + /** + * Determine if a row should be filtered out. + * + * This handles the default filters for the export UI list form. If you + * added additional filters in list_form() then this is where you should + * handle them. + * + * @return + * TRUE if the item should be excluded. + */ + function list_filter($form_state, $item) { + $schema = ctools_export_get_schema($this->plugin['schema']); + if ($form_state['values']['storage'] != 'all' && $form_state['values']['storage'] != $item->{$schema['export']['export type string']}) { + return TRUE; + } + + if ($form_state['values']['disabled'] != 'all' && $form_state['values']['disabled'] != !empty($item->disabled)) { + return TRUE; + } + + if ($form_state['values']['search']) { + $search = strtolower($form_state['values']['search']); + foreach ($this->list_search_fields() as $field) { + if (strpos(strtolower($item->$field), $search) !== FALSE) { + $hit = TRUE; + break; + } + } + if (empty($hit)) { + return TRUE; + } + } + } + + /** + * Provide a list of fields to test against for the default "search" widget. + * + * This widget will search against whatever fields are configured here. By + * default it will attempt to search against the name, title and description fields. + */ + function list_search_fields() { + $fields = array( + $this->plugin['export']['key'], + ); + + if (!empty($this->plugin['export']['admin_title'])) { + $fields[] = $this->plugin['export']['admin_title']; + } + if (!empty($this->plugin['export']['admin_description'])) { + $fields[] = $this->plugin['export']['admin_description']; + } + + return $fields; + } + + /** + * Provide a list of sort options. + * + * Override this if you wish to provide more or change how these work. + * The actual handling of the sorting will happen in build_row(). + */ + function list_sort_options() { + if (!empty($this->plugin['export']['admin_title'])) { + $options = array( + 'disabled' => t('Enabled, title'), + $this->plugin['export']['admin_title'] => t('Title'), + ); + } + else { + $options = array( + 'disabled' => t('Enabled, name'), + ); + } + + $options += array( + 'name' => t('Name'), + 'storage' => t('Storage'), + ); + + return $options; + } + + /** + * Add listing CSS to the page. + * + * Override this if you need custom CSS for your list. + */ + function list_css() { + ctools_add_css('export-ui-list'); + } + + /** + * Builds the operation links for a specific exportable item. + */ + function build_operations($item) { + $plugin = $this->plugin; + $schema = ctools_export_get_schema($plugin['schema']); + $operations = $plugin['allowed operations']; + $operations['import'] = FALSE; + + if ($item->{$schema['export']['export type string']} == t('Normal')) { + $operations['revert'] = FALSE; + } + elseif ($item->{$schema['export']['export type string']} == t('Overridden')) { + $operations['delete'] = FALSE; + } + else { + $operations['revert'] = FALSE; + $operations['delete'] = FALSE; + } + if (empty($item->disabled)) { + $operations['enable'] = FALSE; + } + else { + $operations['disable'] = FALSE; + } + + $allowed_operations = array(); + + foreach ($operations as $op => $info) { + if (!empty($info)) { + $allowed_operations[$op] = array( + 'title' => $info['title'], + 'href' => ctools_export_ui_plugin_menu_path($plugin, $op, $item->{$this->plugin['export']['key']}), + ); + if (!empty($info['ajax'])) { + $allowed_operations[$op]['attributes'] = array('class' => array('use-ajax')); + } + if (!empty($info['token'])) { + $allowed_operations[$op]['query'] = array('token' => drupal_get_token($op)); + } + } + } + + return $allowed_operations; + } + + /** + * Build a row based on the item. + * + * By default all of the rows are placed into a table by the render + * method, so this is building up a row suitable for theme('table'). + * This doesn't have to be true if you override both. + */ + function list_build_row($item, &$form_state, $operations) { + // Set up sorting + $name = $item->{$this->plugin['export']['key']}; + $schema = ctools_export_get_schema($this->plugin['schema']); + + // Note: $item->{$schema['export']['export type string']} should have already been set up by export.inc so + // we can use it safely. + switch ($form_state['values']['order']) { + case 'disabled': + $this->sorts[$name] = empty($item->disabled) . $name; + break; + case 'title': + $this->sorts[$name] = $item->{$this->plugin['export']['admin_title']}; + break; + case 'name': + $this->sorts[$name] = $name; + break; + case 'storage': + $this->sorts[$name] = $item->{$schema['export']['export type string']} . $name; + break; + } + + $this->rows[$name]['data'] = array(); + $this->rows[$name]['class'] = !empty($item->disabled) ? array('ctools-export-ui-disabled') : array('ctools-export-ui-enabled'); + + // If we have an admin title, make it the first row. + if (!empty($this->plugin['export']['admin_title'])) { + $this->rows[$name]['data'][] = array('data' => check_plain($item->{$this->plugin['export']['admin_title']}), 'class' => array('ctools-export-ui-title')); + } + $this->rows[$name]['data'][] = array('data' => check_plain($name), 'class' => array('ctools-export-ui-name')); + $this->rows[$name]['data'][] = array('data' => check_plain($item->{$schema['export']['export type string']}), 'class' => array('ctools-export-ui-storage')); + + $ops = theme('links__ctools_dropbutton', array('links' => $operations, 'attributes' => array('class' => array('links', 'inline')))); + + $this->rows[$name]['data'][] = array('data' => $ops, 'class' => array('ctools-export-ui-operations')); + + // Add an automatic mouseover of the description if one exists. + if (!empty($this->plugin['export']['admin_description'])) { + $this->rows[$name]['title'] = $item->{$this->plugin['export']['admin_description']}; + } + } + + /** + * Provide the table header. + * + * If you've added columns via list_build_row() but are still using a + * table, override this method to set up the table header. + */ + function list_table_header() { + $header = array(); + if (!empty($this->plugin['export']['admin_title'])) { + $header[] = array('data' => t('Title'), 'class' => array('ctools-export-ui-title')); + } + + $header[] = array('data' => t('Name'), 'class' => array('ctools-export-ui-name')); + $header[] = array('data' => t('Storage'), 'class' => array('ctools-export-ui-storage')); + $header[] = array('data' => t('Operations'), 'class' => array('ctools-export-ui-operations')); + + return $header; + } + + /** + * Render all of the rows together. + * + * By default we place all of the rows in a table, and this should be the + * way most lists will go. + * + * Whatever you do if this method is overridden, the ID is important for AJAX + * so be sure it exists. + */ + function list_render(&$form_state) { + $table = array( + 'header' => $this->list_table_header(), + 'rows' => $this->rows, + 'attributes' => array('id' => 'ctools-export-ui-list-items'), + 'empty' => $this->plugin['strings']['message']['no items'], + ); + return theme('table', $table); + } + + /** + * Render a header to go before the list. + * + * This will appear after the filter/sort widgets. + */ + function list_header($form_state) { } + + /** + * Render a footer to go after thie list. + * + * This is a good place to add additional links. + */ + function list_footer($form_state) { } + + // ------------------------------------------------------------------------ + // These methods are the API for adding/editing exportable items + + /** + * Perform a drupal_goto() to the location provided by the plugin for the + * operation. + * + * @param $op + * The operation to use. A string must exist in $this->plugin['redirect'] + * for this operation. + * @param $item + * The item in use; this may be necessary as item IDs are often embedded in + * redirects. + */ + function redirect($op, $item = NULL) { + if (isset($this->plugin['redirect'][$op])) { + $destination = (array) $this->plugin['redirect'][$op]; + if ($item) { + $export_key = $this->plugin['export']['key']; + $destination[0] = str_replace('%ctools_export_ui', $item->{$export_key}, $destination[0]); + } + call_user_func_array('drupal_goto', $destination); + } + else { + // If the operation isn't set, fall back to the plugin's base path. + drupal_goto(ctools_export_ui_plugin_base_path($this->plugin)); + } + } + + function add_page($js, $input, $step = NULL) { + drupal_set_title($this->get_page_title('add'), PASS_THROUGH); + + // If a step not set, they are trying to create a new item. If a step + // is set, they're in the process of creating an item. + if (!empty($this->plugin['use wizard']) && !empty($step)) { + $item = $this->edit_cache_get(NULL, 'add'); + } + if (empty($item)) { + $item = ctools_export_crud_new($this->plugin['schema']); + } + + $form_state = array( + 'plugin' => $this->plugin, + 'object' => &$this, + 'ajax' => $js, + 'item' => $item, + 'op' => 'add', + 'form type' => 'add', + 'rerender' => TRUE, + 'no_redirect' => TRUE, + 'step' => $step, + // Store these in case additional args are needed. + 'function args' => func_get_args(), + ); + + $output = $this->edit_execute_form($form_state); + if (!empty($form_state['executed']) && empty($form_state['rebuild'])) { + $this->redirect($form_state['op'], $form_state['item']); + } + + return $output; + } + + /** + * Main entry point to edit an item. + */ + function edit_page($js, $input, $item, $step = NULL) { + drupal_set_title($this->get_page_title('edit', $item), PASS_THROUGH); + + // Check to see if there is a cached item to get if we're using the wizard. + if (!empty($this->plugin['use wizard'])) { + $cached = $this->edit_cache_get($item, 'edit'); + if (!empty($cached)) { + $item = $cached; + } + } + + $form_state = array( + 'plugin' => $this->plugin, + 'object' => &$this, + 'ajax' => $js, + 'item' => $item, + 'op' => 'edit', + 'form type' => 'edit', + 'rerender' => TRUE, + 'no_redirect' => TRUE, + 'step' => $step, + // Store these in case additional args are needed. + 'function args' => func_get_args(), + ); + + $output = $this->edit_execute_form($form_state); + if (!empty($form_state['executed']) && empty($form_state['rebuild'])) { + $this->redirect($form_state['op'], $form_state['item']); + } + + return $output; + } + + /** + * Main entry point to clone an item. + */ + function clone_page($js, $input, $original, $step = NULL) { + drupal_set_title($this->get_page_title('clone', $original), PASS_THROUGH); + + // If a step not set, they are trying to create a new clone. If a step + // is set, they're in the process of cloning an item. + if (!empty($this->plugin['use wizard']) && !empty($step)) { + $item = $this->edit_cache_get(NULL, 'clone'); + } + if (empty($item)) { + // To make a clone of an item, we first export it and then re-import it. + // Export the handler, which is a fantastic way to clean database IDs out of it. + $export = ctools_export_crud_export($this->plugin['schema'], $original); + $item = ctools_export_crud_import($this->plugin['schema'], $export); + + if (!empty($input[$this->plugin['export']['key']])) { + $item->{$this->plugin['export']['key']} = $input[$this->plugin['export']['key']]; + } + else { + $item->{$this->plugin['export']['key']} = 'clone_of_' . $item->{$this->plugin['export']['key']}; + } + } + + // Tabs and breadcrumb disappearing, this helps alleviate through cheating. + // ...not sure this this is the best way. + $trail = menu_set_active_item(ctools_export_ui_plugin_base_path($this->plugin)); + + $name = $original->{$this->plugin['export']['key']}; + + $form_state = array( + 'plugin' => $this->plugin, + 'object' => &$this, + 'ajax' => $js, + 'item' => $item, + 'op' => 'add', + 'form type' => 'clone', + 'original name' => $name, + 'rerender' => TRUE, + 'no_redirect' => TRUE, + 'step' => $step, + // Store these in case additional args are needed. + 'function args' => func_get_args(), + ); + + $output = $this->edit_execute_form($form_state); + if (!empty($form_state['executed']) && empty($form_state['rebuild'])) { + $this->redirect($form_state['op'], $form_state['item']); + } + + return $output; + } + + /** + * Execute the form. + * + * Add and Edit both funnel into this, but they have a few different + * settings. + */ + function edit_execute_form(&$form_state) { + if (!empty($this->plugin['use wizard'])) { + return $this->edit_execute_form_wizard($form_state); + } + else { + return $this->edit_execute_form_standard($form_state); + } + } + + /** + * Execute the standard form for editing. + * + * By default, export UI will provide a single form for editing an object. + */ + function edit_execute_form_standard(&$form_state) { + $output = drupal_build_form('ctools_export_ui_edit_item_form', $form_state); + if (!empty($form_state['executed']) && empty($form_state['rebuild'])) { + $this->edit_save_form($form_state); + } + + return $output; + } + + /** + * Get the form info for the wizard. + * + * This gets the form info out of the plugin, then adds defaults based on + * how we want edit forms to work. + * + * Overriding this can allow child UIs to tweak this info for specialized + * wizards. + * + * @param array $form_state + * The already created form state. + */ + function get_wizard_info(&$form_state) { + if (!isset($form_state['step'])) { + $form_state['step'] = NULL; + } + + $export_key = $this->plugin['export']['key']; + + // When cloning, the name of the item being cloned is referenced in the + // path, not the name of this item. + if ($form_state['form type'] == 'clone') { + $name = $form_state['original name']; + } + else { + $name = $form_state['item']->{$export_key}; + } + + $form_info = !empty($this->plugin['form info']) ? $this->plugin['form info'] : array(); + $form_info += array( + 'id' => 'ctools_export_ui_edit', + 'path' => ctools_export_ui_plugin_menu_path($this->plugin, $form_state['form type'], $name) . '/%step', + 'show trail' => TRUE, + 'free trail' => TRUE, + 'show back' => $form_state['form type'] == 'add', + 'show return' => FALSE, + 'show cancel' => TRUE, + 'finish callback' => 'ctools_export_ui_wizard_finish', + 'next callback' => 'ctools_export_ui_wizard_next', + 'back callback' => 'ctools_export_ui_wizard_back', + 'cancel callback' => 'ctools_export_ui_wizard_cancel', + 'order' => array(), + 'import order' => array( + 'import' => t('Import code'), + 'settings' => t('Settings'), + ), + ); + + // Set the order of forms based on the op if we have a specific one. + if (isset($form_info[$form_state['form type'] . ' order'])) { + $form_info['order'] = $form_info[$form_state['form type'] . ' order']; + } + + // We have generic fallback forms we can use if they are not specified, + // and they automatically delegate back to the UI object. Use these if + // not specified. + foreach ($form_info['order'] as $key => $title) { + if (empty($form_info['forms'][$key])) { + $form_info['forms'][$key] = array( + 'form id' => 'ctools_export_ui_edit_item_wizard_form', + ); + } + } + + // 'free trail' means the wizard can freely go back and form from item + // via the trail and not with next/back buttons. + if ($form_state['form type'] == 'add' || ($form_state['form type'] == 'import' && empty($form_state['item']->{$export_key}))) { + $form_info['free trail'] = FALSE; + } + + return $form_info; + } + + /** + * Execute the wizard for editing. + * + * For complex objects, sometimes a wizard is needed. This is normally + * activated by setting 'use wizard' => TRUE in the plugin definition + * and then creating a 'form info' array to feed the wizard the data + * it needs. + * + * When creating this wizard, the plugin is responsible for defining all forms + * that will be utilized with the wizard. + * + * Using 'add order' or 'edit order' can be used to ensure that add/edit order + * is different. + */ + function edit_execute_form_wizard(&$form_state) { + $form_info = $this->get_wizard_info($form_state); + + // If there aren't any forms set, fail. + if (empty($form_info['order'])) { + return MENU_NOT_FOUND; + } + + // Figure out if this is a new instance of the wizard + if (empty($form_state['step'])) { + $order = array_keys($form_info['order']); + $form_state['step'] = reset($order); + } + + if (empty($form_info['order'][$form_state['step']]) && empty($form_info['forms'][$form_state['step']])) { + return MENU_NOT_FOUND; + } + + ctools_include('wizard'); + $output = ctools_wizard_multistep_form($form_info, $form_state['step'], $form_state); + if (!empty($form_state['complete'])) { + $this->edit_save_form($form_state); + } + else if ($output && !empty($form_state['item']->export_ui_item_is_cached)) { + // @todo this should be in the plugin strings + drupal_set_message(t('You have unsaved changes. These changes will not be made permanent until you click <em>Save</em>.'), 'warning'); + } + + // Unset the executed flag if any non-wizard button was pressed. Those + // buttons require special handling by whatever client is operating them. + if (!empty($form_state['executed']) && empty($form_state['clicked_button']['#wizard type'])) { + unset($form_state['executed']); + } + return $output; + } + + /** + * Wizard 'back' callback when using a wizard to edit an item. + * + * The wizard callback delegates this back to the object. + */ + function edit_wizard_back(&$form_state) { + // This only exists so child implementations can use it. + } + + /** + * Wizard 'next' callback when using a wizard to edit an item. + * + * The wizard callback delegates this back to the object. + */ + function edit_wizard_next(&$form_state) { + $this->edit_cache_set($form_state['item'], $form_state['form type']); + } + + /** + * Wizard 'cancel' callback when using a wizard to edit an item. + * + * The wizard callback delegates this back to the object. + */ + function edit_wizard_cancel(&$form_state) { + $this->edit_cache_clear($form_state['item'], $form_state['form type']); + } + + /** + * Wizard 'cancel' callback when using a wizard to edit an item. + * + * The wizard callback delegates this back to the object. + */ + function edit_wizard_finish(&$form_state) { + $form_state['complete'] = TRUE; + + // If we are importing, and overwrite was selected, delete the original so + // that this one writes properly. + if ($form_state['form type'] == 'import' && !empty($form_state['item']->export_ui_allow_overwrite)) { + ctools_export_crud_delete($this->plugin['schema'], $form_state['item']); + } + + $this->edit_cache_clear($form_state['item'], $form_state['form type']); + } + + /** + * Retrieve the item currently being edited from the object cache. + */ + function edit_cache_get($item, $op = 'edit') { + ctools_include('object-cache'); + if (is_string($item)) { + $name = $item; + } + else { + $name = $this->edit_cache_get_key($item, $op); + } + + $cache = ctools_object_cache_get('ctui_' . $this->plugin['name'], $name); + if ($cache) { + $cache->export_ui_item_is_cached = TRUE; + return $cache; + } + } + + /** + * Cache the item currently currently being edited. + */ + function edit_cache_set($item, $op = 'edit') { + ctools_include('object-cache'); + $name = $this->edit_cache_get_key($item, $op); + return $this->edit_cache_set_key($item, $name); + } + + function edit_cache_set_key($item, $name) { + return ctools_object_cache_set('ctui_' . $this->plugin['name'], $name, $item); + } + + /** + * Clear the object cache for the currently edited item. + */ + function edit_cache_clear($item, $op = 'edit') { + ctools_include('object-cache'); + $name = $this->edit_cache_get_key($item, $op); + return ctools_object_cache_clear('ctui_' . $this->plugin['name'], $name); + } + + /** + * Figure out what the cache key is for this object. + */ + function edit_cache_get_key($item, $op) { + $export_key = $this->plugin['export']['key']; + return $op == 'edit' ? $item->{$this->plugin['export']['key']} : "::$op"; + } + + /** + * Called to save the final product from the edit form. + */ + function edit_save_form($form_state) { + $item = &$form_state['item']; + $export_key = $this->plugin['export']['key']; + + $result = ctools_export_crud_save($this->plugin['schema'], $item); + + if ($result) { + $message = str_replace('%title', check_plain($item->{$export_key}), $this->plugin['strings']['confirmation'][$form_state['op']]['success']); + drupal_set_message($message); + } + else { + $message = str_replace('%title', check_plain($item->{$export_key}), $this->plugin['strings']['confirmation'][$form_state['op']]['fail']); + drupal_set_message($message, 'error'); + } + } + + /** + * Provide the actual editing form. + */ + function edit_form(&$form, &$form_state) { + $export_key = $this->plugin['export']['key']; + $item = $form_state['item']; + $schema = ctools_export_get_schema($this->plugin['schema']); + + if (!empty($this->plugin['export']['admin_title'])) { + $form['info'][$this->plugin['export']['admin_title']] = array( + '#type' => 'textfield', + '#title' => t('Administrative title'), + '#description' => t('This will appear in the administrative interface to easily identify it.'), + '#default_value' => $item->{$this->plugin['export']['admin_title']}, + ); + } + + $form['info'][$export_key] = array( + '#title' => t($schema['export']['key name']), + '#type' => 'textfield', + '#default_value' => $item->{$export_key}, + '#description' => t('The unique ID for this @export.', array('@export' => $this->plugin['title singular'])), + '#required' => TRUE, + '#maxlength' => 255, + ); + + if (!empty($this->plugin['export']['admin_title'])) { + $form['info'][$export_key]['#type'] = 'machine_name'; + $form['info'][$export_key]['#machine_name'] = array( + 'exists' => 'ctools_export_ui_edit_name_exists', + 'source' => array('info', $this->plugin['export']['admin_title']), + ); + } + + if ($form_state['op'] === 'edit') { + $form['info'][$export_key]['#disabled'] = TRUE; + $form['info'][$export_key]['#value'] = $item->{$export_key}; + } + + if (!empty($this->plugin['export']['admin_description'])) { + $form['info'][$this->plugin['export']['admin_description']] = array( + '#type' => 'textarea', + '#title' => t('Administrative description'), + '#default_value' => $item->{$this->plugin['export']['admin_description']}, + ); + } + + // Add plugin's form definitions. + if (!empty($this->plugin['form']['settings'])) { + // Pass $form by reference. + $this->plugin['form']['settings']($form, $form_state); + } + + // Add the buttons if the wizard is not in use. + if (empty($form_state['form_info'])) { + // Make sure that whatever happens, the buttons go to the bottom. + $form['buttons']['#weight'] = 100; + + // Add buttons. + $form['buttons']['submit'] = array( + '#type' => 'submit', + '#value' => t('Save'), + ); + + $form['buttons']['delete'] = array( + '#type' => 'submit', + '#value' => $item->export_type & EXPORT_IN_CODE ? t('Revert') : t('Delete'), + '#access' => $form_state['op'] === 'edit' && $item->export_type & EXPORT_IN_DATABASE, + '#submit' => array('ctools_export_ui_edit_item_form_delete'), + ); + } + } + + /** + * Validate callback for the edit form. + */ + function edit_form_validate(&$form, &$form_state) { + if (!empty($this->plugin['form']['validate'])) { + // Pass $form by reference. + $this->plugin['form']['validate']($form, $form_state); + } + } + + /** + * Perform a final validation check before allowing the form to be + * finished. + */ + function edit_finish_validate(&$form, &$form_state) { + if ($form_state['op'] != 'edit') { + // Validate the export key. Fake an element for form_error(). + $export_key = $this->plugin['export']['key']; + $element = array( + '#value' => $form_state['item']->{$export_key}, + '#parents' => array($export_key), + ); + $form_state['plugin'] = $this->plugin; + ctools_export_ui_edit_name_validate($element, $form_state); + } + } + + /** + * Handle the submission of the edit form. + * + * At this point, submission is successful. Our only responsibility is + * to copy anything out of values onto the item that we are able to edit. + * + * If the keys all match up to the schema, this method will not need to be + * overridden. + */ + function edit_form_submit(&$form, &$form_state) { + if (!empty($this->plugin['form']['submit'])) { + // Pass $form by reference. + $this->plugin['form']['submit']($form, $form_state); + } + + // Transfer data from the form to the $item based upon schema values. + $schema = ctools_export_get_schema($this->plugin['schema']); + foreach (array_keys($schema['fields']) as $key) { + if(isset($form_state['values'][$key])) { + $form_state['item']->{$key} = $form_state['values'][$key]; + } + } + } + + // ------------------------------------------------------------------------ + // These methods are the API for 'other' stuff with exportables such as + // enable, disable, import, export, delete + + /** + * Callback to enable a page. + */ + function enable_page($js, $input, $item) { + return $this->set_item_state(FALSE, $js, $input, $item); + } + + /** + * Callback to disable a page. + */ + function disable_page($js, $input, $item) { + return $this->set_item_state(TRUE, $js, $input, $item); + } + + /** + * Set an item's state to enabled or disabled and output to user. + * + * If javascript is in use, this will rebuild the list and send that back + * as though the filter form had been executed. + */ + function set_item_state($state, $js, $input, $item) { + ctools_export_crud_set_status($this->plugin['schema'], $item, $state); + + if (!$js) { + drupal_goto(ctools_export_ui_plugin_base_path($this->plugin)); + } + else { + return $this->list_page($js, $input); + } + } + + /** + * Page callback to delete an exportable item. + */ + function delete_page($js, $input, $item) { + $form_state = array( + 'plugin' => $this->plugin, + 'object' => &$this, + 'ajax' => $js, + 'item' => $item, + 'op' => $item->export_type & EXPORT_IN_CODE ? 'revert' : 'delete', + 'rerender' => TRUE, + 'no_redirect' => TRUE, + ); + + $output = drupal_build_form('ctools_export_ui_delete_confirm_form', $form_state); + if (!empty($form_state['executed'])) { + $this->delete_form_submit($form_state); + $this->redirect($form_state['op'], $item); + } + + return $output; + } + + /** + * Deletes exportable items from the database. + */ + function delete_form_submit(&$form_state) { + $item = $form_state['item']; + + ctools_export_crud_delete($this->plugin['schema'], $item); + $export_key = $this->plugin['export']['key']; + $message = str_replace('%title', check_plain($item->{$export_key}), $this->plugin['strings']['confirmation'][$form_state['op']]['success']); + drupal_set_message($message); + } + + /** + * Page callback to display export information for an exportable item. + */ + function export_page($js, $input, $item) { + drupal_set_title($this->get_page_title('export', $item), PASS_THROUGH); + return drupal_get_form('ctools_export_form', ctools_export_crud_export($this->plugin['schema'], $item), t('Export')); + } + + /** + * Page callback to import information for an exportable item. + */ + function import_page($js, $input, $step = NULL) { + drupal_set_title($this->get_page_title('import'), PASS_THROUGH); + // Import is basically a multi step wizard form, so let's go ahead and + // use CTools' wizard.inc for it. + + // If a step not set, they are trying to create a new item. If a step + // is set, they're in the process of creating an item. + if (!empty($step)) { + $item = $this->edit_cache_get(NULL, 'import'); + } + if (empty($item)) { + $item = ctools_export_crud_new($this->plugin['schema']); + } + + $form_state = array( + 'plugin' => $this->plugin, + 'object' => &$this, + 'ajax' => $js, + 'item' => $item, + 'op' => 'add', + 'form type' => 'import', + 'rerender' => TRUE, + 'no_redirect' => TRUE, + 'step' => $step, + // Store these in case additional args are needed. + 'function args' => func_get_args(), + ); + + // import always uses the wizard. + $output = $this->edit_execute_form_wizard($form_state); + if (!empty($form_state['executed'])) { + $this->redirect($form_state['op'], $form_state['item']); + } + + return $output; + } + + /** + * Import form. Provides simple helptext instructions and textarea for + * pasting a export definition. + */ + function edit_form_import(&$form, &$form_state) { + $form['help'] = array( + '#type' => 'item', + '#value' => $this->plugin['strings']['help']['import'], + ); + + $form['import'] = array( + '#title' => t('@plugin code', array('@plugin' => $this->plugin['title singular proper'])), + '#type' => 'textarea', + '#rows' => 10, + '#required' => TRUE, + '#default_value' => !empty($form_state['item']->export_ui_code) ? $form_state['item']->export_ui_code : '', + ); + + $form['overwrite'] = array( + '#title' => t('Allow import to overwrite an existing record.'), + '#type' => 'checkbox', + '#default_value' => !empty($form_state['item']->export_ui_allow_overwrite) ? $form_state['item']->export_ui_allow_overwrite : FALSE, + ); + } + + /** + * Import form validate handler. + * + * Evaluates code and make sure it creates an object before we continue. + */ + function edit_form_import_validate($form, &$form_state) { + $item = ctools_export_crud_import($this->plugin['schema'], $form_state['values']['import']); + if (is_string($item)) { + form_error($form['import'], t('Unable to get an import from the code. Errors reported: @errors', array('@errors' => $item))); + return; + } + + $form_state['item'] = $item; + $form_state['item']->export_ui_allow_overwrite = $form_state['values']['overwrite']; + $form_state['item']->export_ui_code = $form_state['values']['import']; + } + + /** + * Submit callback for import form. + * + * Stores the item in the session. + */ + function edit_form_import_submit($form, &$form_state) { + // The validate function already imported and stored the item. This + // function exists simply to prevent it from going to the default + // edit_form_submit() method. + } +} + +// ----------------------------------------------------------------------- +// Forms to be used with this class. +// +// Since Drupal's forms are completely procedural, these forms will +// mostly just be pass-throughs back to the object. + +/** + * Add all appropriate includes to forms so that caching the form + * still loads the files that we need. + */ +function _ctools_export_ui_add_form_files($form, &$form_state) { + ctools_form_include($form_state, 'export'); + ctools_form_include($form_state, 'export-ui'); + + // Also make sure the plugin .inc file is loaded. + ctools_form_include_file($form_state, $form_state['object']->plugin['path'] . '/' . $form_state['object']->plugin['file']); +} + +/** + * Form callback to handle the filter/sort form when listing items. + * + * This simply loads the object defined in the plugin and hands it off. + */ +function ctools_export_ui_list_form($form, &$form_state) { + $form_state['object']->list_form($form, $form_state); + return $form; +} + +/** + * Validate handler for ctools_export_ui_list_form. + */ +function ctools_export_ui_list_form_validate(&$form, &$form_state) { + $form_state['object']->list_form_validate($form, $form_state); +} + +/** + * Submit handler for ctools_export_ui_list_form. + */ +function ctools_export_ui_list_form_submit(&$form, &$form_state) { + $form_state['object']->list_form_submit($form, $form_state); +} + +/** + * Form callback to edit an exportable item. + * + * This simply loads the object defined in the plugin and hands it off. + */ +function ctools_export_ui_edit_item_form($form, &$form_state) { + // When called using #ajax via ajax_form_callback(), 'export' may + // not be included so include it here. + _ctools_export_ui_add_form_files($form, $form_state); + + $form_state['object']->edit_form($form, $form_state); + return $form; +} + +/** + * Validate handler for ctools_export_ui_edit_item_form. + */ +function ctools_export_ui_edit_item_form_validate(&$form, &$form_state) { + $form_state['object']->edit_form_validate($form, $form_state); +} + +/** + * Submit handler for ctools_export_ui_edit_item_form. + */ +function ctools_export_ui_edit_item_form_submit(&$form, &$form_state) { + $form_state['object']->edit_form_submit($form, $form_state); +} + +/** + * Submit handler to delete for ctools_export_ui_edit_item_form + * + * @todo Put this on a callback in the object. + */ +function ctools_export_ui_edit_item_form_delete(&$form, &$form_state) { + _ctools_export_ui_add_form_files($form, $form_state); + + $export_key = $form_state['plugin']['export']['key']; + $path = $form_state['item']->export_type & EXPORT_IN_CODE ? 'revert' : 'delete'; + + drupal_goto(ctools_export_ui_plugin_menu_path($form_state['plugin'], $path, $form_state['item']->{$export_key}), array('cancel_path' => $_GET['q'])); +} + +/** + * Validate that an export item name is acceptable and unique during add. + */ +function ctools_export_ui_edit_name_validate($element, &$form_state) { + $plugin = $form_state['plugin']; + // Check for string identifier sanity + if (!preg_match('!^[a-z0-9_]+$!', $element['#value'])) { + form_error($element, t('The export id can only consist of lowercase letters, underscores, and numbers.')); + return; + } + + // Check for name collision + if (empty($form_state['item']->export_ui_allow_overwrite) && $exists = ctools_export_crud_load($plugin['schema'], $element['#value'])) { + form_error($element, t('A @plugin with this name already exists. Please choose another name or delete the existing item before creating a new one.', array('@plugin' => $plugin['title singular']))); + } +} + +/** + * Test for #machine_name type to see if an export exists. + */ +function ctools_export_ui_edit_name_exists($name, $element, &$form_state) { + $plugin = $form_state['plugin']; + + return (empty($form_state['item']->export_ui_allow_overwrite) && ctools_export_crud_load($plugin['schema'], $name)); +} + +/** + * Delete/Revert confirm form. + * + * @todo -- call back into the object instead. + */ +function ctools_export_ui_delete_confirm_form($form, &$form_state) { + _ctools_export_ui_add_form_files($form, $form_state); + + $plugin = $form_state['plugin']; + $item = $form_state['item']; + + $form = array(); + + $export_key = $plugin['export']['key']; + $question = str_replace('%title', check_plain($item->{$export_key}), $plugin['strings']['confirmation'][$form_state['op']]['question']); + $path = (!empty($_REQUEST['cancel_path']) && !url_is_external($_REQUEST['cancel_path'])) ? $_REQUEST['cancel_path'] : ctools_export_ui_plugin_base_path($plugin); + + $form = confirm_form($form, + $question, + $path, + $plugin['strings']['confirmation'][$form_state['op']]['information'], + $plugin['allowed operations'][$form_state['op']]['title'], t('Cancel') + ); + return $form; +} + +// -------------------------------------------------------------------------- +// Forms and callbacks for using the edit system with the wizard. + +/** + * Form callback to edit an exportable item using the wizard + * + * This simply loads the object defined in the plugin and hands it off. + */ +function ctools_export_ui_edit_item_wizard_form($form, &$form_state) { + _ctools_export_ui_add_form_files($form, $form_state); + + $method = 'edit_form_' . $form_state['step']; + if (!method_exists($form_state['object'], $method)) { + $method = 'edit_form'; + } + + $form_state['object']->$method($form, $form_state); + return $form; +} + +/** + * Validate handler for ctools_export_ui_edit_item_wizard_form. + */ +function ctools_export_ui_edit_item_wizard_form_validate(&$form, &$form_state) { + $method = 'edit_form_' . $form_state['step'] . '_validate'; + if (!method_exists($form_state['object'], $method)) { + $method = 'edit_form_validate'; + } + + $form_state['object']->$method($form, $form_state); + + // Additionally, if there were no errors from that, and we're finishing, + // perform a final validate to make sure everything is ok. + if (isset($form_state['clicked_button']['#wizard type']) && $form_state['clicked_button']['#wizard type'] == 'finish' && !form_get_errors()) { + $form_state['object']->edit_finish_validate($form, $form_state); + } +} + +/** + * Submit handler for ctools_export_ui_edit_item_wizard_form. + */ +function ctools_export_ui_edit_item_wizard_form_submit(&$form, &$form_state) { + $method = 'edit_form_' . $form_state['step'] . '_submit'; + if (!method_exists($form_state['object'], $method)) { + $method = 'edit_form_submit'; + } + + $form_state['object']->$method($form, $form_state); +} + +/** + * Wizard 'back' callback when using a wizard to edit an item. + */ +function ctools_export_ui_wizard_back(&$form_state) { + $form_state['object']->edit_wizard_back($form_state); +} + +/** + * Wizard 'next' callback when using a wizard to edit an item. + */ +function ctools_export_ui_wizard_next(&$form_state) { + $form_state['object']->edit_wizard_next($form_state); +} + +/** + * Wizard 'cancel' callback when using a wizard to edit an item. + */ +function ctools_export_ui_wizard_cancel(&$form_state) { + $form_state['object']->edit_wizard_cancel($form_state); +} + +/** + * Wizard 'finish' callback when using a wizard to edit an item. + */ +function ctools_export_ui_wizard_finish(&$form_state) { + $form_state['object']->edit_wizard_finish($form_state); +} diff --git a/sites/all/modules/ctools/plugins/export_ui/ctools_export_ui.inc b/sites/all/modules/ctools/plugins/export_ui/ctools_export_ui.inc new file mode 100644 index 000000000..4e0a84978 --- /dev/null +++ b/sites/all/modules/ctools/plugins/export_ui/ctools_export_ui.inc @@ -0,0 +1,24 @@ +<?php + +/** + * The default plugin exists only to provide the base class. Other plugins + * which do not provide a class will get this class instead. Any classes + * provided should use this class as their parent: + * + * @code + * 'handler' => array( + * 'class' => 'ctools_export_ui_mine', + * 'parent' => 'ctools_export_ui', + * ), + * @endcode + * + * Using the above notation will ensure that this plugin's is loaded before + * the child plugin's class and avoid whitescreens. + */ +$plugin = array( + // As this is the base class plugin, it shouldn't declare any menu items. + 'has menu' => FALSE, + 'handler' => array( + 'class' => 'ctools_export_ui', + ), +); diff --git a/sites/all/modules/ctools/plugins/relationships/book_parent.inc b/sites/all/modules/ctools/plugins/relationships/book_parent.inc new file mode 100644 index 000000000..30ada4aa0 --- /dev/null +++ b/sites/all/modules/ctools/plugins/relationships/book_parent.inc @@ -0,0 +1,68 @@ +<?php + +/** + * @file + * Plugin to provide an relationship handler for book parent. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Book parent'), + 'keyword' => 'book_parent', + 'description' => t('Adds a book parent from a node context.'), + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'context' => 'ctools_book_parent_context', + 'edit form' => 'ctools_book_parent_settings_form', + 'defaults' => array('type' => 'top'), +); + +/** + * Return a new context based on an existing context. + */ +function ctools_book_parent_context($context, $conf) { + // If unset it wants a generic, unfilled context, which is just NULL. + if (empty($context->data)) { + return ctools_context_create_empty('node'); + } + + if (isset($context->data->book)) { + if ($conf['type'] == 'top') { + $nid = $context->data->book['bid']; + } + else { + // Just load the parent book. + $item = book_link_load($context->data->book['plid']); + $nid = $item['nid']; + } + + if (!empty($nid)) { + // Load the node. + $node = node_load($nid); + // Generate the context. + if (node_access('view', $node)) { + return ctools_context_create('node', $node); + } + } + } + else { + return ctools_context_create_empty('node'); + } +} + +/** + * Settings form for the relationship. + */ +function ctools_book_parent_settings_form($form, &$form_state) { + $conf = $form_state['conf']; + $form['type'] = array( + '#type' => 'select', + '#title' => t('Relationship type'), + '#options' => array('parent' => t('Immediate parent'), 'top' => t('Top level book')), + '#default_value' => $conf['type'], + ); + + return $form; +} diff --git a/sites/all/modules/ctools/plugins/relationships/entity_from_field.inc b/sites/all/modules/ctools/plugins/relationships/entity_from_field.inc new file mode 100644 index 000000000..fdffc41cf --- /dev/null +++ b/sites/all/modules/ctools/plugins/relationships/entity_from_field.inc @@ -0,0 +1,229 @@ +<?php + +/** + * @file + * Plugin to provide an relationship handler for an entity from a field. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Entity'), + 'description' => t('Creates an entity context from a foreign key on a field.'), + 'context' => 'ctools_entity_from_field_context', + 'edit form' => 'ctools_entity_from_field_edit_form', + 'get child' => 'ctools_entity_from_field_get_child', + 'get children' => 'ctools_entity_from_field_get_children', + 'defaults' => array('delta' => 0), +); + +function ctools_entity_from_field_get_child($plugin, $parent, $child) { + $plugins = ctools_entity_from_field_get_children($plugin, $parent); + return $plugins[$parent . ':' . $child]; +} + +function ctools_entity_from_field_get_children($parent_plugin, $parent) { + $cid = $parent_plugin['name'] . ':' . $parent; + $cache = &drupal_static(__FUNCTION__); + if (!empty($cache[$cid])) { + return $cache[$cid]; + } + + ctools_include('fields'); + $entities = entity_get_info(); + $plugins = array(); + $context_types = array(); + + // Get the schema information for every field. + $fields_info = field_info_fields(); + foreach ($fields_info as $field_name => $field) { + foreach ($field['bundles'] as $from_entity => $bundles) { + foreach ($bundles as $bundle) { + // There might be fields attached to bundles that are disabled (e.g. a + // module that declared a node's content type, is now disabled), but the + // field instance is still shown. + if (!empty($entities[$from_entity]['bundles'][$bundle])) { + $foreign_keys = ctools_field_foreign_keys($field_name); + + foreach ($foreign_keys as $key => $info) { + if (isset($info['table'])) { + foreach ($entities as $to_entity => $to_entity_info) { + $from_entity_info = $entities[$from_entity]; + // If somehow the bundle doesn't exist on the to-entity, + // skip. + if (!isset($from_entity_info['bundles'][$bundle])) { + continue; + } + + if (isset($to_entity_info['base table']) && $to_entity_info['base table'] == $info['table'] && array_keys($info['columns'], $to_entity_info['entity keys']['id'])) { + $name = $field_name . '-' . $from_entity . '-' . $to_entity; + $plugin_id = $parent . ':' . $name; + + // Record the bundle for later. + $context_types[$plugin_id]['types'][$bundle] = $from_entity_info['bundles'][$bundle]['label']; + + // We check for every bundle; this plugin may already have + // been created, so don't recreate it. + if (!isset($plugins[$plugin_id])) { + $plugin = $parent_plugin; + $replacements = array( + '@to_entity' => $to_entity_info['label'], + '@from_entity' => $from_entity_info['label'], + '@field_name' => $field_name, + '@field_label' => ctools_field_label($field_name), + ); + $plugin['title'] = t('@to_entity from @from_entity (on @from_entity: @field_label [@field_name])', $replacements); + $plugin['keyword'] = $to_entity; + $plugin['context name'] = $name; + $plugin['name'] = $plugin_id; + $plugin['description'] = t('Creates a @to_entity context from @from_entity using the @field_name field on @from_entity.', $replacements); + $plugin['from entity'] = $from_entity; + $plugin['to entity'] = $to_entity; + $plugin['field name'] = $field_name; + $plugin['join key'] = $key; + $plugin['source key'] = current(array_keys($info['columns'])); + $plugin['parent'] = $parent; + + $plugins[$plugin_id] = $plugin; + +/* +-- commented out until I figure out how to actually load the reverse properly. + // Build the reverse + $plugin = $parent_plugin; + $name = $field_name . '-' . $from_entity . '-' . $to_entity . '-reverse'; + $plugin_id = $parent . ':' . $name; + + $plugin['title'] = t('@from_entity from @to_entity (on @from_entity: @field_name)', $replacements); + $plugin['keyword'] = $to_entity; + $plugin['context name'] = $name; + $plugin['name'] = $plugin_id; + $plugin['description'] = t('Creates a @from_entity context from @to_entity using the @field_name field on @from_entity.', $replacements); + + $plugin['from entity'] = $from_entity; + $plugin['to entity'] = $to_entity; + $plugin['field name'] = $field_name; + $plugin['reverse'] = TRUE; + $plugin['parent'] = $parent; + + // Since we can't apply restrictions on the reverse relationship + // we just add the required context here. + $plugin['required context'] = new ctools_context_required($to_entity_info['label'], $to_entity); + + $plugin_entities = array( + 'to' => array($from_entity => $from_entity_info), + 'from' => array($to_entity => $to_entity_info) + ); + drupal_alter('ctools_entity_context', $plugin, $plugin_entities, $plugin_id); + + $plugins[$plugin_id] = $plugin; +*/ + } + } + } + } + } + } + } + } + } + + foreach ($context_types as $key => $context) { + list($parent, $plugin_name) = explode(':', $key); + list($field_name, $from_entity, $to_entity) = explode('-', $plugin_name); + + $from_entity_info = $entities[$from_entity]; + $to_entity_info = $entities[$to_entity]; + + $plugins[$key]['required context'] = new ctools_context_required($from_entity_info['label'], $from_entity, array('type' => array_keys($context['types']))); + + $plugin_entities = array( + 'to' => array($to_entity => $to_entity_info), + 'from' => array($from_entity => $from_entity_info) + ); + drupal_alter('ctools_entity_context', $plugins[$key], $plugin_entities, $key); + } + drupal_alter('ctools_entity_contexts', $plugins); + + $cache[$cid] = $plugins; + return $plugins; +} + +/** + * Return a new context based on an existing context. + */ +function ctools_entity_from_field_context($context, $conf) { + // Perform access check on current logged in user. + global $user; + // Clone user object so account can be passed by value to access callback. + $account = clone $user; + + $delta = !empty($conf['delta']) ? intval($conf['delta']) : 0; + $plugin = $conf['name']; + list($plugin, $plugin_name) = explode(':', $plugin); + list($field_name, $from_entity, $to_entity) = explode('-', $plugin_name); + // If unset it wants a generic, unfilled context, which is just NULL. + $entity_info = entity_get_info($from_entity); + if (empty($context->data) || !isset($context->data->{$entity_info['entity keys']['id']})) { + return ctools_context_create_empty('entity:' . $to_entity, NULL); + } + + if (isset($context->data->{$entity_info['entity keys']['id']})) { + // Load the entity. + $id = $context->data->{$entity_info['entity keys']['id']}; + $entity = entity_load($from_entity, array($id)); + $entity = $entity[$id]; + if ($items = field_get_items($from_entity, $entity, $field_name)) { + if (isset($items[$delta])) { + ctools_include('fields'); + $to_entity_info = entity_get_info($to_entity); + + $plugin_info = ctools_get_relationship($conf['name']); + $to_entity_id = $items[$delta][$plugin_info['source key']]; + $loaded_to_entity = entity_load($to_entity, array($to_entity_id)); + $loaded_to_entity = array_shift($loaded_to_entity); + + // Pass current user account and entity type to access callback. + if (isset($to_entity_info['access callback']) && function_exists($to_entity_info['access callback']) && !call_user_func($to_entity_info['access callback'], 'view', $loaded_to_entity)) { + return ctools_context_create_empty('entity:' . $to_entity, NULL); + } + else { + // Send it to ctools. + return ctools_context_create('entity:' . $to_entity, $to_entity_id); + } + } + else { + // In case that delta was empty. + return ctools_context_create_empty('entity:' . $to_entity, NULL); + } + } + } +} + +function ctools_entity_from_field_edit_form($form, &$form_state) { + $field = field_info_field($form_state['plugin']['field name']); + $conf = $form_state['conf']; + + if ($field && $field['cardinality'] != 1) { + if ($field['cardinality'] == -1) { + $form['delta'] = array( + '#type' => 'textfield', + '#title' => t('Delta'), + '#description' => t('The relationship can only create one context, but multiple items can be related. Please select which one. Since this can have unlimited items, type in the number you want. The first one will be 0.'), + '#default_value' => !empty($conf['delta']) ? $conf['delta'] : 0, + ); + } + else { + $form['delta'] = array( + '#type' => 'select', + '#title' => t('Delta'), + '#description' => t('The relationship can only create one context, but multiple items can be related. Please select which one.'), + '#options' => range(1, $field['cardinality']), + '#default_value' => !empty($conf['delta']) ? $conf['delta'] : 0, + ); + } + } + + return $form; +} diff --git a/sites/all/modules/ctools/plugins/relationships/entity_from_schema.inc b/sites/all/modules/ctools/plugins/relationships/entity_from_schema.inc new file mode 100644 index 000000000..809473eb6 --- /dev/null +++ b/sites/all/modules/ctools/plugins/relationships/entity_from_schema.inc @@ -0,0 +1,136 @@ +<?php + +/** + * @file + * Plugin to provide an relationship handler for an entity from a field. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Entity'), + 'description' => t('Creates an entity context from a foreign key on a field.'), + 'context' => 'ctools_entity_from_schema_context', + 'get child' => 'ctools_entity_from_schema_get_child', + 'get children' => 'ctools_entity_from_schema_get_children', +); + +function ctools_entity_from_schema_get_child($plugin, $parent, $child) { + $plugins = ctools_entity_from_schema_get_children($plugin, $parent); + return $plugins[$parent . ':' . $child]; +} + +function ctools_entity_from_schema_get_children($parent_plugin, $parent) { + $entities = entity_get_info(); + $plugins = array(); + + foreach (module_implements('entity_info') as $module) { + module_load_install($module); + $schemas = drupal_get_schema(); + + foreach ($entities as $from_entity => $from_entity_info) { + if (empty($from_entity_info['base table'])) { + continue; + } + + $table = $from_entity_info['base table']; + if (isset($schemas[$table]['foreign keys'])) { + foreach ($schemas[$table]['foreign keys'] as $relationship => $info) { + foreach ($entities as $to_entity => $to_entity_info) { + if (empty($info['table'])) { + continue; + } + + if (isset($to_entity_info['base table']) && $info['table'] == $to_entity_info['base table'] && in_array($to_entity_info['entity keys']['id'], $info['columns'])) { + $this_col = ctools_entity_from_schema_columns_filter($info['columns'], $to_entity_info['entity keys']['id']); + + // Set up our t() replacements as we reuse these. + $replacements = array( + '@relationship' => $relationship, + '@base_table' => $table, + '@to_entity' => $to_entity_info['label'], + '@from_entity' => $from_entity_info['label'], + ); + + $name = $this_col . '-' . $from_entity . '-' . $to_entity; + $plugin_id = $parent . ':' . $name; + $plugin = $parent_plugin; + + $plugin['title'] = t('@to_entity from @from_entity (on @base_table.@relationship)', $replacements); + $plugin['keyword'] = $to_entity; + $plugin['context name'] = $name; + $plugin['name'] = $plugin_id; + $plugin['description'] = t('Builds a relationship from a @from_entity to a @to_entity using the @base_table.@relationship field.', $replacements); + + $plugin['required context'] = new ctools_context_required($from_entity_info['label'], $from_entity); + + $plugin_entities = array('to' => $to_entity_info, 'from' => $from_entity_info); + $plugin_entities = array('to' => array($to_entity => $to_entity_info), 'from' => array($from_entity => $from_entity_info)); + + drupal_alter('ctools_entity_context', $plugin, $plugin_entities, $plugin_id); + $plugins[$plugin_id] = $plugin; + + // Add the relation in the reverse direction. + $name = $this_col . '-' . $to_entity . '-' . $from_entity; + $plugin_id = $parent . ':' . $name; + $plugin = $parent_plugin; + + $plugin['title'] = t('@from_entity from @to_entity (on @base_table.@relationship)', $replacements); + $plugin['keyword'] = $to_entity; + $plugin['context name'] = $name; + $plugin['name'] = $plugin_id; + $plugin['description'] = t('Builds a relationship from a @to_entity to a @from_entity using the @base_table.@relationship field.', $replacements); + + $plugin['required context'] = new ctools_context_required($to_entity_info['label'], $to_entity); + + $plugin_entities = array('to' => $from_entity_info, 'from' => $to_entity_info); + $plugin_entities = array('to' => array($from_entity => $from_entity_info), 'from' => array($to_entity => $to_entity_info)); + drupal_alter('ctools_entity_context', $plugin, $plugin_entities, $plugin_id); + $plugins[$plugin_id] = $plugin; + + } + } + } + } + } + } + drupal_alter('ctools_entity_contexts', $plugins); + return $plugins; +} + +function ctools_entity_from_schema_columns_filter($columns, $value) { + foreach ($columns as $this_col => $that_col) { + if ($value == $that_col) { + return $this_col; + } + } +} + +/** + * Return a new context based on an existing context. + */ +function ctools_entity_from_schema_context($context, $conf) { + $plugin = $conf['name']; + list($plugin, $plugin_name) = explode(':', $plugin); + list($this_col, $from_entity, $to_entity) = explode('-', $plugin_name); + // If unset it wants a generic, unfilled context, which is just NULL. + $entity_info = entity_get_info($from_entity); + if (empty($context->data) || !isset($context->data->{$entity_info['entity keys']['id']})) { + return ctools_context_create_empty('entity:' . $to_entity, NULL); + } + + if (isset($context->data->{$entity_info['entity keys']['id']})) { + // Load the entity. + $id = $context->data->{$entity_info['entity keys']['id']}; + $entity = entity_load($from_entity, array($id)); + $entity = $entity[$id]; + if (isset($entity->$this_col)) { + $to_entity_id = $entity->$this_col; + + // Send it to ctools. + return ctools_context_create('entity:' . $to_entity, $to_entity_id); + } + } +} diff --git a/sites/all/modules/ctools/plugins/relationships/node_edit_form_from_node.inc b/sites/all/modules/ctools/plugins/relationships/node_edit_form_from_node.inc new file mode 100644 index 000000000..15c758a22 --- /dev/null +++ b/sites/all/modules/ctools/plugins/relationships/node_edit_form_from_node.inc @@ -0,0 +1,31 @@ +<?php + +/** + * @file + * Plugin to provide an relationship handler for term from node. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Node edit form from node'), + 'keyword' => 'node_form', + 'description' => t('Adds node edit form from a node context.'), + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'context' => 'ctools_node_edit_form_from_node_context', +); + +/** + * Return a new context based on an existing context. + */ +function ctools_node_edit_form_from_node_context($context, $conf) { + if (empty($context->data)) { + return ctools_context_create_empty('node_edit_form', NULL); + } + + if (isset($context->data->nid)) { + return ctools_context_create('node_edit_form', $context->data); + } +} diff --git a/sites/all/modules/ctools/plugins/relationships/term_from_node.inc b/sites/all/modules/ctools/plugins/relationships/term_from_node.inc new file mode 100644 index 000000000..38f6aeaa0 --- /dev/null +++ b/sites/all/modules/ctools/plugins/relationships/term_from_node.inc @@ -0,0 +1,60 @@ +<?php + +/** + * @file + * Plugin to provide an relationship handler for term from node. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Term from node'), + 'keyword' => 'term', + 'description' => t('Adds a taxonomy term from a node context; if multiple terms are selected, this will get the "first" term only.'), + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'context' => 'ctools_term_from_node_context', + 'edit form' => 'ctools_term_from_node_settings_form', + 'defaults' => array('vid' => ''), +); + +/** + * Return a new context based on an existing context. + */ +function ctools_term_from_node_context($context, $conf) { + // If unset it wants a generic, unfilled context, which is just NULL. + if (empty($context->data)) { + return ctools_context_create_empty('entity:taxonomy_term', NULL); + } + + if (isset($context->data->taxonomy)) { + foreach ($context->data->taxonomy as $term) { + if ($term->vid == $conf['vid']) { + return ctools_context_create('entity:taxonomy_term', $term); + } + } + } +} + +/** + * Settings form for the relationship. + */ +function ctools_term_from_node_settings_form($form, &$form_state) { + $conf = $form_state['conf']; + + $options = array(); + foreach (taxonomy_get_vocabularies() as $vid => $vocabulary) { + $options[$vid] = $vocabulary->name; + } + $form['vid'] = array( + '#title' => t('Vocabulary'), + '#type' => 'select', + '#options' => $options, + '#default_value' => $conf['vid'], + '#prefix' => '<div class="clearfix">', + '#suffix' => '</div>', + ); + + return $form; +} diff --git a/sites/all/modules/ctools/plugins/relationships/term_parent.inc b/sites/all/modules/ctools/plugins/relationships/term_parent.inc new file mode 100644 index 000000000..f084cca83 --- /dev/null +++ b/sites/all/modules/ctools/plugins/relationships/term_parent.inc @@ -0,0 +1,68 @@ +<?php + +/** + * @file relationships/term_parent.inc + * Plugin to provide an relationship handler for term parent. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Term parent'), + 'keyword' => 'parent_term', + 'description' => t('Adds a taxonomy term parent from a term context.'), + 'required context' => new ctools_context_required(t('Term'), 'entity:taxonomy_term'), + 'context' => 'ctools_term_parent_context', + 'edit form' => 'ctools_term_parent_settings_form', + 'defaults' => array('type' => 'top'), +); + +/** + * Return a new context based on an existing context. + */ +function ctools_term_parent_context($context, $conf) { + // If unset it wants a generic, unfilled context, which is just NULL. + if (empty($context->data)) { + return ctools_context_create_empty('entity:taxonomy_term'); + } + + if (isset($context->data)) { + $result = db_query('SELECT t1.* FROM {taxonomy_term_hierarchy} t1 INNER JOIN {taxonomy_term_hierarchy} t2 ON t1.tid = t2.parent WHERE t2.tid = :tid', array(':tid' => $context->data->tid))->fetchAssoc(); + + // If top level term, keep looking up until we see a top level. + if ($conf['type'] == 'top') { + // If looking for top level, and there are no parents at all, make sure + // the current term is the 'top level'. + if (empty($result)) { + $result['tid'] = $context->data->tid; + } + while (!empty($result['parent'])) { + $result = db_query('SELECT * FROM {taxonomy_term_hierarchy} WHERE tid = :tid', array(':tid' => $result['parent']))->fetchAssoc(); + } + } + + // Load the term. + if ($result) { + $term = taxonomy_term_load($result['tid']); + return ctools_context_create('entity:taxonomy_term', $term); + } + } +} + +/** + * Settings form for the relationship. + */ +function ctools_term_parent_settings_form($form, &$form_state) { + $conf = $form_state['conf']; + + $form['type'] = array( + '#type' => 'select', + '#title' => t('Relationship type'), + '#options' => array('parent' => t('Immediate parent'), 'top' => t('Top level term')), + '#default_value' => $conf['type'], + ); + + return $form; +} diff --git a/sites/all/modules/ctools/plugins/relationships/terms_from_node.inc b/sites/all/modules/ctools/plugins/relationships/terms_from_node.inc new file mode 100644 index 000000000..07081f2ff --- /dev/null +++ b/sites/all/modules/ctools/plugins/relationships/terms_from_node.inc @@ -0,0 +1,83 @@ +<?php + +/** + * @file + * Plugin to provide an relationship handler for all terms from node. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Multiple terms from node'), + 'keyword' => 'terms', + 'description' => t('Adds a taxonomy terms from a node context; if multiple terms are selected, they wil be concatenated.'), + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'context' => 'ctools_terms_from_node_context', + 'edit form' => 'ctools_terms_from_node_settings_form', + 'defaults' => array('vocabulary' => array(), 'concatenator' => ','), +); + +/** + * Return a new context based on an existing context. + */ +function ctools_terms_from_node_context($context, $conf) { + // If unset it wants a generic, unfilled context, which is just NULL. + if (empty($context->data)) { + return ctools_context_create_empty('terms', NULL); + } + + // Collect all terms for the chosen vocabulary and concatenate them. + $node = $context->data; + $terms = array(); + + $fields = field_info_instances('node', $node->type); + foreach ($fields as $name => $info) { + $field_info = field_info_field($name); + if ($field_info['type'] == 'taxonomy_term_reference' && (empty($conf['vocabulary']) || !empty($conf['vocabulary'][$field_info['settings']['allowed_values'][0]['vocabulary']]))) { + $items = field_get_items('node', $node, $name); + if (is_array($items)) { + foreach ($items as $item) { + $terms[] = $item['tid']; + } + } + } + } + + if (!empty($terms)) { + $all_terms = ctools_break_phrase(implode($conf['concatenator'], $terms)); + return ctools_context_create('terms', $all_terms); + } +} + +/** + * Settings form for the relationship. + */ +function ctools_terms_from_node_settings_form($form, &$form_state) { + $conf = $form_state['conf']; + + $options = array(); + foreach (taxonomy_vocabulary_get_names() as $name => $vocabulary) { + $options[$name] = $vocabulary->name; + } + $form['vocabulary'] = array( + '#title' => t('Vocabulary'), + '#type' => 'checkboxes', + '#options' => $options, + '#default_value' => $conf['vocabulary'], + '#prefix' => '<div class="clearfix">', + '#suffix' => '</div>', + ); + $form['concatenator'] = array( + '#title' => t('Concatenator'), + '#type' => 'select', + '#options' => array(',' => ', (AND)', '+' => '+ (OR)'), + '#default_value' => $conf['concatenator'], + '#prefix' => '<div class="clearfix">', + '#suffix' => '</div>', + '#description' => t("When the value from this context is passed on to a view as argument, the terms can be concatenated in the form of 1+2+3 (for OR) or 1,2,3 (for AND)."), + ); + + return $form; +} diff --git a/sites/all/modules/ctools/plugins/relationships/user_category_edit_form_from_user.inc b/sites/all/modules/ctools/plugins/relationships/user_category_edit_form_from_user.inc new file mode 100644 index 000000000..28dac72c5 --- /dev/null +++ b/sites/all/modules/ctools/plugins/relationships/user_category_edit_form_from_user.inc @@ -0,0 +1,31 @@ +<?php + +/** + * @file + * Plugin to provide an relationship handler for term from node. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('User category edit form from user'), + 'keyword' => 'user_category_form', + 'description' => t('Adds user category edit form from a user context.'), + 'required context' => new ctools_context_required(t('User'), 'user'), + 'context' => 'ctools_user_category_edit_form_from_user_context', +); + +/** + * Return a new context based on an existing context. + */ +function ctools_user_category_edit_form_from_user_context($context, $conf) { + if (empty($context->data)) { + return ctools_context_create_empty('user_edit_form', NULL); + } + + if (isset($context->data->user_category)) { + return ctools_context_create('user_edit_form', $context->data, array('category' => $context->data->user_category)); + } +} diff --git a/sites/all/modules/ctools/plugins/relationships/user_from_node.inc b/sites/all/modules/ctools/plugins/relationships/user_from_node.inc new file mode 100644 index 000000000..388b1cec1 --- /dev/null +++ b/sites/all/modules/ctools/plugins/relationships/user_from_node.inc @@ -0,0 +1,38 @@ +<?php + +/** + * @file + * Plugin to provide an relationship handler for node from user. + */ + +/** + * Plugins are described by creating a $plugin array which will be used + * by the system that includes this file. + */ +$plugin = array( + 'title' => t('Node author'), + 'keyword' => 'user', + 'description' => t('Creates the author of a node as a user context.'), + 'required context' => new ctools_context_required(t('Node'), 'node'), + 'context' => 'ctools_user_from_node_context', + 'no ui' => TRUE, +); + +/** + * Return a new context based on an existing context. + */ +function ctools_user_from_node_context($context, $conf) { + // If unset it wants a generic, unfilled context, which is just NULL. + if (empty($context->data) || !isset($context->data->uid)) { + return ctools_context_create_empty('user', NULL); + } + + if (isset($context->data->uid)) { + // Load the user that is the author of the node. + $uid = $context->data->uid; + $account = user_load($uid); + + // Send it to ctools. + return ctools_context_create('user', $account); + } +} |