Projet

Général

Profil

Paste
Télécharger (20 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / media / includes / media.fields.inc @ ca0757b9

1
<?php
2

    
3
/**
4
 * @file
5
 * Provide the media selector widget and media field formatters to the Fields
6
 * API.
7
 */
8

    
9
/**
10
 * Implements hook_field_widget_info().
11
 */
12
function media_field_widget_info() {
13
  return array(
14
    'media_generic' => array(
15
      'label' => t('Media browser'),
16
      'field types' => array('file', 'image'),
17
      'settings' => array(
18
        'allowed_types' => array('image'),
19
        'browser_plugins' => array(),
20
        'allowed_schemes' => array('public', 'private'),
21
      ),
22
      'behaviors' => array(
23
        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
24
        'default value' => FIELD_BEHAVIOR_NONE,
25
      ),
26
    ),
27
  );
28
}
29

    
30
/**
31
 * Implements hook_field_widget_settings_form().
32
 */
33
function media_field_widget_settings_form($field, $instance) {
34
  $widget = $instance['widget'];
35
  $settings = $widget['settings'];
36

    
37
  $plugins = media_get_browser_plugin_info();
38
  $options = array();
39
  foreach ($plugins as $key => $plugin) {
40
    $options[$key] = check_plain($plugin['title']);
41
  }
42

    
43
  $form['browser_plugins'] = array(
44
    '#type' => 'checkboxes',
45
    '#title' => t('Enabled browser plugins'),
46
    '#options' => $options,
47
    '#default_value' => $settings['browser_plugins'],
48
    '#description' => t('Media browser plugins which are allowed for this field. If no plugins are selected, they will all be available.'),
49
  );
50

    
51
  $form['allowed_types'] = array(
52
    '#type' => 'checkboxes',
53
    '#title' => t('Allowed file types'),
54
    '#options' => file_entity_type_get_names(),
55
    '#default_value' => $settings['allowed_types'],
56
    '#description' => t('File types which are allowed for this field. If no file types are selected, they will all be available.'),
57
  );
58

    
59
  $visible_steam_wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_VISIBLE);
60
  $options = array();
61
  foreach ($visible_steam_wrappers as $scheme => $information) {
62
    $options[$scheme] = check_plain($information['name']);
63
  }
64

    
65
  $form['allowed_schemes'] = array(
66
    '#type' => 'checkboxes',
67
    '#title' => t('Allowed URI schemes'),
68
    '#options' => $options,
69
    '#default_value' => $settings['allowed_schemes'],
70
    '#description' => t('URI schemes which are allowed for this field. If no schemes are selected, they will all be available.'),
71
  );
72

    
73
  return $form;
74
}
75

    
76
/**
77
 * Implements hook_field_widget_form().
78
 */
79
function media_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
80

    
81
  // Add display_field setting to field because media_field_widget_form() assumes it is set.
82
  if (!isset($field['settings']['display_field'])) {
83
    $field['settings']['display_field'] = 0;
84
  }
85

    
86
  $defaults = array(
87
    'fid' => 0,
88
    'display' => !empty($field['settings']['display_default']),
89
    'description' => '',
90
  );
91

    
92
  // Load the items for form rebuilds from the field state as they might not be
93
  // in $form_state['values'] because of validation limitations. Also, they are
94
  // only passed in as $items when editing existing entities.
95
  $field_state = field_form_get_state($element['#field_parents'], $field['field_name'], $langcode, $form_state);
96
  if (isset($field_state['items'])) {
97
    $items = $field_state['items'];
98
  }
99

    
100
  $field_settings = $instance['settings'];
101
  $widget_settings = $instance['widget']['settings'];
102

    
103
  // Essentially we use the media type, extended with some enhancements.
104
  $element_info = element_info('media');
105
  $element += array(
106
    '#type' => 'media',
107
    '#value_callback' => 'media_field_widget_value',
108
    '#process' => array_merge($element_info['#process'], array('media_field_widget_process')),
109
    '#media_options' => array(
110
      'global' => array(
111
        'types' => array_filter($widget_settings['allowed_types']),
112
        'enabledPlugins' => array_filter($instance['widget']['settings']['browser_plugins']),
113
        'schemes' => array_filter($widget_settings['allowed_schemes']),
114
        'file_directory' => isset($field_settings['file_directory']) ? $field_settings['file_directory'] : '',
115
        'file_extensions' => isset($field_settings['file_extensions']) ? $field_settings['file_extensions'] : variable_get('file_entity_default_allowed_extensions', 'jpg jpeg gif png txt doc docx xls xlsx pdf ppt pptx pps ppsx odt ods odp mp3 mov mp4 m4a m4v mpeg avi ogg oga ogv weba webp webm'),
116
        'max_filesize' => isset($field_settings['max_filesize']) ? $field_settings['max_filesize'] : 0,
117
        'uri_scheme' => !empty($field['settings']['uri_scheme']) ? $field['settings']['uri_scheme'] : file_default_scheme(),
118
      ),
119
    ),
120
    // Allows this field to return an array instead of a single value.
121
    '#extended' => TRUE,
122
  );
123

    
124
  // Add image field specific validators.
125
  if ($field['type'] == 'image') {
126
    if ($field_settings['min_resolution'] || $field_settings['max_resolution']) {
127
      $element['#media_options']['global']['min_resolution'] = $field_settings['min_resolution'];
128
      $element['#media_options']['global']['max_resolution'] = $field_settings['max_resolution'];
129
    }
130
  }
131

    
132
  if ($field['cardinality'] == 1) {
133
    // Set the default value.
134
    $element['#default_value'] = !empty($items) ? $items[0] : $defaults;
135
    // If there's only one field, return it as delta 0.
136
    if (empty($element['#default_value']['fid'])) {
137
      $element['#description'] = theme('media_upload_help', array('description' => $element['#description']));
138
    }
139
    $elements = array($element);
140
  }
141
  else {
142
    // If there are multiple values, add an element for each existing one.
143
    foreach ($items as $item) {
144
      $elements[$delta] = $element;
145
      $elements[$delta]['#default_value'] = $item;
146
      $elements[$delta]['#weight'] = $delta;
147
      $delta++;
148
    }
149
    // And then add one more empty row for new uploads except when this is a
150
    // programmed form as it is not necessary.
151
    if (($field['cardinality'] == FIELD_CARDINALITY_UNLIMITED || $delta < $field['cardinality']) && empty($form_state['programmed'])) {
152
      $elements[$delta] = $element;
153
      $elements[$delta]['#default_value'] = $defaults;
154
      $elements[$delta]['#weight'] = $delta;
155
      $elements[$delta]['#required'] = ($element['#required'] && $delta == 0);
156
    }
157
    // The group of elements all-together need some extra functionality
158
    // after building up the full list (like draggable table rows).
159
    $elements['#file_upload_delta'] = $delta;
160
    $elements['#theme'] = 'media_widget_multiple';
161
    $elements['#theme_wrappers'] = array('fieldset');
162
    $elements['#process'] = array('media_field_widget_process_multiple');
163
    $elements['#title'] = $element['#title'];
164
    $elements['#description'] = $element['#description'];
165
    $elements['#field_name'] = $element['#field_name'];
166
    $elements['#language'] = $element['#language'];
167
    $elements['#display_field'] = $field['settings']['display_field'];
168

    
169
    // Add some properties that will eventually be added to the media upload
170
    // field. These are added here so that they may be referenced easily through
171
    // a hook_form_alter().
172
    $elements['#file_upload_title'] = t('Attach media');
173
    $elements['#file_upload_description'] = theme('media_upload_help', array('description' => ''));
174
  }
175

    
176
  return $elements;
177
}
178

    
179
/**
180
 * The #value_callback for the media field element.
181
 */
182
function media_field_widget_value($element, $input = FALSE, $form_state) {
183
  if ($input) {
184
    // Checkboxes lose their value when empty.
185
    // If the display field is present make sure its unchecked value is saved.
186
    $field = field_widget_field($element, $form_state);
187
    if (empty($input['display'])) {
188
      $input['display'] = $field['settings']['display_field'] ? 0 : 1;
189
    }
190
  }
191

    
192
  // We depend on the media element to handle uploads.
193
  $return = media_file_value($element, $input, $form_state);
194

    
195
  // Ensure that all the required properties are returned even if empty.
196
  $return += array(
197
    'fid' => 0,
198
    'display' => 1,
199
    'description' => '',
200
  );
201

    
202
  return $return;
203
}
204

    
205
/**
206
 * An element #process callback for the media field type.
207
 *
208
 * Expands the media type to include the description and display fields.
209
 */
210
function media_field_widget_process($element, &$form_state, $form) {
211
  $item = $element['#value'];
212
  $item['fid'] = $element['fid']['#value'];
213

    
214
  $field = field_widget_field($element, $form_state);
215
  $instance = field_widget_instance($element, $form_state);
216
  $settings = $instance['widget']['settings'];
217

    
218
  $element['#theme'] = 'media_widget';
219

    
220
  // Add the display field if enabled.
221
  if (!empty($field['settings']['display_field']) && $item['fid']) {
222
    $element['display'] = array(
223
      '#type' => empty($item['fid']) ? 'hidden' : 'checkbox',
224
      '#title' => t('Include file in display'),
225
      '#value' => isset($item['display']) ? $item['display'] : $field['settings']['display_default'],
226
      '#attributes' => array('class' => array('file-display')),
227
    );
228
  }
229
  else {
230
    $element['display'] = array(
231
      '#type' => 'hidden',
232
      '#value' => '1',
233
    );
234
  }
235

    
236
  // Add the description field if enabled.
237
  if (!empty($instance['settings']['description_field']) && $item['fid']) {
238
    $element['description'] = array(
239
      '#type' => variable_get('file_description_type', 'textfield'),
240
      '#title' => t('Description'),
241
      '#value' => isset($item['description']) ? $item['description'] : '',
242
      '#maxlength' => variable_get('file_description_length', 128),
243
      '#description' => t('The description may be used as the label of the link to the file.'),
244
    );
245
  }
246

    
247
  // Adjust the Ajax settings so that on upload and remove of any individual
248
  // file, the entire group of file fields is updated together.
249
  if ($field['cardinality'] != 1) {
250
    $parents = array_slice($element['#array_parents'], 0, -1);
251
    $new_path = 'media/ajax/' . implode('/', $parents) . '/' . $form['form_build_id']['#value'];
252
    $field_element = drupal_array_get_nested_value($form, $parents);
253
    $new_wrapper = $field_element['#id'] . '-ajax-wrapper';
254
    foreach (element_children($element) as $key) {
255
      if (isset($element[$key]['#ajax'])) {
256
        $element[$key]['#ajax']['path'] = $new_path;
257
        $element[$key]['#ajax']['wrapper'] = $new_wrapper;
258
      }
259
    }
260
    unset($element['#prefix'], $element['#suffix']);
261
  }
262

    
263
  // Add another submit handler to the upload and remove buttons, to implement
264
  // functionality needed by the field widget. This submit handler, along with
265
  // the rebuild logic in media_field_widget_form() requires the entire field,
266
  // not just the individual item, to be valid.
267
  foreach (array('attach_button', 'remove_button') as $key) {
268
    $element[$key]['#submit'][] = 'media_field_widget_submit';
269
    $element[$key]['#limit_validation_errors'] = array(array_slice($element['#parents'], 0, -1));
270
  }
271

    
272
  return $element;
273
}
274

    
275
/**
276
 * An element #process callback for a group of media fields.
277
 *
278
 * Adds the weight field to each row so it can be ordered and adds a new Ajax
279
 * wrapper around the entire group so it can be replaced all at once.
280
 */
281
function media_field_widget_process_multiple($element, &$form_state, $form) {
282
  $element_children = element_children($element, TRUE);
283
  $count = count($element_children);
284

    
285
  foreach ($element_children as $delta => $key) {
286
    if ($key != $element['#file_upload_delta']) {
287
      $description = _media_field_get_description_from_element($element[$key]);
288
      $element[$key]['_weight'] = array(
289
        '#type' => 'weight',
290
        '#title' => $description ? t('Weight for @title', array('@title' => $description)) : t('Weight for new file'),
291
        '#title_display' => 'invisible',
292
        '#delta' => $count,
293
        '#default_value' => $delta,
294
      );
295
    }
296
    else {
297
      // The title needs to be assigned to the attach field so that validation
298
      // errors include the correct widget label.
299
      $element[$key]['#title'] = $element['#title'];
300
      $element[$key]['_weight'] = array(
301
        '#type' => 'hidden',
302
        '#default_value' => $delta,
303
      );
304
    }
305
  }
306

    
307
  // Add a new wrapper around all the elements for Ajax replacement.
308
  $element['#prefix'] = '<div id="' . $element['#id'] . '-ajax-wrapper">';
309
  $element['#suffix'] = '</div>';
310

    
311
  return $element;
312
}
313

    
314
/**
315
 * Retrieves the file description from a media field element.
316
 *
317
 * This helper function is used by media_field_widget_process_multiple().
318
 *
319
 * @param $element
320
 *   The element being processed.
321
 *
322
 * @return
323
 *   A description of the file suitable for use in the administrative interface.
324
 */
325
function _media_field_get_description_from_element($element) {
326
  // Use the actual file description, if it's available.
327
  if (!empty($element['#default_value']['description'])) {
328
    return $element['#default_value']['description'];
329
  }
330
  // Otherwise, fall back to the filename.
331
  if (!empty($element['#default_value']['filename'])) {
332
    return $element['#default_value']['filename'];
333
  }
334
  // This is probably a newly uploaded file; no description is available.
335
  return FALSE;
336
}
337

    
338
/**
339
 * Form submission handler for attach/remove button of media_field_widget_form().
340
 *
341
 * This runs in addition to and after media_field_widget_submit().
342
 *
343
 * @see media_field_widget_submit()
344
 * @see media_field_widget_form()
345
 * @see media_field_widget_process()
346
 */
347
function media_field_widget_submit($form, &$form_state) {
348
  // During the form rebuild, media_field_widget_form() will create field item
349
  // widget elements using re-indexed deltas, so clear out $form_state['input']
350
  // to avoid a mismatch between old and new deltas. The rebuilt elements will
351
  // have #default_value set appropriately for the current state of the field,
352
  // so nothing is lost in doing this.
353
  $parents = array_slice($form_state['triggering_element']['#parents'], 0, -2);
354
  drupal_array_set_nested_value($form_state['input'], $parents, NULL);
355

    
356
  $button = $form_state['triggering_element'];
357

    
358
  // Go one level up in the form, to the widgets container.
359
  $element = drupal_array_get_nested_value($form, array_slice($button['#array_parents'], 0, -1));
360
  $field_name = $element['#field_name'];
361
  $langcode = $element['#language'];
362
  $parents = $element['#field_parents'];
363

    
364
  $submitted_values = drupal_array_get_nested_value($form_state['values'], array_slice($button['#parents'], 0, -2));
365
  foreach ($submitted_values as $delta => $submitted_value) {
366
    if (!$submitted_value['fid']) {
367
      unset($submitted_values[$delta]);
368
    }
369
  }
370

    
371
  // Re-index deltas after removing empty items.
372
  $submitted_values = array_values($submitted_values);
373

    
374
  // Update form_state values.
375
  drupal_array_set_nested_value($form_state['values'], array_slice($button['#parents'], 0, -2), $submitted_values);
376

    
377
  // Update items.
378
  $field_state = field_form_get_state($parents, $field_name, $langcode, $form_state);
379
  $field_state['items'] = $submitted_values;
380
  field_form_set_state($parents, $field_name, $langcode, $form_state, $field_state);
381
}
382

    
383
/**
384
 * Returns HTML for an individual media widget.
385
 *
386
 * @param $variables
387
 *   An associative array containing:
388
 *   - element: A render element representing the widget.
389
 *
390
 * @ingroup themeable
391
 */
392
function theme_media_widget($variables) {
393
  $element = $variables['element'];
394
  $output = '';
395

    
396
  // The "form-media" class is required for proper Ajax functionality.
397
  $output .= '<div id="' . $element['#id'] . '" class="media-widget form-media clearfix">';
398
  $output .= drupal_render_children($element);
399
  $output .= '</div>';
400

    
401
  return $output;
402
}
403

    
404
/**
405
 * Returns HTML for a group of media widgets.
406
 *
407
 * @param $variables
408
 *   An associative array containing:
409
 *   - element: A render element representing the widgets.
410
 *
411
 * @ingroup themeable
412
 */
413
function theme_media_widget_multiple($variables) {
414
  $element = $variables['element'];
415

    
416
  // Special ID and classes for draggable tables.
417
  $weight_class = $element['#id'] . '-weight';
418
  $table_id = $element['#id'] . '-table';
419

    
420
  // Build up a table of applicable fields.
421
  $headers = array();
422
  $headers[] = t('File information');
423
  if ($element['#display_field']) {
424
    $headers[] = array(
425
      'data' => t('Display'),
426
      'class' => array('checkbox'),
427
    );
428
  }
429
  $headers[] = t('Weight');
430
  $headers[] = t('Operations');
431

    
432
  // Get our list of widgets in order (needed when the form comes back after
433
  // preview or failed validation).
434
  $widgets = array();
435
  foreach (element_children($element) as $key) {
436
    $widgets[] = &$element[$key];
437
  }
438
  usort($widgets, '_field_sort_items_value_helper');
439

    
440
  $rows = array();
441
  foreach ($widgets as $key => &$widget) {
442
    // Save the uploading row for last.
443
    if ($widget['#file'] == FALSE) {
444
      $widget['#title'] = $element['#file_upload_title'];
445
      $widget['#description'] = $element['#file_upload_description'];
446
      continue;
447
    }
448

    
449
    // Delay rendering of the buttons, so that they can be rendered later in the
450
    // "operations" column.
451
    $operations_elements = array();
452
    foreach (element_children($widget) as $sub_key) {
453
      if (isset($widget[$sub_key]['#type']) && $widget[$sub_key]['#type'] == 'submit') {
454
        hide($widget[$sub_key]);
455
        $operations_elements[] = &$widget[$sub_key];
456
      }
457
    }
458

    
459
    // Delay rendering of the "Display" option and the weight selector, so that
460
    // each can be rendered later in its own column.
461
    if ($element['#display_field']) {
462
      hide($widget['display']);
463
    }
464
    hide($widget['_weight']);
465

    
466
    // Render everything else together in a column, without the normal wrappers.
467
    $widget['#theme_wrappers'] = array();
468
    $information = drupal_render($widget);
469

    
470
    // Render the previously hidden elements, using render() instead of
471
    // drupal_render(), to undo the earlier hide().
472
    $operations = '';
473
    foreach ($operations_elements as $operation_element) {
474
      $operations .= render($operation_element);
475
    }
476
    $display = '';
477
    if ($element['#display_field']) {
478
      unset($widget['display']['#title']);
479
      $display = array(
480
        'data' => render($widget['display']),
481
        'class' => array('checkbox'),
482
      );
483
    }
484
    $widget['_weight']['#attributes']['class'] = array($weight_class);
485
    $weight = render($widget['_weight']);
486

    
487
    // Arrange the row with all of the rendered columns.
488
    $row = array();
489
    $row[] = $information;
490
    if ($element['#display_field']) {
491
      $row[] = $display;
492
    }
493
    $row[] = $weight;
494
    $row[] = $operations;
495
    $rows[] = array(
496
      'data' => $row,
497
      'class' => isset($widget['#attributes']['class']) ? array_merge($widget['#attributes']['class'], array('draggable')) : array('draggable'),
498
    );
499
  }
500

    
501
  drupal_add_tabledrag($table_id, 'order', 'sibling', $weight_class);
502

    
503
  $output = '';
504
  $output = empty($rows) ? '' : theme('table', array('header' => $headers, 'rows' => $rows, 'attributes' => array('id' => $table_id)));
505
  $output .= drupal_render_children($element);
506
  return $output;
507
}
508

    
509
/**
510
 * Returns HTML for help text.
511
 *
512
 * @param $variables
513
 *   An associative array containing:
514
 *   - description: The normal description for this field, specified by the
515
 *     user.
516
 *
517
 * @ingroup themeable
518
 */
519
function theme_media_upload_help($variables) {
520
  $description = $variables['description'];
521

    
522
  $descriptions = array();
523

    
524
  if (strlen($description)) {
525
    $descriptions[] = $description;
526
  }
527

    
528
  return implode('<br />', $descriptions);
529
}
530

    
531
/**
532
 * Implements hook_field_formatter_info().
533
 *
534
 * Provides legacy support for the "Large filetype icon" file field formatter.
535
 * This was originally used when media entities contained file fields. The
536
 * current file entity architecture no longer needs this, but people may
537
 * have used this formatter for other file fields on their website.
538
 *
539
 * @todo Some day, remove this.
540
 */
541
function media_field_formatter_info() {
542
  $formatters = array(
543
    'media_large_icon' => array(
544
      'label' => t('Large filetype icon'),
545
      'field types' => array('file'),
546
    ),
547
  );
548
  return $formatters;
549
}
550

    
551
/**
552
 * Implements hook_field_formatter_view().
553
 *
554
 * Legacy support for the "Large filetype icon" file field formatter.
555
 * @see media_field_formatter_info()
556
 */
557
function media_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
558
  $element = array();
559

    
560
  if ($display['type'] == 'media_large_icon') {
561
    // Use the media_thumbnail image style so that the output in media browser
562
    // is consistent.
563
    foreach ($items as $delta => $item) {
564
      $element[$delta] = array(
565
        '#theme' => 'media_formatter_large_icon',
566
        '#file' => (object) $item,
567
      );
568
    }
569
  }
570

    
571
  return $element;
572
}