groups/modules/commons/commons_bw/commons_bw.module

506 lines
15 KiB
Plaintext

<?php
/**
* @file
* Code for the Commons Browsing Widget feature.
*/
include_once 'commons_bw.features.inc';
/**
* Implements hook_hook_info().
*/
function commons_bw_hook_info() {
$hooks = array(
'commons_bw_group_widget',
'commons_bw_create_all_widget',
);
return array_fill_keys($hooks, array('group' => 'commons'));
}
/**
* Implements hook_system_info_alter().
*/
function commons_bw_system_info_alter(&$info, $file, $type) {
// Commons BW dynamically adds the title_field field to content types that
// request it.
// We must add a corresponding line for each field instance to commons_bw.info
// so that Features is aware of the instance and can successfully revert the
// field_instance component back to its default state.
if ($file->name == 'commons_bw') {
foreach (node_type_get_types() as $node_type_object) {
$node_type = $node_type_object->type;
if (commons_bw_node_auto_title_instance($node_type)) {
$info['features']['field_instance'][] = "node-$node_type-title_field";
}
}
}
// Dynamically adding a field to a content type results in features
// automatically detecting Commons BW as a dependency.
// We manually exclude the dependency in order to prevent the content type
// modules from appearing overridden and to allow them to be used
// independently of Commons BW.
$node_types = &drupal_static(__FUNCTION__);
if (!isset($node_types)) {
foreach (module_implements('node_info') as $module) {
$node_types[$module] = call_user_func($module . '_node_info');
}
}
if (isset($node_types[$file->name])) {
foreach ($node_types[$file->name] as $node_type => $node_info) {
if (commons_bw_node_auto_title_instance($node_type)) {
$info['features_exclude']['dependencies']['commons_bw'] = 'commons_bw';
}
}
}
}
/**
* Implements hook_modules_enabled().
*/
function commons_bw_modules_enabled($modules) {
// Ensure that dynamically added title_field fields are in the default state
// when modules that provide content types are enabled.
foreach ($modules as $module) {
if (module_hook($module, 'node_info')) {
features_revert(array('commons_bw' => array('field_instance')));
}
}
}
/**
* Implements hook_forms().
*
* The bundle is added to the partial node form ID, to prevent duplicate IDs on
* the same page, but all of the partial forms are built with the same function.
*/
function commons_bw_forms($form_id, $args) {
$forms = array();
if (strpos($form_id, 'commons_bw_partial_node_form__') === 0) {
$forms[$form_id] = array(
'callback' => 'commons_bw_partial_node_form',
);
}
return $forms;
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function commons_bw_form_views_exposed_form_alter(&$form, &$form_state, $form_id) {
// Implements tweaks to exposed filters and sorts per the Commons designs.
if (strpos($form['#id'],'views-exposed-form-commons-bw') === 0) {
// Remove the sort order (eg, descending vs ascending).
$form['sort_order']['#access'] = FALSE;
$form['sort_by']['#title'] = t('Sorted by');
}
}
/**
* Implements hook_form_FORM_ID_alter().
*
* Add a setting to group content fields, to determine whether they will be
* displayed on the mini node form of the browsing widget.
*/
function commons_bw_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
if (!og_is_group_content_type($form['instance']['entity_type']['#value'], $form['instance']['bundle']['#value'])) {
return;
}
// See if we're building for the first time, or getting pre-saved values.
$field_name = $form['#field']['field_name'];
if(!empty($form_state['field'][$field_name][LANGUAGE_NONE]['instance']['display_in_partial_form'])) {
$display_default = $form_state['field'][$field_name][LANGUAGE_NONE]['instance']['display_in_partial_form'];
}
else if (isset($form_state['build_info']['args'][0]['display_in_partial_form'])) {
$display_default = $form_state['build_info']['args'][0]['display_in_partial_form'];
}
else {
$display_default = FALSE;
}
$form['instance']['display_in_partial_form'] = array(
'#type' => 'checkbox',
'#title' => t('Display in the browsing widget mini-form'),
'#default_value' => $display_default,
);
}
/**
* Partial node form for the browsing widget.
*/
function commons_bw_partial_node_form($form, &$form_state, $bundle, $group_id = NULL) {
global $user;
global $language;
if (!$group_id) {
// Reset the og_field_widget_form cache because otherwise it ignores
// multiple tries to render the same group audience widget (We have the
// same group audience widget on the All and Posts tabs, when displaying
// this form without group context).
drupal_static_reset('og_field_widget_form');
}
if ($group_id) {
$form_state['group_id'] = $group_id;
}
$instances = field_info_instances('node', $bundle);
// Remove all fields except those marked as "display_in_partial_form".
foreach($instances as $field_name => $instance) {
if (empty($instance['display_in_partial_form'])) {
unset($instances[$field_name]);
}
}
// Make sure there's a field left to display.
if (empty($instances)) {
return $form;
}
// Create a dummy node for field_attach_form().
$node = new stdClass();
$node->type = $bundle;
node_object_prepare($node);
if (module_exists('locale')) {
if (locale_multilingual_node_type($node->type)) {
$node->language = $language->language;
}
else {
$default = language_default();
$node->language = $default->language;
}
}
else {
$node->language = LANGUAGE_NONE;
}
field_attach_form('node', $node, $form, $form_state, entity_language('node', $node));
foreach(element_children($form) as $field_name) {
if (empty($instances[$field_name])) {
$form[$field_name]['#access'] = FALSE;
}
}
if (!empty($form['#metatags'])) {
unset($form['#metatags']);
}
// When not in a group context, enable the group audience widget.
$form[OG_AUDIENCE_FIELD]['#weight'] = 100;
$form[OG_AUDIENCE_FIELD]['#access'] = !$group_id;
// Add a default form title.
$form['title'] = array(
'#markup' => t('Create content'),
'#weight' => -100,
);
// Display the user's picture.
$wrapper = entity_metadata_wrapper('user', $user);
$path = empty($user->picture) ? variable_get('user_picture_default') : $wrapper->value()->picture->uri;
$form['user_picture'] = array(
'#theme' => 'image_style',
'#style_name' => '50x50_avatar',
'#path' => $path,
'#prefix' => '<div class="user-picture">',
'#suffix' => '</div>',
'#weight' => -20,
);
$form['actions'] = array(
'#type' => 'actions',
'#weight' => 200,
);
$form['actions']['submit'] = array(
'#type' => 'submit',
'#value' => t('Save'),
);
// Attach the browsing widget JS and give it a higher weight than
// quicktabs.js.
$form['#attached']['js'][] = array(
'data' => drupal_get_path('module', 'commons_bw') . '/js/partial_node_form.js',
'type' => 'file',
'weight' => 100,
);
// Add in some descriptive classes for css down the line.
$form['#attributes']['class'][] = 'node';
$form['#attributes']['class'][] = 'commons-bw-partial-node-form';
$form['#attributes']['class'][] = 'commons-bw-partial-node-form-' . $bundle;
// Add a link to the full node form.
$form['full_form'] = array(
'#theme' => 'link',
'#text' => t('Go to full form'),
'#path' => 'node/add/' . str_replace('_', '-', $bundle),
'#options' => array(
'attributes' => array('class' => array('full-form')),
'html' => FALSE,
),
'#weight' => 100,
);
if ($group_id) {
$form['full_form']['#options']['query'] = array(OG_AUDIENCE_FIELD => $group_id);
}
// Add the commons_bw after build first, in case other pre-renders needs need
// to address fields by there CSS ID.
array_unshift($form['#pre_render'], 'commons_bw_partial_node_form_after_build');
$form['#validate'][] = 'commons_bw_partial_node_form_validate';
return $form;
}
/**
* After-build call-back. See commons_bw_partial_node_form().
*/
function commons_bw_partial_node_form_after_build($form) {
$bundle = $form['#bundle'];
// Add the node's bundle to the IDs of inputs, to avoid having duplicate IDs.
$id_suffix = '-' . str_replace('_', '-', $bundle);
foreach(element_children($form) as $field_name) {
if (!empty($form[$field_name]['#language'])) {
$language = $form[$field_name]['#language'];
if (!empty($form[$field_name][$language][0]['value']['#id'])) {
$form[$field_name][$language][0]['value']['#id'] .= $id_suffix;
}
if (!empty($form[$field_name][$language][0]['default']['#id'])) {
$form[$field_name][$language][0]['default']['#id'] .= $id_suffix;
}
}
}
// Set the form action to the form's tab.
$tabs = commons_bw_get_tab_definitions();
// Search for the tab displaying the current bundle.
foreach ($tabs as $tab_id => $settings) {
if ($settings['bundle'] == $bundle) {
break;
}
}
$form['#action'] = url(current_path(), array('query' => array('qt-commons_bw' => $tab_id)));
return $form;
}
/**
* Validation handler; Attach the node validation to the partial node form.
*/
function commons_bw_partial_node_form_validate($form, $form_state) {
$node = $form['#entity'];
field_attach_validate('node', $node);
node_validate($node, $form, $form_state);
if ((!module_exists('commons_trusted_contacts') || (module_exists('commons_trusted_contacts') && !module_exists('og_access'))) && empty($form_state['group_id']) && empty($form_state['values'][OG_AUDIENCE_FIELD][LANGUAGE_NONE][0])) {
form_set_error(OG_AUDIENCE_FIELD, t('Please enter one or more groups where this content will be posted.'));
return FALSE;
}
}
/**
* Submit handler; Create a node from the partial node form.
*/
function commons_bw_partial_node_form_submit($form, $form_state) {
$node = $form['#entity'];
node_submit($node);
// Mark the node as created with the partial form
$node->partial_node_form = TRUE;
field_attach_submit('node', $node, $form, $form_state);
$wrapper = entity_metadata_wrapper('node', $node);
// If the node has a body and doesn't has a title, create a title from the
// body.
if ((empty($wrapper->title_field) || !$wrapper->title_field->value()) && empty($node->title)) {
if (!empty($wrapper->body) && $wrapper->body->value()) {
$title = htmlspecialchars_decode($wrapper->body->value->value());
// Strip tags and whitespaces.
$title = preg_replace('/[\t\n\r\0\x0B]/', '', strip_tags($title));
// Shorten the title.
$node->title = truncate_utf8($title, 30, TRUE, TRUE);
}
}
// Set the group audience.
if (!empty($form_state['group_id'])) {
$wrapper->{OG_AUDIENCE_FIELD}->set(array($form_state['group_id']));
}
$node->form_state = $form_state;
$wrapper->save();
// Notify about the node creation.
$arguments = array('@type' => node_type_get_name($node), '%title' => $node->title);
drupal_set_message(t('@type %title has been created.', $arguments));
}
/**
* Get a list of modules that add content to a particular type of widget.
*
* The only currently supported widget type is 'group', but this
* could be extended to support other entities.
*
* @param $widget_type
* An optional type of widget to restrict results to, defaults to 'group'.
*
* @return array
* An array of return values of the hook implementations.
*/
function commons_bw_get_tab_definitions($widget_type = 'group') {
$hook_name = 'commons_bw_' . $widget_type . '_widget';
$tabs = module_invoke_all($hook_name);
drupal_alter($hook_name, $tabs);
return $tabs;
}
/**
* Helper function to determine whether Commons_BW should define a title field
* instance on behalf of a content type.
*
* @param $node_type
* The type of the node to check auto title settings for.
*
* @return boolean
* The value of the auto title setting if available, TRUE otherwise.
*/
function commons_bw_node_auto_title_instance($node_type) {
$commons_groups_entity_types = commons_groups_get_group_content_entity_types();
return isset($commons_groups_entity_types['node'][$node_type]['auto_title_instance']) ? $commons_groups_entity_types['node'][$node_type]['auto_title_instance'] : TRUE;
}
/**
* Provides a styled content creation dropdown widget for the 'all' tab of the
* group homepage browsing widget.
*
* @param $group
* The group node associated with the group homepage.
*
* @return string
* The content creation dropdown widget HTML.
*/
function commons_bw_create_all_widget($group) {
$links = array();
// Collect definitions from implementing modules.
$items = module_invoke_all('commons_bw_create_all_widget', $group);
uasort($items, 'element_sort');
foreach ($items as $module => $item) {
$links[] = $item['link'] . ' ' . $item['text'];
// Populate the default content creation link.
if (isset($item['default']) && $item['default']) {
$default = $item;
}
}
$output = '';
if (!empty($default)) {
$output .= $default['link'] . '<a class="commons-bw-create-choose"><span></span></a>';
}
$output .= '<div class="commons-bw-create-choose-bg"></div><div class="commons-bw-create-choose-holder">' . theme('item_list', array('items' => $links, 'type' => 'ul', 'attributes' => array('class' => 'commons-bw-create-all-widget-types'))) . '</div>';
return $output;
}
/**
* Generate a renderable group widget.
*
* @param $group
* An optional group node to be used as a tab and views argument.
*
* @return array
* An array in the format expected by drupal_render().
*/
function commons_bw_generate_group_widget($group = NULL) {
// Prepare an array of default quicktabs settings.
$settings = array(
'style' => 'Commons Pills',
'ajax' => FALSE,
'html' => TRUE,
);
// Load the browsing widget tab definitions.
$tabs = commons_bw_get_tab_definitions('group');
foreach ($tabs as $machine_name => $tab_settings) {
// Populate the group argument.
$tabs[$machine_name]['args'] = $group ? $group->nid : 0;
// Add the result count to the title for 'view' tabs.
if ($tab_settings['type'] == 'view') {
// Get the view specified by the tab settings.
$view = views_get_view($tab_settings['vid']);
// If the tab specified a view display use it, otherwise the view will be
// rendered using the default display.
if (isset($tab_settings['display'])) {
$view->set_display($tab_settings['display']);
}
// If the tab references a group, set it as a tab argument.
if ($group) {
$view->set_arguments(array($group->nid));
}
$view->display_handler->options['filters']['flagged']['value'] = 'All';
$view->get_total_rows = TRUE;
$view->execute();
// Append the result count to the tab title.
$tabs[$machine_name]['title'] = $tabs[$machine_name]['title'] . ' <span class="commons-bw-result-count">'. $view->total_rows . '</span>';
}
// Use the current tab as the quicktabs default if the tab settings specify.
if (!empty($tabs[$machine_name]['default'])) {
$settings['default_tab'] = $machine_name;
}
}
return quicktabs_build_quicktabs('commons_bw', $settings, $tabs);
}
/**
* Implements hook_quicktabs_tabstyles().
*/
function commons_bw_quicktabs_tabstyles() {
$path = drupal_get_path('module', 'commons_bw');
return array(
$path . '/plugins/quicktabs_styles/commons_pills/commons_pills.css' => t('Commons Pills'),
$path . '/plugins/quicktabs_styles/commons_tabs/commons_tabs.css' => t('Commons Tabs'),
);
}