Projet

Général

Profil

Paste
Télécharger (18,8 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / ds / modules / ds_ui / includes / ds.fields.inc @ ba3b3627

1
<?php
2

    
3
/**
4
 * @file
5
 * Administrative functions for managing custom fields for every entity.
6
 */
7

    
8
/**
9
 * Shows the list of custom fields.
10
 */
11
function ds_custom_fields_list() {
12
  $output = '';
13

    
14
  ctools_include('export');
15
  $custom_fields = ctools_export_crud_load_all('ds_fields');
16
  if (!empty($custom_fields)) {
17

    
18
    $rows = array();
19
    foreach ($custom_fields as $field_key => $field_value) {
20
      $row = array();
21
      $row[] = check_plain($field_value->label);
22
      $row[] = ds_field_human_name($field_value->field_type);
23
      $row[] = $field_key;
24
      $row[] = ucwords(str_replace('_', ' ', implode(', ', $field_value->entities)));
25
      $operations = l(t('Edit'), 'admin/structure/ds/fields/manage/' . $field_key, array('alias' => TRUE));
26

    
27
      if ($field_value->export_type == 3) {
28
        $operations .= ' - ' . l(t('Revert'), 'admin/structure/ds/fields/revert/' . $field_key, array('alias' => TRUE));
29
      }
30
      elseif ($field_value->export_type == 1) {
31
        $operations .= ' - ' . l(t('Delete'), 'admin/structure/ds/fields/delete/' . $field_key, array('alias' => TRUE));
32
      }
33
      $row[] = $operations;
34
      $rows[] = $row;
35
    }
36

    
37
    $table = array(
38
      'header' => array(
39
        'Label',
40
        'Type',
41
        'Machine name',
42
        'Entities',
43
        'Operations',
44
      ),
45
      'rows' => $rows,
46
    );
47

    
48
    $output = theme('table', $table);
49
  }
50
  else {
51
    $output = t('No custom fields have been defined.');
52
  }
53

    
54
  return $output;
55
}
56

    
57
/**
58
 * Return the human name of a field.
59
 *
60
 * @return $human_name
61
 *   The human name of a field.
62
 */
63
function ds_field_human_name($type) {
64

    
65
  switch ($type) {
66
    case DS_FIELD_TYPE_CODE:
67
      return t('Code field');
68
    case DS_FIELD_TYPE_BLOCK:
69
      return t('Block field');
70
    case DS_FIELD_TYPE_CTOOLS:
71
      return t('Dynamic field');
72
    case DS_FIELD_TYPE_PREPROCESS:
73
      return t('Preprocess field');
74
  }
75

    
76
  // Fallback
77
  return t('Unknown');
78
}
79

    
80
/**
81
 * Manage a field. This will redirect to the exact form.
82
 */
83
function ds_custom_manage($field_key = '') {
84
  $redirect = '';
85
  ctools_include('export');
86
  $custom_fields = ctools_export_crud_load_all('ds_fields');
87
  if (isset($custom_fields[$field_key])) {
88
    $field = $custom_fields[$field_key];
89
    switch ($field->field_type) {
90
      case DS_FIELD_TYPE_CODE:
91
        $redirect = 'admin/structure/ds/fields/manage_custom/' . $field_key;
92
        break;
93

    
94
      case DS_FIELD_TYPE_BLOCK:
95
        $redirect = 'admin/structure/ds/fields/manage_block/' . $field_key;
96
        break;
97

    
98
      case DS_FIELD_TYPE_CTOOLS:
99
        $redirect = 'admin/structure/ds/fields/manage_ctools/' . $field_key;
100
        break;
101

    
102
      case DS_FIELD_TYPE_PREPROCESS:
103
        $redirect = 'admin/structure/ds/fields/manage_preprocess/' . $field_key;
104
        break;
105

    
106
      default:
107
        drupal_set_message(t('Field not found'));
108
        $redirect = 'admin/structure/ds/fields';
109
        break;
110
    }
111
  }
112

    
113
  drupal_goto($redirect);
114
}
115

    
116
/**
117
 * Shared form for all fields.
118
 */
119
function ds_shared_form(&$form, $field) {
120
  ctools_include('export');
121
  $custom_fields = ctools_export_crud_load_all('ds_fields');
122
  if (isset($custom_fields[$field])) {
123
    $field = $custom_fields[$field];
124
    if (!isset($field->ui_limit)) {
125
      $field->ui_limit = '';
126
    }
127
  }
128
  else {
129
    $field = new stdClass;
130
    $field->label = '';
131
    $field->field = '';
132
    $field->ui_limit = '';
133
    $field->entities = array();
134
    $field->properties = array();
135
  }
136

    
137
  $form['name'] = array(
138
    '#title' => t('Label'),
139
    '#type' => 'textfield',
140
    '#default_value' => $field->label,
141
    '#description' => t('The human-readable label of the field.'),
142
    '#maxlength' => 128,
143
    '#required' => TRUE,
144
    '#size' => 30,
145
  );
146

    
147
  $form['field'] = array(
148
    '#type' => 'machine_name',
149
    '#default_value' => $field->field,
150
    '#maxlength' => 32,
151
    '#description' => t('The machine-readable name of this field. This name must contain only lowercase letters and underscores. This name must be unique.'),
152
    '#disabled' => !empty($field->field),
153
    '#machine_name' => array(
154
      'exists' => 'ds_field_unique',
155
    ),
156
  );
157

    
158
  $entity_options = array();
159
  $entities = entity_get_info();
160
  foreach ($entities as $entity_type => $entity_info) {
161
    if ((isset($entity_info['fieldable']) && $entity_info['fieldable']) || $entity_type == 'ds_views') {
162
      $entity_options[$entity_type] = drupal_ucfirst(str_replace('_', ' ', $entity_type));
163
    }
164
  }
165
  $form['entities'] = array(
166
    '#title' => t('Entities'),
167
    '#description' => t('Select the entities for which this field will be made available.'),
168
    '#type' => 'checkboxes',
169
    '#required' => TRUE,
170
    '#options' => $entity_options,
171
    '#default_value' => $field->entities,
172
  );
173

    
174
  $form['ui_limit'] = array(
175
    '#title' => t('Limit field'),
176
    '#description' => t('Limit this field on field UI per bundles and/or view modes. The values are in the form of $bundle|$view_mode, where $view_mode may be either a view mode set to use custom settings, or \'default\'. You may use * to select all, e.g article|*, *|full or *|*. Enter one value per line.'),
177
    '#type' => 'textarea',
178
    '#default_value' => $field->ui_limit,
179
    '#element_validate' => array('ds_ui_limit_validate'),
180
  );
181

    
182
  $form['submit'] = array(
183
    '#type' => 'submit',
184
    '#value' => t('Save'),
185
    '#weight' => 100,
186
  );
187

    
188
  // Validate & submit are also the same.
189
  $form['#validate'][] = 'ds_shared_form_validate';
190
  $form['#submit'][] = 'ds_shared_form_submit';
191

    
192
  return $field;
193
}
194

    
195
/**
196
 * Element validation function for ui limit field.
197
 */
198
function ds_ui_limit_validate($element, &$form_state, $form) {
199
  // Get all enabled entity types.
200
  $entity_types = array_filter($form_state['values']['entities']);
201

    
202
  if (!empty($element['#value'])) {
203
    $ui_limit = $element['#value'];
204

    
205
    $lines = explode("\n", str_replace("\r", "\n", $ui_limit));
206
    // Ensure that all strings are trimmed and filter out empty lines.
207
    $lines = array_filter(array_map('trim', $lines));
208

    
209
    $error = FALSE;
210
    foreach ($lines as $line) {
211
      // Each line should hold a pipe character to seperate bundle and view_mode.
212
      if (strpos($line, '|') === FALSE) {
213
        $error = TRUE;
214
        continue;
215
      }
216

    
217
      list($bundle, $view_mode) = explode('|', $line);
218

    
219
      if (empty($bundle) || empty($view_mode) || !_ds_check_existing_ui_limit($entity_types, $bundle, $view_mode)) {
220
        $error = TRUE;
221
      }
222
    }
223
    if ($error) {
224
      form_error($element, t('The values are in the form of $bundle|$view_mode, where $view_mode may be either a view mode set to use custom settings, or \'default\'.'));
225
    }
226

    
227
    // Set trimmed and validated entry back as value.
228
    form_set_value($element, implode("\n", $lines), $form_state);
229
  }
230
}
231

    
232
/**
233
 * Helper function to check if bundle + view_mode combination exists.
234
 */
235
function _ds_check_existing_ui_limit($entity_types, $bundle, $view_mode) {
236
  $exists = FALSE;
237
  foreach ($entity_types as $entity_type) {
238
    $info = entity_get_info($entity_type);
239

    
240
    // Combine allowed bundles and entity specific ones.
241
    $bundle_allowed = array('*');
242
    $bundles = array_merge($bundle_allowed, array_keys($info['bundles']));
243

    
244
    // Combine allowed view_modes and entity specific ones.
245
    $view_mode_allowed = array('*', 'default');
246
    $view_modes = array_merge($view_mode_allowed, array_keys($info['view modes']));
247

    
248
    if (in_array($bundle, $bundles) &&
249
      in_array($view_mode, $view_modes)) {
250

    
251
      $exists = TRUE;
252
      break;
253
    }
254
  }
255
  if (!$exists) {
256
    drupal_set_message(t('Incorrect field limit combination: @bundle|@view_mode', array('@bundle' => $bundle, '@view_mode' => $view_mode)), 'error');
257
  }
258

    
259
  return $exists;
260
}
261

    
262
/**
263
 * Return whether a field machine name is unique.
264
 */
265
function ds_field_unique($name) {
266
  ctools_include('export');
267
  $custom_fields = ctools_export_crud_load_all('ds_fields');
268
  $value = strtr($name, array('-' => '_'));
269
  return isset($custom_fields[$value]) ? TRUE : FALSE;
270
}
271

    
272
/**
273
 * Shared field form validation.
274
 */
275
function ds_shared_form_validate($form, &$form_state) {
276
  $field = new stdClass;
277
  $field->properties = array();
278
  $field->field = $form_state['values']['field'];
279
  $field->label = $form_state['values']['name'];
280
  $field->ui_limit = $form_state['values']['ui_limit'];
281

    
282
  $entities = $form_state['values']['entities'];
283
  foreach ($entities as $key => $value) {
284
    if ($key !== $value) {
285
      unset($entities[$key]);
286
    }
287
  }
288
  $field->entities = $entities;
289
  $form_state['field'] = $field;
290
}
291

    
292
/**
293
 * Save any field.
294
 */
295
function ds_shared_form_submit($form, &$form_state) {
296
  $field = $form_state['field'];
297

    
298
  // Delete previous field configuration.
299
  db_delete('ds_fields')
300
    ->condition('field', $field->field)
301
    ->execute();
302

    
303
  // Save field and clear ds_fields.
304
  drupal_write_record('ds_fields', $field);
305
  cache_clear_all('ds_fields:', 'cache', TRUE);
306

    
307
  // Redirect.
308
  $form_state['redirect'] = 'admin/structure/ds/fields';
309
  drupal_set_message(t('The field %field has been saved', array('%field' => $field->label)));
310
}
311

    
312
/**
313
 * Manage a custom field.
314
 */
315
function ds_edit_custom_field_form($form, &$form_state, $custom_field = '') {
316
  drupal_set_title(empty($custom_field) ? t('Add a code field') : t('Edit code field'));
317

    
318
  $custom_field = ds_shared_form($form, $custom_field);
319

    
320
  $form['code'] = array(
321
    '#type' => 'text_format',
322
    '#title' => t('Field code'),
323
    '#default_value' => isset($custom_field->properties['code']['value']) ? $custom_field->properties['code']['value'] : '',
324
    '#format' => isset($custom_field->properties['code']['format']) ? $custom_field->properties['code']['format'] : 'ds_code',
325
    '#base_type' => 'textarea',
326
    '#required' => TRUE,
327
  );
328

    
329
  $form['use_token'] = array(
330
    '#type' => 'checkbox',
331
    '#title' => t('Token'),
332
    '#description' => t('Toggle this checkbox if you are using tokens in this field.'),
333
    '#default_value' => isset($custom_field->properties['use_token']) ? $custom_field->properties['use_token'] : '',
334
  );
335

    
336
  // Token support.
337
  if (module_exists('token')) {
338

    
339
    $form['tokens'] = array(
340
      '#title' => t('Tokens'),
341
      '#type' => 'container',
342
      '#states' => array(
343
        'invisible' => array(
344
          'input[name="use_token"]' => array('checked' => FALSE),
345
        ),
346
      ),
347
    );
348
    $form['tokens']['help'] = array(
349
      '#theme' => 'token_tree',
350
      '#token_types' => 'all',
351
      '#global_types' => FALSE,
352
      '#dialog' => TRUE,
353
    );
354
  }
355
  else {
356
    $form['use_token']['#description'] = t('Toggle this checkbox if you are using tokens in this field. If the token module is installed, you get a nice list of all tokens available in your site.');
357
  }
358

    
359
  $form['#validate'][] = 'ds_custom_field_form_validate';
360

    
361
  return $form;
362
}
363

    
364
/**
365
 * Custom field form validation.
366
 */
367
function ds_custom_field_form_validate($form, &$form_state) {
368
  $form_state['field']->field_type = DS_FIELD_TYPE_CODE;
369
  $form_state['field']->properties['code'] = $form_state['values']['code'];
370
  $form_state['field']->properties['use_token'] = $form_state['values']['use_token'];
371
}
372

    
373
/**
374
 * Manage a CTools field.
375
 */
376
function ds_edit_ctools_field_form($form, &$form_state, $ctools_field = '') {
377
  drupal_set_title(empty($ctools_field) ? t('Add a dynamic field') : t('Edit dynamic field'));
378

    
379
  $custom_field = ds_shared_form($form, $ctools_field);
380
  $form['info'] = array(
381
    '#markup' => t('The content of this field is configurable on the "Manage display" screens.'),
382
    '#weight' => -10,
383
  );
384
  $form['#validate'][] = 'ds_ctools_field_form_validate';
385
  return $form;
386
}
387

    
388
/**
389
 * CTools field form validation.
390
 */
391
function ds_ctools_field_form_validate($form, &$form_state) {
392
  $form_state['field']->field_type = DS_FIELD_TYPE_CTOOLS;
393
  $form_state['field']->properties['default'] = array();
394
  $form_state['field']->properties['settings'] = array('show_title' => array('type' => 'checkbox'), 'title_wrapper' => array('type' => 'textfield', 'description' => t('Eg: h1, h2, p')), 'ctools' => array('type' => 'ctools'));
395
}
396

    
397
/**
398
 * Manage a Preprocess field.
399
 */
400
function ds_edit_preprocess_field_form($form, &$form_state, $preprocess_field = '') {
401
  drupal_set_title(empty($preprocess_field) ? t('Add a preprocess field') : t('Edit preprocess field'));
402

    
403
  $custom_field = ds_shared_form($form, $preprocess_field);
404
  $form['info'] = array(
405
    '#markup' => t('The machine name of this field must reflect the key in the variables, e.g. "submitted". So in most cases, it is very likely you will have to manually edit the machine name as well, which can not be changed anymore after saving. Note that this field type works best on Nodes.'),
406
    '#weight' => -10,
407
  );
408
  $form['#validate'][] = 'ds_preprocess_field_form_validate';
409
  return $form;
410
}
411

    
412
/**
413
 * CTools field form validation.
414
 */
415
function ds_preprocess_field_form_validate($form, &$form_state) {
416
  $form_state['field']->field_type = DS_FIELD_TYPE_PREPROCESS;
417
}
418

    
419
/**
420
 * Manage a custom block.
421
 */
422
function ds_edit_block_field_form($form, &$form_state, $custom_block = '') {
423
  drupal_set_title(empty($custom_block) ? t('Add a block field') : t('Edit block field'));
424

    
425
  $custom_block = ds_shared_form($form, $custom_block);
426

    
427
  $blocks = array();
428
  foreach (module_implements('block_info') as $module) {
429
    $module_blocks = module_invoke($module, 'block_info');
430
    if ($module_blocks) {
431
      foreach ($module_blocks as $module_key => $info) {
432
        $blocks[drupal_ucfirst($module)][$module . '|' . $module_key] = $info['info'];
433
      }
434
    }
435
  }
436
  ksort($blocks);
437
  foreach($blocks as &$subarray) {
438
    asort($subarray);
439
  }
440

    
441
  $form['block_identity']['block'] = array(
442
    '#type' => 'select',
443
    '#options' => $blocks,
444
    '#title' => t('Block'),
445
    '#required' => TRUE,
446
    '#default_value' => isset($custom_block->properties['block']) ? $custom_block->properties['block'] : '',
447
  );
448
  $form['block_identity']['block_visibility'] = array(
449
    '#type' => 'checkbox',
450
    '#title' => t('Respect Block Visibility'),
451
    '#description' => t('Toggle this checkbox if you would like this field to respect the same visibility settings configured for the block.'),
452
    '#default_value' => isset($custom_block->properties['block_visibility']) ? $custom_block->properties['block_visibility'] : FALSE,
453
  );
454
  $form['block_identity']['block_render'] = array(
455
    '#type' => 'select',
456
    '#options' => array(
457
      DS_BLOCK_TEMPLATE => t('Default'),
458
      DS_BLOCK_TITLE_CONTENT => t('Show block title + content'),
459
      DS_BLOCK_CONTENT => t('Show only block content'),
460
    ),
461
    '#title' => t('Layout'),
462
    '#required' => TRUE,
463
    '#default_value' => isset($custom_block->properties['block_render']) ? $custom_block->properties['block_render'] : '',
464
  );
465

    
466
  $form['#validate'][] = 'ds_block_field_form_validate';
467

    
468
  return $form;
469
}
470

    
471
/**
472
 * Custom field form validation.
473
 */
474
function ds_block_field_form_validate($form, &$form_state) {
475
  $form_state['field']->field_type = DS_FIELD_TYPE_BLOCK;
476
  $form_state['field']->properties = array();
477
  $form_state['field']->properties['block'] = $form_state['values']['block'];
478
  $form_state['field']->properties['block_render'] = $form_state['values']['block_render'];
479
  $form_state['field']->properties['block_visibility'] = $form_state['values']['block_visibility'];
480
}
481

    
482
/**
483
 * Menu callback: Confirmation custom field delete form.
484
 */
485
function ds_delete_field_confirm($form, &$form_state, $field = '') {
486
  return ds_remove_fields_form($form, $form_state, $field, 'delete');
487
}
488

    
489
/**
490
 * Menu callback: Confirmation custom field delete form.
491
 */
492
function ds_revert_field_confirm($form, &$form_state, $field = '') {
493
  return ds_remove_fields_form($form, $form_state, $field, 'revert');
494
}
495

    
496
/**
497
 * Confirmation delete or revert form.
498
 */
499
function ds_remove_fields_form($form, &$form_state, $field = '', $action = 'delete') {
500
  ctools_include('export');
501
  $custom_fields = ctools_export_crud_load_all('ds_fields');
502
  if (isset($custom_fields[$field])) {
503
    $field = $custom_fields[$field];
504
    $form['#ds_field'] = $field;
505
    return confirm_form($form,
506
      t('Are you sure you want to ' . $action . ' %field?', array('%field' => $field->label)),
507
      'admin/structure/ds/fields',
508
      t('This action cannot be undone.'),
509
      t(drupal_ucfirst($action)),
510
      t('Cancel')
511
    );
512
  }
513
  else {
514
    drupal_set_message(t('Unknown field'));
515
    drupal_goto('admin/structure/ds/fields');
516
  }
517
}
518

    
519
/**
520
 * Submit callback: confirmed delete submit.
521
 */
522
function ds_delete_field_confirm_submit($form, &$form_state) {
523
  ds_remove_field_confirm_submit($form, $form_state, 'deleted');
524
}
525

    
526
/**
527
 * Submit callback: confirmed revert submit.
528
 */
529
function ds_revert_field_confirm_submit($form, &$form_state) {
530
  ds_remove_field_confirm_submit($form, $form_state, 'reverted');
531
}
532

    
533
/**
534
 * Confirmed field delete or revert submit callback.
535
 */
536
function ds_remove_field_confirm_submit($form, &$form_state, $action = 'deleted') {
537

    
538
  $field = $form['#ds_field'];
539

    
540
  // Remove field.
541
  db_delete('ds_fields')
542
    ->condition('field', $field->field)
543
    ->execute();
544

    
545
  // Clear cache.
546
  cache_clear_all('ds_fields:', 'cache', TRUE);
547

    
548
  // Redirect.
549
  $form_state['redirect'] = 'admin/structure/ds/fields';
550
  drupal_set_message(t('The field %field has been ' . $action, array('%field' => $field->label)));
551
}
552

    
553
/**
554
 * Handles ctools modal Add field
555
 *
556
 * @param $js
557
 *  Whether js is used or not.
558
 * @param $field_type
559
 *   The name of the field type.
560
 */
561
function ds_ajax_add_field($js, $field_type) {
562

    
563
  if (!$js) {
564
    // We don't support degrading this from js because we're not
565
    // using the server to remember the state of the table.
566
    drupal_goto("admin/structure/ds/fields/" . $field_type);
567
    return;
568
  }
569

    
570
  ctools_include('ajax');
571
  ctools_include('modal');
572

    
573
  switch ($field_type) {
574

    
575
    case "manage_ctools":
576
      $title = t('Add a dynamic field');
577
      $form_name = "ds_edit_ctools_field_form";
578
      break;
579

    
580
    case "manage_preprocess":
581
      $title = t('Add a preprocess field');
582
      $form_name = "ds_edit_preprocess_field_form";
583
      break;
584

    
585
    case "manage_block":
586
      $title = t('Add a block field');
587
      $form_name = "ds_edit_block_field_form";
588
      break;
589

    
590
    default:
591
      $title = t('Add a code field');
592
      $form_name = "ds_edit_custom_field_form";
593
      $field_type = 'manage_custom';
594
      break;
595
  }
596

    
597
  $form_state = array();
598
  $form_state['build_info']['args'] = array();
599
  $form_state += array(
600
    'title' => $title,
601
    'ajax' => TRUE,
602
    're_render' => FALSE,
603
  );
604

    
605
  $output = NULL;
606
  form_load_include($form_state, 'inc', 'ds_ui', 'includes/ds.fields');
607

    
608
  $output = ctools_modal_form_wrapper($form_name, $form_state);
609

    
610
  // Field is saved.
611
  if ($form_state['executed']) {
612

    
613
    $output = array();
614

    
615
    // Do not print messages on screen.
616
    if ($messages = theme('status_messages')) {
617
      $output[] = ajax_command_append('#console', $messages);
618
    }
619

    
620
    // Close the modal.
621
    $output[] = ctools_modal_command_dismiss();
622

    
623
    // Call our own javascript function which will trigger a refresh of the table.
624
    $output[] = ajax_command_invoke('#field-display-overview', 'dsRefreshDisplayTable');
625
  }
626

    
627
  drupal_add_http_header('Content-Type', 'application/json');
628
  print ajax_render($output);
629
  exit;
630
}