Projet

Général

Profil

Paste
Télécharger (21,4 ko) Statistiques
| Branche: | Révision:

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

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(
19
          'image' => 'image',
20
        ),
21
        'browser_plugins' => array(),
22
        'allowed_schemes' => array(
23
          'public' => 'public',
24
        ),
25
      ),
26
      'behaviors' => array(
27
        'multiple values' => FIELD_BEHAVIOR_CUSTOM,
28
        'default value' => FIELD_BEHAVIOR_NONE,
29
      ),
30
    ),
31
  );
32
}
33

    
34
/**
35
 * Implements hook_field_widget_settings_form().
36
 */
37
function media_field_widget_settings_form($field, $instance) {
38
  $widget = $instance['widget'];
39
  $settings = $widget['settings'];
40

    
41
  $plugins = media_get_browser_plugin_info();
42
  $options = array();
43
  foreach ($plugins as $key => $plugin) {
44
    $options[$key] = check_plain($plugin['title']);
45
  }
46

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

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

    
63
  $visible_steam_wrappers = file_get_stream_wrappers(STREAM_WRAPPERS_VISIBLE);
64
  $options = array();
65
  foreach ($visible_steam_wrappers as $scheme => $information) {
66
    $options[$scheme] = check_plain($information['name']);
67
  }
68

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

    
77
  return $form;
78
}
79

    
80
/**
81
 * Implements hook_field_widget_form().
82
 */
83
function media_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
84
  $defaults = array(
85
    'fid' => 0,
86
    'display' => !empty($field['settings']['display_default']),
87
    'description' => '',
88
  );
89

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

    
98
  $field_settings = $instance['settings'];
99
  $widget_settings = $instance['widget']['settings'];
100

    
101
  // Essentially we use the media type, extended with some enhancements.
102
  $element_info = element_info('media');
103
  $element += array(
104
    '#type' => 'media',
105
    '#value_callback' => 'media_field_widget_value',
106
    '#process' => array_merge($element_info['#process'], array('media_field_widget_process')),
107
    '#media_options' => array(
108
      'global' => array(
109
        'types' => array_filter($widget_settings['allowed_types']),
110
        'enabledPlugins' => array_filter($instance['widget']['settings']['browser_plugins']),
111
        'schemes' => array_filter($widget_settings['allowed_schemes']),
112
        'file_directory' => isset($field_settings['file_directory']) ? $field_settings['file_directory'] : '',
113
        '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'),
114
        'max_filesize' => isset($field_settings['max_filesize']) ? $field_settings['max_filesize'] : 0,
115
        'uri_scheme' => !empty($field['settings']['uri_scheme']) ? $field['settings']['uri_scheme'] : file_default_scheme(),
116
      ),
117
    ),
118
    // Allows this field to return an array instead of a single value.
119
    '#extended' => TRUE,
120
  );
121

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

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

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

    
174
  return $elements;
175
}
176

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

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

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

    
200
  return $return;
201
}
202

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

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

    
216
  $element['#theme'] = 'media_widget';
217

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

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

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

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

    
270
  return $element;
271
}
272

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

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

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

    
309
  return $element;
310
}
311

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

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

    
354
  $button = $form_state['triggering_element'];
355

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

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

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

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

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

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

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

    
399
  return $output;
400
}
401

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

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

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

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

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

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

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

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

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

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

    
499
  drupal_add_tabledrag($table_id, 'order', 'sibling', $weight_class);
500

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

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

    
520
  $descriptions = array();
521

    
522
  if (strlen($description)) {
523
    $descriptions[] = $description;
524
  }
525

    
526
  return implode('<br />', $descriptions);
527
}
528

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

    
550
  return $formatters;
551
}
552

    
553
/**
554
 * Implements hook_field_formatter_settings_form().
555
 *
556
 * Legacy support for the "Large filetype icon" file field formatter.
557
 * @see media_field_formatter_info()
558
 */
559
function media_field_formatter_settings_form($field, $instance, $view_mode, $form, &$form_state) {
560
  $display = $instance['display'][$view_mode];
561
  $settings = $display['settings'];
562

    
563
  $image_styles = image_style_options(FALSE, PASS_THROUGH);
564
  $element['image_style'] = array(
565
    '#title' => t('Image style'),
566
    '#type' => 'select',
567
    '#default_value' => $settings['image_style'],
568
    '#empty_option' => t('None (original image)'),
569
    '#options' => $image_styles,
570
  );
571

    
572
  return $element;
573
}
574

    
575
/**
576
 * Implements hook_field_formatter_settings_summary().
577
 *
578
 * Legacy support for the "Large filetype icon" file field formatter.
579
 * @see media_field_formatter_info()
580
 */
581
function media_field_formatter_settings_summary($field, $instance, $view_mode) {
582
  $display = $instance['display'][$view_mode];
583
  $settings = $display['settings'];
584

    
585
  $summary = array();
586

    
587
  $image_styles = image_style_options(FALSE, PASS_THROUGH);
588
  // Unset possible 'No defined styles' option.
589
  unset($image_styles['']);
590
  // Styles could be lost because of enabled/disabled modules that defines
591
  // their styles in code.
592
  if (isset($image_styles[$settings['image_style']])) {
593
    $summary[] = t('Image style: @style', array('@style' => $image_styles[$settings['image_style']]));
594
  }
595
  else {
596
    $summary[] = t('Original image');
597
  }
598

    
599
  return implode('<br />', $summary);
600
}
601

    
602
/**
603
 * Implements hook_field_formatter_view().
604
 *
605
 * Legacy support for the "Large filetype icon" file field formatter.
606
 * @see media_field_formatter_info()
607
 */
608
function media_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
609
  $element = array();
610

    
611
  if ($display['type'] == 'media_large_icon') {
612
    foreach ($items as $delta => $item) {
613
      $element[$delta] = array(
614
        '#theme' => 'media_formatter_large_icon',
615
        '#file' => (object) $item,
616
        '#style_name' => $display['settings']['image_style'],
617
      );
618
    }
619
  }
620

    
621
  return $element;
622
}