Newer
Older
Angie Byron
committed
<?php
/**
* @file
* Administrative interface for custom field type creation.
*/
/**
* Menu callback; lists all defined fields for quick reference.
*/
function field_ui_fields_list() {
$instances = field_info_instances();
$field_types = field_info_field_types();
$bundles = field_info_bundles();
Angie Byron
committed
$modules = system_rebuild_module_data();
Angie Byron
committed
$header = array(t('Field name'), t('Field type'), t('Used in'));
$rows = array();
foreach ($instances as $entity_type => $type_bundles) {
foreach ($type_bundles as $bundle => $bundle_instances) {
foreach ($bundle_instances as $field_name => $instance) {
Dries Buytaert
committed
$field = field_info_field($field_name);
Angie Byron
committed
// Initialize the row if we encounter the field for the first time.
if (!isset($rows[$field_name])) {
$rows[$field_name]['class'] = $field['locked'] ? array('menu-disabled') : array('');
$rows[$field_name]['data'][0] = $field['locked'] ? t('@field_name (Locked)', array('@field_name' => $field_name)) : $field_name;
$module_name = $field_types[$field['type']]['module'];
$rows[$field_name]['data'][1] = $field_types[$field['type']]['label'] . ' ' . t('(module: !module)', array('!module' => $modules[$module_name]->info['name']));
}
// Add the current instance.
$admin_path = _field_ui_bundle_admin_path($entity_type, $bundle);
Angie Byron
committed
$rows[$field_name]['data'][2][] = $admin_path ? l($bundles[$entity_type][$bundle]['label'], $admin_path . '/fields') : $bundles[$entity_type][$bundle]['label'];
Dries Buytaert
committed
}
Angie Byron
committed
}
}
foreach ($rows as $field_name => $cell) {
$rows[$field_name]['data'][2] = implode(', ', $cell['data'][2]);
}
if (empty($rows)) {
Dries Buytaert
committed
$output = t('No fields have been defined yet.');
Angie Byron
committed
}
else {
// Sort rows by field name.
ksort($rows);
Dries Buytaert
committed
$output = theme('table', array('header' => $header, 'rows' => $rows));
Angie Byron
committed
}
return $output;
}
/**
* Helper function to display a message about inactive fields.
*/
function field_ui_inactive_message($entity_type, $bundle) {
$inactive_instances = field_ui_inactive_instances($entity_type, $bundle);
Angie Byron
committed
if (!empty($inactive_instances)) {
$field_types = field_info_field_types();
$widget_types = field_info_widget_types();
foreach ($inactive_instances as $field_name => $instance) {
$list[] = t('%field (@field_name) field requires the %widget_type widget provided by %widget_module module', array(
'%field' => $instance['label'],
'@field_name' => $instance['field_name'],
Dries Buytaert
committed
'%widget_type' => isset($widget_types[$instance['widget']['type']]) ? $widget_types[$instance['widget']['type']]['label'] : $instance['widget']['type'],
Angie Byron
committed
'%widget_module' => $instance['widget']['module'],
));
}
Dries Buytaert
committed
drupal_set_message(t('Inactive fields are not shown unless their providing modules are enabled. The following fields are not enabled: !list', array('!list' => theme('item_list', array('items' => $list)))), 'error');
Angie Byron
committed
}
}
Dries Buytaert
committed
/**
* Helper function: determines the rendering order of a tree array.
*
* This is intended as a callback for array_reduce().
*/
function _field_ui_reduce_order($array, $a) {
$array = !isset($array) ? array() : $array;
Dries Buytaert
committed
if ($a['name']) {
$array[] = $a['name'];
}
if (!empty($a['children'])) {
uasort($a['children'], 'drupal_sort_weight');
$array = array_merge($array, array_reduce($a['children'], '_field_ui_reduce_order'));
}
return $array;
}
/**
* Returns the region to which a row in the 'Manage fields' screen belongs.
Dries Buytaert
committed
*
* This function is used as a #row_callback in field_ui_field_overview_form(),
* and is called during field_ui_table_pre_render().
Dries Buytaert
committed
*/
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
function field_ui_field_overview_row_region($row) {
switch ($row['#row_type']) {
case 'field':
case 'extra_field':
return 'main';
case 'add_new_field':
// If no input in 'label', assume the row has not been dragged out of the
// 'add new' section.
return (!empty($row['label']['#value']) ? 'main' : 'add_new');
}
}
/**
* Returns the region to which a row in the 'Manage display' screen belongs.
*
* This function is used as a #row_callback in field_ui_field_overview_form(),
* and is called during field_ui_table_pre_render().
*/
function field_ui_display_overview_row_region($row) {
switch ($row['#row_type']) {
case 'field':
case 'extra_field':
return ($row['format']['type']['#value'] == 'hidden' ? 'hidden' : 'visible');
}
}
/**
* Pre-render callback for field_ui_table elements.
*/
function field_ui_table_pre_render($elements) {
$js_settings = array();
Dries Buytaert
committed
// For each region, build the tree structure from the weight and parenting
// data contained in the flat form structure, to determine row order and
// indentation.
$regions = $elements['#regions'];
Dries Buytaert
committed
$tree = array('' => array('name' => '', 'children' => array()));
$trees = array_fill_keys(array_keys($regions), $tree);
Dries Buytaert
committed
$parents = array();
$list = drupal_map_assoc(element_children($elements));
Dries Buytaert
committed
// Iterate on rows until we can build a known tree path for all of them.
while ($list) {
foreach ($list as $name) {
$row = &$elements[$name];
$parent = $row['parent_wrapper']['parent']['#value'];
// Proceed if parent is known.
if (empty($parent) || isset($parents[$parent])) {
// Grab parent, and remove the row from the next iteration.
Dries Buytaert
committed
$parents[$name] = $parent ? array_merge($parents[$parent], array($parent)) : array();
unset($list[$name]);
// Determine the region for the row.
$function = $row['#region_callback'];
$region_name = $function($row);
Dries Buytaert
committed
// Add the element in the tree.
$target = &$trees[$region_name][''];
Dries Buytaert
committed
foreach ($parents[$name] as $key) {
$target = &$target['children'][$key];
}
$target['children'][$name] = array('name' => $name, 'weight' => $row['weight']['#value']);
// Add tabledrag indentation to the first row cell.
if ($depth = count($parents[$name])) {
$cell = current(element_children($row));
$row[$cell]['#prefix'] = theme('indentation', array('size' => $depth)) . (isset($row[$cell]['#prefix']) ? $row[$cell]['#prefix'] : '');
}
// Add row id and associate JS settings.
$id = drupal_html_class($name);
$row['#attributes']['id'] = $id;
Angie Byron
committed
if (isset($row['#js_settings'])) {
$row['#js_settings'] += array(
'rowHandler' => $row['#row_type'],
'name' => $name,
'region' => $region_name,
);
$js_settings[$id] = $row['#js_settings'];
}
Dries Buytaert
committed
}
}
}
// Determine rendering order from the tree structure.
foreach ($regions as $region_name => $region) {
$elements['#regions'][$region_name]['rows_order'] = array_reduce($trees[$region_name], '_field_ui_reduce_order');
}
Dries Buytaert
committed
Dries Buytaert
committed
$elements['#attached']['js'][] = array(
'type' => 'setting',
'data' => array('fieldUIRowsData' => $js_settings),
);
return $elements;
Dries Buytaert
committed
}
/**
* Returns HTML for Field UI overview tables.
*
* @param $variables
* An associative array containing:
* - elements: An associative array containing a Form API structure to be
* rendered as a table.
*
* @ingroup themeable
*/
function theme_field_ui_table($variables) {
$elements = $variables['elements'];
$table = array();
$js_settings = array();
Dries Buytaert
committed
// Add table headers and attributes.
Dries Buytaert
committed
foreach (array('header', 'attributes') as $key) {
if (isset($elements["#$key"])) {
$table[$key] = $elements["#$key"];
}
}
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
// Determine the colspan to use for region rows, by checking the number of
// columns in the headers.
$colums_count = 0;
foreach ($table['header'] as $header) {
$colums_count += (is_array($header) && isset($header['colspan']) ? $header['colspan'] : 1);
}
// Render rows, region by region.
foreach ($elements['#regions'] as $region_name => $region) {
$region_name_class = drupal_html_class($region_name);
// Add region rows.
if (isset($region['title'])) {
$table['rows'][] = array(
'class' => array('region-title', 'region-' . $region_name_class . '-title'),
'no_striping' => TRUE,
'data' => array(
array('data' => $region['title'], 'colspan' => $colums_count),
),
);
}
if (isset($region['message'])) {
$class = (empty($region['rows_order']) ? 'region-empty' : 'region-populated');
$table['rows'][] = array(
'class' => array('region-message', 'region-' . $region_name_class . '-message', $class),
'no_striping' => TRUE,
'data' => array(
array('data' => $region['message'], 'colspan' => $colums_count),
),
);
}
// Add form rows, in the order determined at pre-render time.
foreach ($region['rows_order'] as $name) {
$element = $elements[$name];
$row = array('data' => array());
if (isset($element['#attributes'])) {
$row += $element['#attributes'];
}
Dries Buytaert
committed
foreach (element_children($element) as $cell_key) {
$cell = array('data' => drupal_render($element[$cell_key]));
if (isset($element[$cell_key]['#cell_attributes'])) {
$cell += $element[$cell_key]['#cell_attributes'];
}
$row['data'][] = $cell;
Dries Buytaert
committed
}
$table['rows'][] = $row;
Dries Buytaert
committed
}
}
return theme('table', $table);
}
Angie Byron
committed
/**
Dries Buytaert
committed
* Menu callback; listing of fields for a bundle.
Angie Byron
committed
*
* Allows fields and pseudo-fields to be re-ordered.
*/
function field_ui_field_overview_form($form, &$form_state, $entity_type, $bundle) {
$bundle = field_extract_bundle($entity_type, $bundle);
Angie Byron
committed
field_ui_inactive_message($entity_type, $bundle);
$admin_path = _field_ui_bundle_admin_path($entity_type, $bundle);
Angie Byron
committed
// When displaying the form, make sure the list of fields is up-to-date.
if (empty($form_state['post'])) {
Dries Buytaert
committed
field_info_cache_clear();
Angie Byron
committed
}
// Gather bundle information.
$instances = field_info_instances($entity_type, $bundle);
Angie Byron
committed
$field_types = field_info_field_types();
$widget_types = field_info_widget_types();
Dries Buytaert
committed
$extra_fields = field_info_extra_fields($entity_type, $bundle, 'form');
Angie Byron
committed
$form += array(
'#entity_type' => $entity_type,
Angie Byron
committed
'#bundle' => $bundle,
'#fields' => array_keys($instances),
Dries Buytaert
committed
'#extra' => array_keys($extra_fields),
Angie Byron
committed
);
Dries Buytaert
committed
$table = array(
'#type' => 'field_ui_table',
Dries Buytaert
committed
'#tree' => TRUE,
'#header' => array(
t('Label'),
t('Weight'),
t('Parent'),
t('Name'),
t('Field'),
t('Widget'),
array('data' => t('Operations'), 'colspan' => 2),
),
Dries Buytaert
committed
'#parent_options' => array(),
'#regions' => array(
Angie Byron
committed
'main' => array('message' => t('No fields are present yet.')),
'add_new' => array('title' => ' '),
),
'#attributes' => array(
'class' => array('field-ui-overview'),
'id' => 'field-overview',
),
Dries Buytaert
committed
);
Angie Byron
committed
// Fields.
foreach ($instances as $name => $instance) {
$field = field_info_field($instance['field_name']);
$admin_field_path = $admin_path . '/fields/' . $instance['field_name'];
Dries Buytaert
committed
$table[$name] = array(
'#attributes' => array('class' => array('draggable', 'tabledrag-leaf')),
'#row_type' => 'field',
'#region_callback' => 'field_ui_field_overview_row_region',
Angie Byron
committed
'label' => array(
'#markup' => check_plain($instance['label']),
),
Dries Buytaert
committed
'weight' => array(
'#type' => 'textfield',
Dries Buytaert
committed
'#title' => t('Weight for @title', array('@title' => $instance['label'])),
'#title_display' => 'invisible',
'#default_value' => $instance['widget']['weight'],
Dries Buytaert
committed
'#size' => 3,
'#attributes' => array('class' => array('field-weight')),
),
'parent_wrapper' => array(
'parent' => array(
'#type' => 'select',
Dries Buytaert
committed
'#title' => t('Parent for @title', array('@title' => $instance['label'])),
'#title_display' => 'invisible',
'#options' => $table['#parent_options'],
Angie Byron
committed
'#empty_value' => '',
Dries Buytaert
committed
'#attributes' => array('class' => array('field-parent')),
'#parents' => array('fields', $name, 'parent'),
Dries Buytaert
committed
),
'hidden_name' => array(
'#type' => 'hidden',
'#default_value' => $name,
'#attributes' => array('class' => array('field-name')),
),
),
Angie Byron
committed
'field_name' => array(
'#markup' => $instance['field_name'],
),
'type' => array(
'#type' => 'link',
'#title' => t($field_types[$field['type']]['label']),
'#href' => $admin_field_path . '/field-settings',
'#options' => array('attributes' => array('title' => t('Edit field settings.'))),
Angie Byron
committed
),
'widget_type' => array(
'#type' => 'link',
'#title' => t($widget_types[$instance['widget']['type']]['label']),
'#href' => $admin_field_path . '/widget-type',
'#options' => array('attributes' => array('title' => t('Change widget type.'))),
Angie Byron
committed
),
'edit' => array(
'#type' => 'link',
'#title' => t('edit'),
'#href' => $admin_field_path,
'#options' => array('attributes' => array('title' => t('Edit instance settings.'))),
Angie Byron
committed
),
'delete' => array(
'#type' => 'link',
'#title' => t('delete'),
'#href' => $admin_field_path . '/delete',
'#options' => array('attributes' => array('title' => t('Delete instance.'))),
),
Angie Byron
committed
);
if (!empty($instance['locked'])) {
Dries Buytaert
committed
$table[$name]['edit'] = array('#value' => t('Locked'));
$table[$name]['delete'] = array();
$table[$name]['#attributes']['class'][] = 'menu-disabled';
Angie Byron
committed
}
}
// Non-field elements.
Dries Buytaert
committed
foreach ($extra_fields as $name => $extra_field) {
Dries Buytaert
committed
$table[$name] = array(
'#attributes' => array('class' => array('draggable', 'tabledrag-leaf')),
'#row_type' => 'extra_field',
'#region_callback' => 'field_ui_field_overview_row_region',
Angie Byron
committed
'label' => array(
Dries Buytaert
committed
'#markup' => check_plain($extra_field['label']),
Angie Byron
committed
),
'weight' => array(
'#type' => 'textfield',
'#default_value' => $extra_field['weight'],
Angie Byron
committed
'#size' => 3,
Dries Buytaert
committed
'#attributes' => array('class' => array('field-weight')),
'#title_display' => 'invisible',
Dries Buytaert
committed
'#title' => t('Weight for @title', array('@title' => $extra_field['label'])),
Angie Byron
committed
),
Dries Buytaert
committed
'parent_wrapper' => array(
'parent' => array(
'#type' => 'select',
Dries Buytaert
committed
'#title' => t('Parent for @title', array('@title' => $extra_field['label'])),
'#title_display' => 'invisible',
'#options' => $table['#parent_options'],
Angie Byron
committed
'#empty_value' => '',
Dries Buytaert
committed
'#attributes' => array('class' => array('field-parent')),
'#parents' => array('fields', $name, 'parent'),
Dries Buytaert
committed
),
'hidden_name' => array(
'#type' => 'hidden',
'#default_value' => $name,
'#attributes' => array('class' => array('field-name')),
),
),
'field_name' => array(
'#markup' => $name,
),
'type' => array(
'#markup' => isset($extra_field['description']) ? $extra_field['description'] : '',
'#cell_attributes' => array('colspan' => 2),
),
Angie Byron
committed
'edit' => array(
Dries Buytaert
committed
'#markup' => isset($extra_field['edit']) ? $extra_field['edit'] : '',
Angie Byron
committed
),
'delete' => array(
Dries Buytaert
committed
'#markup' => isset($extra_field['delete']) ? $extra_field['delete'] : '',
Angie Byron
committed
),
);
}
// Additional row: add new field.
$max_weight = field_info_max_weight($entity_type, $bundle, 'form');
Angie Byron
committed
$field_type_options = field_ui_field_type_options();
$widget_type_options = field_ui_widget_type_options(NULL, TRUE);
if ($field_type_options && $widget_type_options) {
$name = '_add_new_field';
Dries Buytaert
committed
$table[$name] = array(
'#attributes' => array('class' => array('draggable', 'tabledrag-leaf', 'add-new')),
'#row_type' => 'add_new_field',
'#region_callback' => 'field_ui_field_overview_row_region',
Angie Byron
committed
'label' => array(
'#type' => 'textfield',
Dries Buytaert
committed
'#title' => t('New field label'),
'#title_display' => 'invisible',
Angie Byron
committed
'#size' => 15,
'#description' => t('Label'),
Dries Buytaert
committed
'#prefix' => '<div class="label-input"><div class="add-new-placeholder">' . t('Add new field') .'</div>',
'#suffix' => '</div>',
),
'weight' => array(
'#type' => 'textfield',
'#default_value' => $max_weight + 1,
Dries Buytaert
committed
'#size' => 3,
'#title_display' => 'invisible',
'#title' => t('Weight for new field'),
'#attributes' => array('class' => array('field-weight')),
'#prefix' => '<div class="add-new-placeholder"> </div>',
),
'parent_wrapper' => array(
'parent' => array(
'#type' => 'select',
Dries Buytaert
committed
'#title' => t('Parent for new field'),
'#title_display' => 'invisible',
'#options' => $table['#parent_options'],
Angie Byron
committed
'#empty_value' => '',
Dries Buytaert
committed
'#attributes' => array('class' => array('field-parent')),
'#prefix' => '<div class="add-new-placeholder"> </div>',
'#parents' => array('fields', $name, 'parent'),
Dries Buytaert
committed
),
'hidden_name' => array(
'#type' => 'hidden',
'#default_value' => $name,
'#attributes' => array('class' => array('field-name')),
),
Angie Byron
committed
),
'field_name' => array(
'#type' => 'textfield',
Dries Buytaert
committed
'#title' => t('New field name'),
'#title_display' => 'invisible',
Angie Byron
committed
// This field should stay LTR even for RTL languages.
'#field_prefix' => '<span dir="ltr">field_',
'#field_suffix' => '</span>‎',
'#attributes' => array('dir'=>'ltr'),
'#size' => 10,
Angie Byron
committed
'#description' => t('Field name (a-z, 0-9, _)'),
Dries Buytaert
committed
'#prefix' => '<div class="add-new-placeholder"> </div>',
Angie Byron
committed
),
'type' => array(
'#type' => 'select',
Dries Buytaert
committed
'#title' => t('Type of new field'),
'#title_display' => 'invisible',
Angie Byron
committed
'#options' => $field_type_options,
Dries Buytaert
committed
'#empty_option' => t('- Select a field type -'),
Angie Byron
committed
'#description' => t('Type of data to store.'),
Dries Buytaert
committed
'#attributes' => array('class' => array('field-type-select')),
'#prefix' => '<div class="add-new-placeholder"> </div>',
Angie Byron
committed
),
'widget_type' => array(
'#type' => 'select',
Dries Buytaert
committed
'#title' => t('Widget for new field'),
'#title_display' => 'invisible',
Angie Byron
committed
'#options' => $widget_type_options,
Dries Buytaert
committed
'#empty_option' => t('- Select a widget -'),
Angie Byron
committed
'#description' => t('Form element to edit the data.'),
Dries Buytaert
committed
'#attributes' => array('class' => array('widget-type-select')),
'#cell_attributes' => array('colspan' => 3),
'#prefix' => '<div class="add-new-placeholder"> </div>',
Angie Byron
committed
),
Angie Byron
committed
'translatable' => array(
'#type' => 'value',
'#value' => FALSE,
),
Angie Byron
committed
);
}
// Additional row: add existing field.
$existing_field_options = field_ui_existing_field_options($entity_type, $bundle);
Angie Byron
committed
if ($existing_field_options && $widget_type_options) {
$name = '_add_existing_field';
Dries Buytaert
committed
$table[$name] = array(
'#attributes' => array('class' => array('draggable', 'tabledrag-leaf', 'add-new')),
'#row_type' => 'add_new_field',
'#region_callback' => 'field_ui_field_overview_row_region',
Angie Byron
committed
'label' => array(
'#type' => 'textfield',
Dries Buytaert
committed
'#title' => t('Existing field label'),
'#title_display' => 'invisible',
Angie Byron
committed
'#size' => 15,
'#description' => t('Label'),
Dries Buytaert
committed
'#attributes' => array('class' => array('label-textfield')),
'#prefix' => '<div class="label-input"><div class="add-new-placeholder">' . t('Add existing field') .'</div>',
'#suffix' => '</div>',
),
'weight' => array(
'#type' => 'textfield',
'#default_value' => $max_weight + 2,
Dries Buytaert
committed
'#size' => 3,
'#title_display' => 'invisible',
'#title' => t('Weight for added field'),
'#attributes' => array('class' => array('field-weight')),
'#prefix' => '<div class="add-new-placeholder"> </div>',
),
'parent_wrapper' => array(
'parent' => array(
'#type' => 'select',
Dries Buytaert
committed
'#title' => t('Parent for existing field'),
'#title_display' => 'invisible',
'#options' => $table['#parent_options'],
Angie Byron
committed
'#empty_value' => '',
Dries Buytaert
committed
'#attributes' => array('class' => array('field-parent')),
'#prefix' => '<div class="add-new-placeholder"> </div>',
'#parents' => array('fields', $name, 'parent'),
Dries Buytaert
committed
),
'hidden_name' => array(
'#type' => 'hidden',
'#default_value' => $name,
'#attributes' => array('class' => array('field-name')),
),
Angie Byron
committed
),
'field_name' => array(
'#type' => 'select',
Dries Buytaert
committed
'#title' => t('Existing field to share'),
'#title_display' => 'invisible',
Angie Byron
committed
'#options' => $existing_field_options,
Dries Buytaert
committed
'#empty_option' => t('- Select an existing field -'),
Angie Byron
committed
'#description' => t('Field to share'),
Dries Buytaert
committed
'#attributes' => array('class' => array('field-select')),
'#cell_attributes' => array('colspan' => 2),
'#prefix' => '<div class="add-new-placeholder"> </div>',
Angie Byron
committed
),
'widget_type' => array(
'#type' => 'select',
Dries Buytaert
committed
'#title' => t('Widget for existing field'),
'#title_display' => 'invisible',
Angie Byron
committed
'#options' => $widget_type_options,
Dries Buytaert
committed
'#empty_option' => t('- Select a widget -'),
Angie Byron
committed
'#description' => t('Form element to edit the data.'),
Dries Buytaert
committed
'#attributes' => array('class' => array('widget-type-select')),
'#cell_attributes' => array('colspan' => 3),
'#prefix' => '<div class="add-new-placeholder"> </div>',
Angie Byron
committed
),
);
}
$form['fields'] = $table;
Dries Buytaert
committed
Dries Buytaert
committed
$form['actions'] = array('#type' => 'actions');
$form['actions']['submit'] = array('#type' => 'submit', '#value' => t('Save'));
Angie Byron
committed
Dries Buytaert
committed
$form['#attached']['css'][] = drupal_get_path('module', 'field_ui') . '/field_ui.css';
$form['#attached']['js'][] = drupal_get_path('module', 'field_ui') . '/field_ui.js';
Angie Byron
committed
// Add settings for the update selects behavior.
$js_fields = array();
Dries Buytaert
committed
foreach ($existing_field_options as $field_name => $fields) {
Angie Byron
committed
$field = field_info_field($field_name);
$instance = field_info_instance($form['#entity_type'], $field_name, $form['#bundle']);
Angie Byron
committed
$js_fields[$field_name] = array('label' => $instance['label'], 'type' => $field['type'], 'widget' => $instance['widget']['type']);
}
Dries Buytaert
committed
$form['#attached']['js'][] = array(
'type' => 'setting',
'data' => array('fields' => $js_fields, 'fieldWidgetTypes' => field_ui_widget_type_options()),
Dries Buytaert
committed
);
Angie Byron
committed
Dries Buytaert
committed
// Add tabledrag behavior.
$form['#attached']['drupal_add_tabledrag'][] = array('field-overview', 'order', 'sibling', 'field-weight');
$form['#attached']['drupal_add_tabledrag'][] = array('field-overview', 'match', 'parent', 'field-parent', 'field-parent', 'field-name');
return $form;
Angie Byron
committed
}
/**
* Validate handler for the field overview form.
*/
function field_ui_field_overview_form_validate($form, &$form_state) {
_field_ui_field_overview_form_validate_add_new($form, $form_state);
_field_ui_field_overview_form_validate_add_existing($form, $form_state);
}
/**
* Helper function for field_ui_field_overview_form_validate.
*
* Validate the 'add new field' row.
*/
function _field_ui_field_overview_form_validate_add_new($form, &$form_state) {
$field = $form_state['values']['fields']['_add_new_field'];
Angie Byron
committed
// Validate if any information was provided in the 'add new field' row.
if (array_filter(array($field['label'], $field['field_name'], $field['type'], $field['widget_type']))) {
// Missing label.
if (!$field['label']) {
form_set_error('fields][_add_new_field][label', t('Add new field: you need to provide a label.'));
Angie Byron
committed
}
// Missing field name.
if (!$field['field_name']) {
form_set_error('fields][_add_new_field][field_name', t('Add new field: you need to provide a field name.'));
Angie Byron
committed
}
// Field name validation.
else {
$field_name = $field['field_name'];
// Add the 'field_' prefix.
if (substr($field_name, 0, 6) != 'field_') {
$field_name = 'field_' . $field_name;
form_set_value($form['fields']['_add_new_field']['field_name'], $field_name, $form_state);
Angie Byron
committed
}
// Invalid field name.
if (!preg_match('!^field_[a-z0-9_]+$!', $field_name)) {
form_set_error('fields][_add_new_field][field_name', t('Add new field: the field name %field_name is invalid. The name must include only lowercase unaccentuated letters, numbers, and underscores.', array('%field_name' => $field_name)));
Angie Byron
committed
}
if (strlen($field_name) > 32) {
form_set_error('fields][_add_new_field][field_name', t("Add new field: the field name %field_name is too long. The name is limited to 32 characters, including the 'field_' prefix.", array('%field_name' => $field_name)));
Angie Byron
committed
}
// Field name already exists. We need to check inactive fields as well, so
// we can't use field_info_fields().
$fields = field_read_fields(array('field_name' => $field_name), array('include_inactive' => TRUE));
if ($fields) {
form_set_error('fields][_add_new_field][field_name', t('Add new field: the field name %field_name already exists.', array('%field_name' => $field_name)));
Angie Byron
committed
}
}
// Missing field type.
if (!$field['type']) {
form_set_error('fields][_add_new_field][type', t('Add new field: you need to select a field type.'));
Angie Byron
committed
}
// Missing widget type.
if (!$field['widget_type']) {
form_set_error('fields][_add_new_field][widget_type', t('Add new field: you need to select a widget.'));
Angie Byron
committed
}
// Wrong widget type.
elseif ($field['type']) {
$widget_types = field_ui_widget_type_options($field['type']);
if (!isset($widget_types[$field['widget_type']])) {
form_set_error('fields][_add_new_field][widget_type', t('Add new field: invalid widget.'));
Angie Byron
committed
}
}
}
}
/**
* Helper function for field_ui_field_overview_form_validate.
*
* Validate the 'add existing field' row.
*/
function _field_ui_field_overview_form_validate_add_existing($form, &$form_state) {
// The form element might be absent if no existing fields can be added to
Dries Buytaert
committed
// this bundle.
if (isset($form_state['values']['fields']['_add_existing_field'])) {
$field = $form_state['values']['fields']['_add_existing_field'];
Angie Byron
committed
// Validate if any information was provided in the 'add existing field' row.
if (array_filter(array($field['label'], $field['field_name'], $field['widget_type']))) {
// Missing label.
if (!$field['label']) {
form_set_error('fields][_add_existing_field][label', t('Add existing field: you need to provide a label.'));
Angie Byron
committed
}
// Missing existing field name.
if (!$field['field_name']) {
form_set_error('fields][_add_existing_field][field_name', t('Add existing field: you need to select a field.'));
Angie Byron
committed
}
// Missing widget type.
if (!$field['widget_type']) {
form_set_error('fields][_add_existing_field][widget_type', t('Add existing field: you need to select a widget.'));
Angie Byron
committed
}
// Wrong widget type.
elseif ($field['field_name'] && ($existing_field = field_info_field($field['field_name']))) {
$widget_types = field_ui_widget_type_options($existing_field['type']);
if (!isset($widget_types[$field['widget_type']])) {
form_set_error('fields][_add_existing_field][widget_type', t('Add existing field: invalid widget.'));
Angie Byron
committed
}
}
}
}
}
/**
* Submit handler for the field overview form.
*/
function field_ui_field_overview_form_submit($form, &$form_state) {
$form_values = $form_state['values']['fields'];
$entity_type = $form['#entity_type'];
Angie Byron
committed
$bundle = $form['#bundle'];
$admin_path = _field_ui_bundle_admin_path($entity_type, $bundle);
Angie Byron
committed
Dries Buytaert
committed
$bundle_settings = field_bundle_settings($entity_type, $bundle);
Angie Byron
committed
// Update field weights.
foreach ($form_values as $key => $values) {
if (in_array($key, $form['#fields'])) {
$instance = field_read_instance($entity_type, $key, $bundle);
Angie Byron
committed
$instance['widget']['weight'] = $values['weight'];
field_update_instance($instance);
}
elseif (in_array($key, $form['#extra'])) {
Dries Buytaert
committed
$bundle_settings['extra_fields']['form'][$key]['weight'] = $values['weight'];
Angie Byron
committed
}
}
Dries Buytaert
committed
field_bundle_settings($entity_type, $bundle, $bundle_settings);
Angie Byron
committed
$destinations = array();
// Create new field.
$field = array();
if (!empty($form_values['_add_new_field']['field_name'])) {
$values = $form_values['_add_new_field'];
$field = array(
'field_name' => $values['field_name'],
'type' => $values['type'],
Angie Byron
committed
'translatable' => $values['translatable'],
Angie Byron
committed
);
$instance = array(
'field_name' => $field['field_name'],
'entity_type' => $entity_type,
Angie Byron
committed
'bundle' => $bundle,
'label' => $values['label'],
'widget' => array(
'type' => $values['widget_type'],
'weight' => $values['weight'],
),
);
// Create the field and instance.
try {
field_create_field($field);
field_create_instance($instance);
$destinations[] = $admin_path . '/fields/' . $field['field_name'] . '/field-settings';
$destinations[] = $admin_path . '/fields/' . $field['field_name'];
Angie Byron
committed
// Store new field information for any additional submit handlers.
$form_state['fields_added']['_add_new_field'] = $field['field_name'];
}
catch (Exception $e) {
drupal_set_message(t('There was a problem creating field %label: @message.', array('%label' => $instance['label'], '@message' => $e->getMessage())));
}
}
// Add existing field.
if (!empty($form_values['_add_existing_field']['field_name'])) {
$values = $form_values['_add_existing_field'];
$field = field_info_field($values['field_name']);
if (!empty($field['locked'])) {
drupal_set_message(t('The field %label cannot be added because it is locked.', array('%label' => $values['label'])));
}
else {
$instance = array(
'field_name' => $field['field_name'],
'entity_type' => $entity_type,
Angie Byron
committed
'bundle' => $bundle,
'label' => $values['label'],
'widget' => array(
'type' => $values['widget_type'],
'weight' => $values['weight'],
),
);
try {
field_create_instance($instance);
$destinations[] = $admin_path . '/fields/' . $instance['field_name'] . '/edit';
// Store new field information for any additional submit handlers.
$form_state['fields_added']['_add_existing_field'] = $instance['field_name'];
}
catch (Exception $e) {
drupal_set_message(t('There was a problem creating field instance %label: @message.', array('%label' => $instance['label'], '@message' => $e->getMessage())));
}
}
}
if ($destinations) {
Dries Buytaert
committed
$destination = drupal_get_destination();
$destinations[] = $destination['destination'];
Dries Buytaert
committed
unset($_GET['destination']);
Angie Byron
committed
$form_state['redirect'] = field_ui_get_destinations($destinations);
}
else {
drupal_set_message(t('Your settings have been saved.'));
}
Angie Byron
committed
}
/**
Dries Buytaert
committed
* Menu callback; presents field display settings for a given view mode.
Angie Byron
committed
*/
Dries Buytaert
committed
function field_ui_display_overview_form($form, &$form_state, $entity_type, $bundle, $view_mode) {
$bundle = field_extract_bundle($entity_type, $bundle);
Angie Byron
committed
field_ui_inactive_message($entity_type, $bundle);
$admin_path = _field_ui_bundle_admin_path($entity_type, $bundle);
Angie Byron
committed
// Gather type information.
$instances = field_info_instances($entity_type, $bundle);
Angie Byron
committed
$field_types = field_info_field_types();
Dries Buytaert
committed
$extra_fields = field_info_extra_fields($entity_type, $bundle, 'display');
Angie Byron
committed
$form_state += array(
'formatter_settings_edit' => NULL,
);
$form += array(
'#entity_type' => $entity_type,
Angie Byron
committed
'#bundle' => $bundle,
Dries Buytaert
committed
'#view_mode' => $view_mode,
Angie Byron
committed
'#fields' => array_keys($instances),
Dries Buytaert
committed
'#extra' => array_keys($extra_fields),
Angie Byron
committed
);
Dries Buytaert
committed
if (empty($instances) && empty($extra_fields)) {
Angie Byron
committed
drupal_set_message(t('There are no fields yet added. You can add new fields on the <a href="@link">Manage fields</a> page.', array('@link' => url($admin_path . '/fields'))), 'warning');
return $form;
}
Dries Buytaert
committed
$table = array(
'#type' => 'field_ui_table',
Dries Buytaert
committed
'#tree' => TRUE,
'#header' => array(
t('Field'),
t('Weight'),
t('Parent'),
t('Label'),
array('data' => t('Format'), 'colspan' => 3),
),
'#regions' => array(
'visible' => array('message' => t('No field is displayed.')),
'hidden' => array('title' => t('Hidden'), 'message' => t('No field is hidden.')),
),
Dries Buytaert
committed
'#parent_options' => array(),
'#attributes' => array(
'class' => array('field-ui-overview'),
'id' => 'field-display-overview',
),
// Add Ajax wrapper.
'#prefix' => '<div id="field-display-overview-wrapper">',
'#suffix' => '</div>',
Dries Buytaert
committed
);
$field_label_options = array(
Angie Byron
committed
'above' => t('Above'),
'inline' => t('Inline'),
'hidden' => t('<Hidden>'),
);
Dries Buytaert
committed
$extra_visibility_options = array(
'visible' => t('Visible'),
'hidden' => t('Hidden'),
);
// Field rows.
Angie Byron
committed
foreach ($instances as $name => $instance) {
$field = field_info_field($instance['field_name']);
Dries Buytaert
committed
$display = $instance['display'][$view_mode];
$table[$name] = array(
'#attributes' => array('class' => array('draggable', 'tabledrag-leaf')),
'#row_type' => 'field',
'#region_callback' => 'field_ui_display_overview_row_region',
'#js_settings' => array(
'rowHandler' => 'field',
'defaultFormatter' => $field_types[$field['type']]['default_formatter'],
),
'human_name' => array(
'#markup' => check_plain($instance['label']),
),
'weight' => array(
'#type' => 'textfield',
Dries Buytaert
committed
'#title' => t('Weight for @title', array('@title' => $instance['label'])),
'#title_display' => 'invisible',
'#default_value' => $display['weight'],
'#size' => 3,
'#attributes' => array('class' => array('field-weight')),
),
'parent_wrapper' => array(
'parent' => array(
'#type' => 'select',
Dries Buytaert
committed
'#title' => t('Label display for @title', array('@title' => $instance['label'])),
'#title_display' => 'invisible',
'#options' => $table['#parent_options'],
Angie Byron
committed
'#empty_value' => '',
'#attributes' => array('class' => array('field-parent')),
'#parents' => array('fields', $name, 'parent'),
),
'hidden_name' => array(
'#type' => 'hidden',
'#default_value' => $name,
'#attributes' => array('class' => array('field-name')),
),
),
'label' => array(
'#type' => 'select',
Dries Buytaert
committed
'#title' => t('Label display for @title', array('@title' => $instance['label'])),
'#title_display' => 'invisible',
'#options' => $field_label_options,
'#default_value' => $display['label'],
),
Dries Buytaert
committed
);
Angie Byron
committed
$formatter_options = field_ui_formatter_options($field['type']);
$formatter_options['hidden'] = t('<Hidden>');
$table[$name]['format'] = array(
'type' => array(
'#type' => 'select',
Dries Buytaert
committed
'#title' => t('Formatter for @title', array('@title' => $instance['label'])),
'#title_display' => 'invisible',
'#options' => $formatter_options,
'#default_value' => $display['type'],
'#parents' => array('fields', $name, 'type'),
'#attributes' => array('class' => array('field-formatter-type')),
),
'settings_edit_form' => array(),
Dries Buytaert
committed
);
// Formatter settings.
// Check the currently selected formatter, and merge persisted values for
// formatter settings.
if (isset($form_state['values']['fields'][$name]['type'])) {
$formatter_type = $form_state['values']['fields'][$name]['type'];
}
else {
$formatter_type = $display['type'];
}
if (isset($form_state['formatter_settings'][$name])) {
$settings = $form_state['formatter_settings'][$name];
}
else {
$settings = $display['settings'];
}
$settings += field_info_formatter_settings($formatter_type);
$instance['display'][$view_mode]['type'] = $formatter_type;
$formatter = field_info_formatter_types($formatter_type);
$instance['display'][$view_mode]['module'] = $formatter['module'];
$instance['display'][$view_mode]['settings'] = $settings;
// Base button element for the various formatter settings actions.
$base_button = array(
'#submit' => array('field_ui_display_overview_multistep_submit'),
'#ajax' => array(
'callback' => 'field_ui_display_overview_multistep_js',
'wrapper' => 'field-display-overview-wrapper',
'effect' => 'fade',
),
'#field_name' => $name,