diff --git a/field-collection-item.tpl.php b/field-collection-item.tpl.php deleted file mode 100644 index 8d345cb..0000000 --- a/field-collection-item.tpl.php +++ /dev/null @@ -1,37 +0,0 @@ - -
> -
> - -
-
diff --git a/field_collection.module b/field_collection.module index 80e4588..d89f5b3 100644 --- a/field_collection.module +++ b/field_collection.module @@ -560,25 +560,41 @@ function field_collection_item_access($op, FieldCollectionItemEntity $item = NUL if (!isset($item)) { return FALSE; } - $op = $op == 'view' ? 'view' : 'edit'; - // Access is determined by the entity and field containing the reference. + $field = field_info_field($item->field_name); - $entity_access = entity_access($op == 'view' ? 'view' : 'update', $item->hostEntityType(), $item->hostEntity(), $account); - return $entity_access && field_access($op, $field, $item->hostEntityType(), $item->hostEntity(), $account); + + // Entity access takes 'view', 'update', 'create' or 'delete' operations. + if ($op == 'edit') { + $op = 'update'; + } + // Field access takes only 'view' or 'edit' operations. + $field_op = $op == 'view' ? 'view' : 'edit'; + + // Access is determined by the entity and field containing the reference. + return entity_access($op, $item->hostEntityType(), $item->hostEntity(), $account) && field_access($field_op, $field, $item->hostEntityType(), $item->hostEntity(), $account); } /** * Implements hook_theme(). */ -function field_collection_theme() { +function field_collection_theme($existing, $type, $theme, $path) { + + $path = drupal_get_path('module', 'field_collection'); + return array( 'field_collection_item' => array( 'render element' => 'elements', + 'path' => $path . '/theme', 'template' => 'field-collection-item', ), 'field_collection_view' => array( 'render element' => 'element', ), + 'field_collection_op_links' => array( + 'path' => $path . '/theme', + 'template' => 'field-collection-op-links', + 'render element' => 'op_links', + ), ); } @@ -622,7 +638,7 @@ function field_collection_field_instance_settings_form($field, $instance) { '#value' => NULL, ); $element['fieldset']['content'] = array( - '#pre' => '

', + '#prefix' => '

', '#markup' => t('To specify a default value, configure it via the regular default value setting of each field that is part of the field collection. To do so, go to the Manage fields screen of the field collection.', array('!url' => url('admin/structure/field-collections/' . strtr($field['field_name'], array('_' => '-')) . '/fields'))), '#suffix' => '

', ); @@ -761,6 +777,7 @@ function field_collection_field_formatter_info() { 'label' => t('Field collection items'), 'field types' => array('field_collection'), 'settings' => array( + 'show_op_links' => FALSE, 'edit' => t('Edit'), 'delete' => t('Delete'), 'add' => t('Add'), @@ -768,16 +785,10 @@ function field_collection_field_formatter_info() { 'view_mode' => 'full', ), ), - 'field_collection_fields' => array( - 'label' => t('Fields only'), - 'field types' => array('field_collection'), - 'settings' => array( - 'view_mode' => 'full', - ), - ), ); } + /** * Implements hook_field_formatter_settings_form(). */ @@ -786,32 +797,57 @@ function field_collection_field_formatter_settings_form($field, $instance, $view $settings = $display['settings']; $elements = array(); - if ($display['type'] != 'field_collection_fields') { + $elements['show_op_links'] = array( + '#type' => 'checkbox', + '#title' => t('Show operation links for field collection items'), + '#default_value' => $settings['show_op_links'], + ); $elements['edit'] = array( '#type' => 'textfield', '#title' => t('Edit link title'), '#default_value' => $settings['edit'], - '#description' => t('Leave the title empty, to hide the link.'), + '#description' => t('Leave the title empty to hide the link.'), + '#states' => array( + 'invisible' => array( + ':input[name="fields[' . $field['field_name'] . '][settings_edit_form][settings][show_op_links]"]' => array('checked' => FALSE), + ), + ) ); $elements['delete'] = array( '#type' => 'textfield', '#title' => t('Delete link title'), '#default_value' => $settings['delete'], - '#description' => t('Leave the title empty, to hide the link.'), + '#description' => t('Leave the title empty to hide the link.'), + '#states' => array( + 'invisible' => array( + ':input[name="fields[' . $field['field_name'] . '][settings_edit_form][settings][show_op_links]"]' => array('checked' => FALSE), + ), + ) ); $elements['add'] = array( '#type' => 'textfield', '#title' => t('Add link title'), '#default_value' => $settings['add'], - '#description' => t('Leave the title empty, to hide the link.'), + '#description' => t('Leave the title empty to hide the link.'), + '#states' => array( + 'invisible' => array( + ':input[name="fields[' . $field['field_name'] . '][settings_edit_form][settings][show_op_links]"]' => array('checked' => FALSE), + ), + ) ); $elements['description'] = array( '#type' => 'checkbox', - '#title' => t('Show the field description beside the add link.'), + '#title' => t('Show the field help text next to the add link.'), '#default_value' => $settings['description'], - '#description' => t('If enabled and the add link is shown, the field description is shown in front of the add link.'), + '#states' => array( + 'invisible' => array( + ':input[name="fields[' . $field['field_name'] . '][settings_edit_form][settings][show_op_links]"]' => array('checked' => FALSE), + ), + 'disabled' => array( + ':input[name="fields[' . $field['field_name'] . '][settings_edit_form][settings][add]"]' => array('value' => ''), + ), + ) ); - } // Add a select form element for view_mode if viewing the rendered field_collection. if ($display['type'] !== 'field_collection_list') { @@ -842,13 +878,16 @@ function field_collection_field_formatter_settings_summary($field, $instance, $v $settings = $display['settings']; $output = array(); - if ($display['type'] !== 'field_collection_fields') { + if ($settings['show_op_links']) { + $links = array_filter(array_intersect_key($settings, array_flip(array('add', 'edit', 'delete')))); + if ($links) { - $output[] = t('Links: @links', array('@links' => check_plain(implode(', ', $links)))); + $links['add'] && $settings['description'] ? $help_text = ' with field help text' : $help_text = ''; + $output[] = t('Links: @links@help_text', array('@links' => check_plain(implode(', ', $links)), '@help_text' => $help_text)); } else { - $output[] = t('Links: none'); + $output[] = t('No operation links.'); } } @@ -859,9 +898,14 @@ function field_collection_field_formatter_settings_summary($field, $instance, $v } } - return implode('
', $output); + // Add linebreaks if we have more than one summary item. + return count($output) > 1 ? implode('
', $output) : implode('', $output); } + + +// RW MOTHERLOAD. + /** * Implements hook_field_formatter_view(). */ @@ -869,22 +913,32 @@ function field_collection_field_formatter_view($entity_type, $entity, $field, $i $element = array(); $settings = $display['settings']; + // RW Switch this to a theme function so it can be overridden switch ($display['type']) { + // RW Change name to links case 'field_collection_list': foreach ($items as $delta => $item) { + if ($field_collection = field_collection_field_get_entity($item)) { + $output = l($field_collection->label(), $field_collection->path()); + + // RW add op links (but no description?). Use same helper function, just css differently. + // RW maybe add a "links-list" class for op links $links = array(); foreach (array('edit', 'delete') as $op) { - if ($settings[$op] && field_collection_item_access($op == 'edit' ? 'update' : $op, $field_collection)) { + if ($settings[$op] && field_collection_item_access($op, $field_collection)) { $title = entity_i18n_string("field:{$field['field_name']}:{$instance['bundle']}:setting_$op", $settings[$op]); $links[] = l($title, $field_collection->path() . '/' . $op, array('query' => drupal_get_destination())); } } + + // RW this is current "theme" implementation. if ($links) { $output .= ' (' . implode('|', $links) . ')'; } + // RW AHHHHH no! $element[$delta] = array('#markup' => $output); } } @@ -893,93 +947,148 @@ function field_collection_field_formatter_view($entity_type, $entity, $field, $i case 'field_collection_view': - $element['#attached']['css'][] = drupal_get_path('module', 'field_collection') . '/field_collection.theme.css'; + // RW remove CSS here for testing. Add it back in with BAT + //$element['#attached']['css'][] = drupal_get_path('module', 'field_collection') . '/field_collection.theme.css'; + $view_mode = !empty($display['settings']['view_mode']) ? $display['settings']['view_mode'] : 'full'; + foreach ($items as $delta => $item) { - if ($field_collection = field_collection_field_get_entity($item)) { - $element[$delta]['entity'] = $field_collection->view($view_mode); - $element[$delta]['#theme_wrappers'] = array('field_collection_view'); - $element[$delta]['#attributes']['class'][] = 'field-collection-view'; - $element[$delta]['#attributes']['class'][] = 'clearfix'; - $element[$delta]['#attributes']['class'][] = drupal_clean_css_identifier('view-mode-' . $view_mode); - - $links = array( - '#theme' => 'links__field_collection_view', - ); - $links['#attributes']['class'][] = 'field-collection-view-links'; - foreach (array('edit', 'delete') as $op) { - if ($settings[$op] && field_collection_item_access($op == 'edit' ? 'update' : $op, $field_collection)) { - $links['#links'][$op] = array( - 'title' => entity_i18n_string("field:{$field['field_name']}:{$instance['bundle']}:setting_$op", $settings[$op]), - 'href' => $field_collection->path() . '/' . $op, - 'query' => drupal_get_destination(), - ); - } - } - $element[$delta]['links'] = $links; - } - } - field_collection_field_formatter_links($element, $entity_type, $entity, $field, $instance, $langcode, $items, $display); - break; - case 'field_collection_fields': + $field_collection_item = field_collection_field_get_entity($item); + $item_id = implode($item); - $view_mode = !empty($display['settings']['view_mode']) ? $display['settings']['view_mode'] : 'full'; - foreach ($items as $delta => $item) { - if ($field_collection = field_collection_field_get_entity($item)) { - $element[$delta]['entity'] = $field_collection->view($view_mode); - } + // Attach fields to the collection. + $element[$delta]['entity'] = $field_collection_item->view($view_mode); + + // Add edit and delete operation links if available. + $op_links = field_collection_field_formatter_op_links($entity_type, $entity, $field, $instance, $langcode, $items, $settings, $ops = array('edit', 'delete'), $field_collection_item); + !empty($op_links) ? $element[$delta]['entity']['field_collection_item'][$item_id]['op_links'] = $op_links : ''; } + + // Add the add operation link if available. + // This is a hack. We render and add to #suffix because adding the ops link array to the field render array doesn't work. + $op_links = field_collection_field_formatter_op_links($entity_type, $entity, $field, $instance, $langcode, $items, $settings, $ops = array('add')); + !empty($op_links) ? $element['#suffix'] = render($op_links) : ''; + break; } return $element; } + /** * Helper function to add links to a field collection field. + * + * Takes $ops as an array and returns a render array snippet. */ -function field_collection_field_formatter_links(&$element, $entity_type, $entity, $field, $instance, $langcode, $items, $display) { - $settings = $display['settings']; - if ($settings['add'] && ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || count($items) < $field['cardinality'])) { - // Check whether the current is allowed to create a new item. +function field_collection_field_formatter_op_links($entity_type, $entity, $field, $instance, $langcode, $items, $settings, $ops, $field_collection_item = NULL) { + + if (!$settings['show_op_links']) { + return NULL; + } + + // If the $op is add, check if there is room for more field collection items. + $room_for_more = in_array('add', $ops) ? ($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || count($items) < $field['cardinality']) : TRUE; + + if (in_array('add', $ops)) { + // Create a dummy field collection item to test against in case none have been added yet. $field_collection_item = entity_create('field_collection_item', array('field_name' => $field['field_name'])); $field_collection_item->setHostEntity($entity_type, $entity, LANGUAGE_NONE, FALSE); + } - if (field_collection_item_access('create', $field_collection_item)) { - $path = field_collection_field_get_path($field); - list($id) = entity_extract_ids($entity_type, $entity); - $element['#suffix'] = ''; - if (!empty($settings['description'])) { - $element['#suffix'] .= '
' . field_filter_xss($instance['description']) . '
'; + // Create the render element. + $op_links = array(); + + foreach ($ops as $op) { + + // Check if $op links should be added. + if (!empty($settings[$op]) && $room_for_more && field_collection_item_access($op, $field_collection_item)) { + + // Build link. + $title = entity_i18n_string("field:{$field['field_name']}:{$instance['bundle']}:setting_$op", $settings[$op]); + + if ($op == 'add') { + list($entity_id) = entity_extract_ids($entity_type, $entity); + $path = field_collection_field_get_path($field) . '/add/' . $entity_type . '/' . $entity_id; + } + else { + $path = $field_collection_item->path() . '/' . $op; } - $title = entity_i18n_string("field:{$field['field_name']}:{$instance['bundle']}:setting_add", $settings['add']); - $add_path = $path . '/add/' . $entity_type . '/' . $id; - $element['#suffix'] .= ''; + + $op_links['#links'][] = l($title, $path, array('query' => drupal_get_destination())); + + // Add help text. + $op_links['#description'] = $op == 'add' && $settings['description'] ? field_filter_xss($instance['description']) : FALSE; } } - // If there is no add link, add a special class to the last item. - if (empty($element['#suffix'])) { - $index = count(element_children($element)) - 1; - $element[$index]['#attributes']['class'][] = 'field-collection-view-final'; - } - $element += array('#prefix' => '', '#suffix' => ''); - $element['#prefix'] .= '
'; - $element['#suffix'] .= '
'; + if (!empty($op_links)) { + $op_links['#theme'] = 'field_collection_op_links'; + $op_links['#weight'] = '1000'; - return $element; + // Include information about the field collection for theme suggestions. + $op_links['#parent']['#field_collection_name'] = $field['field_name']; + $op_links['#parent']['#view_mode'] = $settings['view_mode']; + + return $op_links; + } } /** - * Themes field collection items printed using the field_collection_view formatter. + * Impliments hook_preprocess_HOOK(). */ -function theme_field_collection_view($variables) { - $element = $variables['element']; - return '' . $element['#children'] . ''; +function field_collection_preprocess_entity(&$variables) { + + // Use the elements array in case template_preprocess_entity in entity module changes. + if ($variables['elements']['#entity_type'] == 'field_collection_item') { + + // Replace the default entity classes with something simpler. + $variables['classes_array'] = array(); + $variables['classes_array'][] = $variables['elements']['#entity_type']; + $variables['classes_array'][] = drupal_clean_css_identifier('view-mode-' . $variables['elements']['#view_mode']); + + // Add theme suggestions + $entity_type = $variables['elements']['#entity_type']; + $view_mode = $variables['elements']['#view_mode']; + $field_collection_name = $variables['elements']['#bundle']; + $instance = $variables['elements']['#entity']->instanceInfo(); + $parent_bundle = $instance['bundle']; + + // Replace the default entity classes with field collection specific suggestions. + $variables['theme_hook_suggestions'] = array(); + $variables['theme_hook_suggestions'][] = $entity_type; + $variables['theme_hook_suggestions'][] = $entity_type . '__' . $view_mode; + $variables['theme_hook_suggestions'][] = $entity_type . '__' . $parent_bundle; + $variables['theme_hook_suggestions'][] = $entity_type . '__' . $field_collection_name; + $variables['theme_hook_suggestions'][] = $entity_type . '__' . $parent_bundle . '__' . $view_mode; + $variables['theme_hook_suggestions'][] = $entity_type . '__' . $field_collection_name . '__' . $view_mode; + $variables['theme_hook_suggestions'][] = $entity_type . '__' . $field_collection_name . '__' . $parent_bundle; + $variables['theme_hook_suggestions'][] = $entity_type . '__' . $field_collection_name . '__' . $parent_bundle . '__' . $view_mode; + } +} + +/** + * Impliments template_preprocess_hook(). + */ +function template_preprocess_field_collection_op_links(&$variables) { + + $variables['links'] = $variables['op_links']['#links']; + $variables['help_text'] = $variables['op_links']['#description']; + $variables['view_mode'] = $variables['op_links']['#parent']['#view_mode']; + + // Add theme suggestions. + $op_type = in_array('add', $variables['op_links']['#links']) ? 'add' : 'edit-delete'; + $field_collection_name = $variables['op_links']['#parent']['#field_collection_name']; + + $variables['theme_hook_suggestions'][] = 'field_collection_op_links__' . $op_type; + $variables['theme_hook_suggestions'][] = 'field_collection_op_links__' . $variables['view_mode']; + $variables['theme_hook_suggestions'][] = 'field_collection_op_links__' . $field_collection_name; + $variables['theme_hook_suggestions'][] = 'field_collection_op_links__' . $op_type . '__' . $variables['view_mode']; + $variables['theme_hook_suggestions'][] = 'field_collection_op_links__' . $field_collection_name . '__' . $op_type; + $variables['theme_hook_suggestions'][] = 'field_collection_op_links__' . $field_collection_name . '__' . $variables['view_mode']; + $variables['theme_hook_suggestions'][] = 'field_collection_op_links__' . $field_collection_name . '__' . $op_type . '__' . $variables['view_mode']; } /** @@ -1377,7 +1486,6 @@ function field_collection_i18n_string_list_field_alter(&$properties, $type, $ins if ($field['type'] == 'field_collection' && !empty($instance['display'])) { foreach ($instance['display'] as $view_mode => $display) { - if ($display['type'] != 'field_collection_fields') { $display['settings'] += array('edit' => 'edit', 'delete' => 'delete', 'add' => 'add'); $properties['field'][$instance['field_name']][$instance['bundle']]['setting_edit'] = array( @@ -1392,7 +1500,7 @@ function field_collection_i18n_string_list_field_alter(&$properties, $type, $ins 'title' => t('Add link title'), 'string' => $display['settings']['add'], ); - } + } } } diff --git a/theme/field-collection-item-link.tpl.php b/theme/field-collection-item-link.tpl.php new file mode 100644 index 0000000..20effbd --- /dev/null +++ b/theme/field-collection-item-link.tpl.php @@ -0,0 +1,53 @@ + + +
> +
> + + + +
+ + + + + +
\ No newline at end of file diff --git a/theme/field-collection-item.tpl.php b/theme/field-collection-item.tpl.php new file mode 100644 index 0000000..37215d8 --- /dev/null +++ b/theme/field-collection-item.tpl.php @@ -0,0 +1,58 @@ + + + +
> + +
> + +
+ + + + + +
\ No newline at end of file diff --git a/theme/field-collection-op-links.tpl.php b/theme/field-collection-op-links.tpl.php new file mode 100644 index 0000000..c8da648 --- /dev/null +++ b/theme/field-collection-op-links.tpl.php @@ -0,0 +1,45 @@ + + + +
+ + +