Projet

Général

Profil

Paste
Télécharger (19,3 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / media / modules / media_wysiwyg / media_wysiwyg.module @ da542b7b

1
<?php
2

    
3
/**
4
 * @file
5
 * Primarily Drupal hooks.
6
 */
7

    
8
// Functions for tracking the file usage of [[inline tags]].
9
require_once dirname(__FILE__) . '/includes/media_wysiwyg.file_usage.inc';
10

    
11
// Functions for working with [[inline tags]] and wysiwyg editors.
12
require_once dirname(__FILE__) . '/includes/media_wysiwyg.filter.inc';
13

    
14
// Functions for UUID support to embedded media.
15
require_once dirname(__FILE__) . '/includes/media_wysiwyg.uuid.inc';
16

    
17
/**
18
 * Implements hook_hook_info().
19
 */
20
function media_wysiwyg_hook_info() {
21
  $hooks = array(
22
    'media_wysiwyg_token_to_markup_alter',
23
    'media_wysiwyg_allowed_view_modes_alter',
24
    'media_wysiwyg_format_form_prepare_alter',
25
  );
26

    
27
  return array_fill_keys($hooks, array('group' => 'media_wysiwyg'));
28
}
29

    
30
/**
31
 * Implements hook_menu().
32
 */
33
function media_wysiwyg_menu() {
34
  $items = array();
35

    
36
  $items['media/%file/format-form'] = array(
37
    'title' => 'Style selector',
38
    'description' => 'Choose a format for a piece of media',
39
    'page callback' => 'drupal_get_form',
40
    'page arguments' => array('media_wysiwyg_format_form', 1),
41
    'access callback' => 'media_wysiwyg_access',
42
    'access arguments' => array('view', 1),
43
    'file' => 'includes/media_wysiwyg.pages.inc',
44
    'theme callback' => 'media_dialog_get_theme_name',
45
    'type' => MENU_CALLBACK,
46
  );
47

    
48
  return $items;
49
}
50

    
51
/**
52
 * Implements hook_permission().
53
 */
54
function media_wysiwyg_permission() {
55
  return array(
56
    'use media wysiwyg' => array(
57
      'title' => t('Use Media WYSIWYG in an editor'),
58
      // Marked restrict because the WYSIWYG forms generate image derivatives,
59
      // which could lead to a DoS security vulnerability.
60
      'restrict access' => TRUE,
61
    ),
62
  );
63
}
64

    
65
/**
66
 * Access callback for WYSIWYG Media.
67
 */
68
function media_wysiwyg_access($op, $file = NULL, $account = NULL) {
69
  return user_access('use media wysiwyg', $account) && file_entity_access($op, $file, $account);
70
}
71

    
72
/**
73
 * Implements hook_element_info_alter().
74
 */
75
function media_wysiwyg_element_info_alter(&$types) {
76
  $types['text_format']['#pre_render'][] = 'media_wysiwyg_pre_render_text_format';
77
}
78

    
79
/**
80
 * Builds a map of media tags in the element.
81
 *
82
 * Builds a map of the media tags in an element that are being rendered to their
83
 * rendered HTML. The map is stored in JS, so we can transform them when the
84
 * editor is being displayed.
85
 */
86
function media_wysiwyg_pre_render_text_format($element) {
87
  // filter_process_format() copies properties to the expanded 'value' child
88
  // element.
89
  if (!isset($element['format'])) {
90
    return $element;
91
  }
92

    
93
  $field = &$element['value'];
94
  $settings = array(
95
    'field' => $field['#id'],
96
  );
97

    
98
  if (!isset($field['#value'])) {
99
    return $element;
100
  }
101

    
102
  $tagmap = _media_wysiwyg_generate_tagMap($field['#value']);
103

    
104
  if (isset($tagmap)) {
105
    $element['#attached']['js'][] = array(
106
      'data' => array(
107
        'tagmap' => $tagmap,
108
      ),
109
      'type' => 'setting',
110
    );
111
  }
112

    
113
  // Load the media browser library.
114
  $element['#attached']['library'][] = array('media', 'media_browser');
115
  $element['#attached']['library'][] = array('media', 'media_browser_settings');
116

    
117
  // Add wysiwyg-specific settings.
118
  $settings = array(
119
    'wysiwyg_allowed_attributes' => variable_get('media_wysiwyg_wysiwyg_allowed_attributes', _media_wysiwyg_wysiwyg_allowed_attributes_default()),
120
    'img_alt_field' => 'field_file_image_alt_text',
121
    'img_title_field' => 'field_file_image_title_text',
122
  );
123

    
124
  // The file_entity module lets you specify a string, possibly with tokens, for
125
  // the alt and title attributes of images. We need the actual field names instead.
126
  // If the variable only contains a token of the format [file:field_file_image_alt_text]
127
  // then it's possible to extract it.
128
  $alt_token = variable_get('file_entity_alt', '[file:field_file_image_alt_text]');
129
  $title_token = variable_get('file_entity_title', '[file:field_file_image_title_text]');
130
  $matches = array();
131
  if (preg_match('/^\[file:(field_[[:alnum:]_-]+)\]$/', trim($alt_token), $matches)) {
132
    $settings['img_alt_field'] = $matches[1];
133
  }
134
  if (preg_match('/^\[file:(field_[[:alnum:]_-]+)\]$/', trim($title_token), $matches)) {
135
    $settings['img_title_field'] = $matches[1];
136
  }
137

    
138
  $element['#attached']['js'][] = array(
139
    'data' => array(
140
      'media' => $settings,
141
    ),
142
    'type' => 'setting',
143
  );
144

    
145
  // Add filter handling.
146
  $element['#attached']['js'][] = drupal_get_path('module', 'media_wysiwyg') . '/js/media_wysiwyg.filter.js';
147

    
148
  return $element;
149
}
150

    
151
/**
152
 * Implements hook_form_FORM_ID_alter().
153
 */
154
function media_wysiwyg_form_field_ui_field_edit_form_alter(&$form, &$form_state) {
155
  // Add a checkbox that marks this field as one that can be
156
  // overridden in the WYSIWYG.
157
  if ($form['#instance']['entity_type'] == 'file') {
158
    $field_type = $form['#field']['type'];
159
    $allowed_field_types = variable_get('media_wysiwyg_wysiwyg_override_field_types', array('text', 'text_long'));
160
    if (in_array($field_type, $allowed_field_types)) {
161
      $form['instance']['settings']['wysiwyg_override'] = array(
162
        '#type' => 'checkbox',
163
        '#title' => t('Override in WYSIWYG'),
164
        '#description' => t('If checked, then this field may be overridden in the WYSIWYG editor.'),
165
        '#default_value' => isset($form['#instance']['settings']['wysiwyg_override']) ? $form['#instance']['settings']['wysiwyg_override'] : FALSE,
166
      );
167
    }
168
  }
169
}
170

    
171
/**
172
 * Implements hook_form_FORM_ID_alter().
173
 */
174
function media_wysiwyg_form_wysiwyg_profile_form_alter(&$form, &$form_state) {
175
  // Add warnings if the media filter is disabled for the WYSIWYG's text format.
176
  $form['buttons']['drupal']['media']['#element_validate'][] = 'media_wysiwyg_wysiwyg_button_element_validate';
177
  $form['buttons']['drupal']['media']['#after_build'][] = 'media_wysiwyg_wysiwyg_button_element_validate';
178
  form_load_include($form_state, 'inc', 'media_wysiwyg', 'wysiwyg_plugins/media');
179
}
180

    
181
/**
182
 * Element validate callback for the media WYSIWYG button.
183
 */
184
function media_wysiwyg_wysiwyg_button_element_validate($element, &$form_state) {
185
  if (!empty($element['#value'])) {
186
    $format = filter_format_load($form_state['build_info']['args'][0]->format);
187
    $filters = filter_list_format($format->format);
188
    if (empty($filters['media_filter']->status)) {
189
      form_error($element, t('The <em>Convert Media tags to markup</em> filter must be enabled for the <a href="@format-link">@format format</a> in order to use the Media browser WYSIWYG button.', array(
190
        '@format-link' => url('admin/config/content/formats/' . $format->format, array('query' => array('destination' => $_GET['q']))),
191
        '@format' => $format->name,
192
      )));
193
    }
194
  }
195

    
196
  return $element;
197
}
198

    
199
/**
200
 * Implements hook_form_FORM_ID_alter().
201
 */
202
function media_wysiwyg_form_media_admin_config_browser_alter(&$form, &$form_state) {
203
  $form['wysiwyg'] = array(
204
    '#type' => 'fieldset',
205
    '#title' => t('WYSIWYG configuration'),
206
    '#collapsible' => TRUE,
207
    '#collapsed' => FALSE,
208
  );
209
  $form['wysiwyg']['media_wysiwyg_wysiwyg_browser_plugins'] = array(
210
    '#type' => 'checkboxes',
211
    '#title' => t('Enabled browser plugins'),
212
    '#options' => array(),
213
    '#required' => FALSE,
214
    '#default_value' => variable_get('media_wysiwyg_wysiwyg_browser_plugins', array()),
215
    '#description' => t('If no plugins are selected, they will all be available.'),
216
  );
217

    
218
  $plugins = media_get_browser_plugin_info();
219

    
220
  foreach ($plugins as $key => $plugin) {
221
    $form['wysiwyg']['media_wysiwyg_wysiwyg_browser_plugins']['#options'][$key] = !empty($plugin['title']) ? $plugin['title'] : $key;
222
  }
223

    
224
  $form['wysiwyg']['media_wysiwyg_wysiwyg_upload_directory'] = array(
225
    '#type' => 'textfield',
226
    '#title' => t("File directory for uploaded media"),
227
    '#default_value' => variable_get('media_wysiwyg_wysiwyg_upload_directory', ''),
228
    '#description' => t('Optional subdirectory within the upload destination where files will be stored. Do not include preceding or trailing slashes.'),
229
  );
230

    
231
  if (module_exists('token')) {
232
    $form['wysiwyg']['media_wysiwyg_wysiwyg_upload_directory']['#description'] .= t('This field supports tokens.');
233
    $form['wysiwyg']['tokens'] = array(
234
      '#theme' => 'token_tree',
235
      '#dialog' => TRUE,
236
    );
237
  }
238

    
239
  $form['wysiwyg']['media_wysiwyg_default_render'] = array(
240
    '#type' => 'radios',
241
    '#title' => t('How should file entities be rendered within a text field?'),
242
    '#description' => t("Full file entity rendering is the best choice for most sites. It respects the file entity's display settings specified at admin/structure/file-types. If your site already uses the legacy method, note that changing this option will affect your site's markup. Testing it on a non-production site is recommended."),
243
    '#options' => array(
244
      'file_entity' => 'Full file entity rendering',
245
      'field_attach' => 'Legacy rendering (using field attach)',
246
    ),
247
    '#default_value' => variable_get('media_wysiwyg_default_render', 'file_entity'),
248
  );
249

    
250
  $form['wysiwyg']['media_wysiwyg_wysiwyg_allowed_types'] = array(
251
    '#type' => 'checkboxes',
252
    '#title' => t('Allowed types in WYSIWYG'),
253
    '#options' => file_entity_type_get_names(),
254
    '#default_value' => variable_get('media_wysiwyg_wysiwyg_allowed_types', array('audio', 'image', 'video', 'document')),
255
  );
256

    
257
  $options = array();
258
  foreach(field_info_field_types() as $key => $type) {
259
    $options[$key] = $type['label'];
260
  }
261
  asort($options);
262
  $form['wysiwyg']['media_wysiwyg_wysiwyg_override_field_types'] = array(
263
    '#type' => 'checkboxes',
264
    '#title' => t('Override field types in WYSIWYG'),
265
    '#options' => $options,
266
    '#default_value' => variable_get('media_wysiwyg_wysiwyg_override_field_types', array('text', 'text_long')),
267
    '#description' => t('If checked, then the field type may be overridden in the WYSIWYG editor. Not all field types (e.g. Term reference) currently support being overridden so the desired result might not be achieved.')
268
  );
269

    
270
  $form['#submit'][] = 'media_wysiwyg_admin_config_browser_pre_submit';
271
}
272

    
273
/**
274
 * Manipulate values before form is submitted.
275
 */
276
function media_wysiwyg_admin_config_browser_pre_submit(&$form, &$form_state) {
277
  $wysiwyg_browser_plugins = array_unique(array_values($form_state['values']['media_wysiwyg_wysiwyg_browser_plugins']));
278
  if (empty($wysiwyg_browser_plugins[0])) {
279
    variable_del('media_wysiwyg_wysiwyg_browser_plugins');
280
    unset($form_state['values']['media_wysiwyg_wysiwyg_browser_plugins']);
281
  }
282
}
283

    
284
/**
285
 * Implements hook_filter_info().
286
 */
287
function media_wysiwyg_filter_info() {
288
  $filters['media_filter'] = array(
289
    'title' => t('Convert Media tags to markup'),
290
    'description' => t('This filter will convert [[{type:media... ]] tags into markup. This must be enabled for the Media WYSIWYG integration to work with this input format.'),
291
    'process callback' => 'media_wysiwyg_filter',
292
    'weight' => 2,
293
    // @TODO not implemented
294
    'tips callback' => 'media_filter_tips',
295
  );
296

    
297
  $filters['media_filter_paragraph_fix'] = array(
298
    'title' => t('Ensure that embedded Media tags are not contained in paragraphs'),
299
    'description' => t('This filter will strip any paragraph tags surrounding embedded Media tags. This helps to avoid the chopped up markup that can result from unexpectedly closed paragraph tags. This filter should be positioned above (before) the "Convert Media tags to markup" filter.'),
300
    'process callback' => 'media_wysiwyg_filter_paragraph_fix',
301
    'weight' => 1,
302
  );
303

    
304
  return $filters;
305
}
306

    
307
/**
308
 * Implements hook_wysiwyg_include_directory().
309
 */
310
function media_wysiwyg_wysiwyg_include_directory($type) {
311
  switch ($type) {
312
    case 'plugins':
313
      return 'wysiwyg_plugins';
314

    
315
      break;
316
  }
317
}
318

    
319
/**
320
 * Returns the default set of allowed attributes for use with WYSIWYG.
321
 *
322
 * @return array
323
 *   An array of whitelisted attributes.
324
 */
325
function _media_wysiwyg_wysiwyg_allowed_attributes_default() {
326
  return array(
327
    'alt',
328
    'title',
329
    'height',
330
    'width',
331
    'hspace',
332
    'vspace',
333
    'border',
334
    'align',
335
    'style',
336
    'class',
337
    'id',
338
    'usemap',
339
    'data-picture-group',
340
    'data-picture-align',
341
    'data-picture-mapping',
342
  );
343
}
344

    
345
/**
346
 * Returns a drupal_render() array for just the file portion of a file entity.
347
 *
348
 * Optional custom settings can override how the file is displayed.
349
 */
350
function media_wysiwyg_get_file_without_label($file, $view_mode, $settings = array(), $langcode = NULL) {
351
  // Get the override alt & title from the fields override array. Grab the
352
  // "special" field names from the token replacement in file_entity, then see
353
  // if an override is provided and needed.
354
  $pattern = '/\[(\w+):(\w+)\]/';
355
  $alt = variable_get('file_entity_alt', '[file:field_file_image_alt_text]');
356
  $title = variable_get('file_entity_title', '[file:field_file_image_title_text]');
357
  $overrides = array(
358
    'alt' => $alt,
359
    'title' => $title,
360
  );
361
  foreach ($overrides as $field_type => $field_name) {
362
    preg_match($pattern, $field_name, $matches);
363
    if (!empty($matches[2])) {
364
      $field_name = $matches[2];
365
      $langcode = field_language('file', $file, $field_name);
366
      if (isset($settings['fields'][$field_name][$langcode]['value'])) {
367
        if (empty($settings['attributes'][$field_type])) {
368
          $settings['attributes'][$field_type] = $settings['fields'][$field_name][$langcode]['value'];
369
        }
370
      }
371
      if (isset($settings['fields'][$field_name][$langcode][0]['value'])) {
372
        if (empty($settings['attributes'][$field_type])) {
373
          $settings['attributes'][$field_type] = $settings['fields'][$field_name][$langcode][0]['value'];
374
        }
375
      }
376
    }
377
  }
378

    
379
  $file->override = $settings;
380

    
381
  $element = file_view_file($file, $view_mode, $langcode);
382

    
383
  // Field Translation Support.
384
  if (field_has_translation_handler('file')) {
385
    if ($field_items = field_get_items('file', $file, 'field_file_image_alt_text', $langcode)) {
386
      $value = field_view_value('file', $file, 'field_file_image_alt_text', $field_items[0], array(), $langcode);
387
      $element['#alt'] = isset($value['#markup']) ? $value['#markup'] : '';
388
    }
389
  }
390

    
391
  // The formatter invoked by file_view_file() can use $file->override to
392
  // customize the returned render array to match the requested settings. To
393
  // support simple formatters that don't do this, set the element attributes to
394
  // what was requested, but not if the formatter applied its own logic for
395
  // element attributes.
396
  if (isset($settings['attributes'])) {
397
    if (empty($element['#attributes'])) {
398
      $element['#attributes'] = $settings['attributes'];
399
    }
400

    
401
    // While this function may be called for any file type, images are a common
402
    // use-case, and image theme functions have their own structure for render
403
    // arrays.
404
    if (isset($element['#theme'])) {
405
      // theme_image() and theme_image_style() require the 'alt' attributes to
406
      // be passed separately from the 'attributes' array. (see
407
      // http://drupal.org/node/999338). Until that's fixed, implement this
408
      // special-case logic. Image formatters using other theme functions are
409
      // responsible for their own 'alt' attribute handling. See
410
      // theme_media_formatter_large_icon() for an example.
411
      if (in_array($element['#theme'], array('image', 'image_style'))) {
412
        if (empty($element['#alt']) && isset($settings['attributes']['alt'])) {
413
          $element['#alt'] = $settings['attributes']['alt'];
414
        }
415
      }
416
      // theme_image_formatter() and any potential replacements, such as
417
      // theme_colorbox_image_formatter(), also require attribute handling.
418
      elseif (strpos($element['#theme'], 'image_formatter') !== FALSE) {
419
        // theme_image_formatter() requires the attributes to be
420
        // set on the item rather than the element itself.
421
        if (empty($element['#item']['attributes'])) {
422
          $element['#item']['attributes'] = $settings['attributes'];
423
        }
424

    
425
        // theme_image_formatter() also requires alt, title, height, and
426
        // width attributes to be set on the item rather than within its
427
        // attributes array.
428
        foreach (array('alt', 'title', 'width', 'height') as $attr) {
429
          if (isset($settings['attributes'][$attr])) {
430
            $element['#item'][$attr] = $settings['attributes'][$attr];
431
          }
432
        }
433
      }
434
    }
435
  }
436

    
437
  return $element;
438
}
439

    
440
/**
441
 * Returns an array containing the names of all fields that perform text filtering.
442
 */
443
function media_wysiwyg_filter_fields_with_text_filtering($entity_type, $entity) {
444
  list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entity);
445
  $fields = field_info_instances($entity_type, $bundle);
446

    
447
  // Get all of the fields on this entity that allow text filtering.
448
  $fields_with_text_filtering = array();
449
  foreach ($fields as $field_name => $field) {
450
    if (!empty($field['settings']['text_processing'])) {
451
      $fields_with_text_filtering[] = $field_name;
452
    }
453
  }
454

    
455
  return $fields_with_text_filtering;
456
}
457

    
458
/**
459
 * Return a list of view modes allowed for a file type.
460
 *
461
 * @param string $file_type
462
 *   A file type machine name.
463
 *
464
 * @return array
465
 *   An array of view modes that can be used on the file type.
466
 */
467
function media_wysiwyg_get_file_type_view_mode_options($file_type) {
468
  $enabled_view_modes = &drupal_static(__FUNCTION__, array());
469

    
470
  // @todo Add more caching for this.
471
  if (!isset($enabled_view_modes[$file_type])) {
472
    $enabled_view_modes[$file_type] = array();
473

    
474
    // Add the default view mode by default.
475
    $enabled_view_modes[$file_type]['default'] = t('Default');
476

    
477
    $entity_info = entity_get_info('file');
478
    $view_mode_settings = field_view_mode_settings('file', $file_type);
479
    foreach ($entity_info['view modes'] as $view_mode => $view_mode_info) {
480
      // Do not show view modes that don't have their own settings and will
481
      // only fall back to the default view mode.
482
      if (empty($view_mode_settings[$view_mode]['custom_settings'])) {
483
        continue;
484
      }
485

    
486
      // Don't present the user with an option to choose a view mode in which
487
      // the file is hidden.
488
      $extra_fields = field_extra_fields_get_display('file', $file_type, $view_mode);
489
      if (empty($extra_fields['file']['visible'])) {
490
        continue;
491
      }
492

    
493
      // Add the view mode to the list of enabled view modes.
494
      $enabled_view_modes[$file_type][$view_mode] = $view_mode_info['label'];
495
    }
496
  }
497

    
498
  return $enabled_view_modes[$file_type];
499
}
500

    
501
/**
502
 * Return a list of view modes allowed for a file embedded in the WYSIWYG.
503
 *
504
 * @param object $file
505
 *   A file entity.
506
 *
507
 * @return array
508
 *   An array of view modes that can be used on the file when embedded in the
509
 *   WYSIWYG.
510
 */
511
function media_wysiwyg_get_file_view_mode_options($file) {
512
  $view_modes = media_wysiwyg_get_file_type_view_mode_options($file->type);
513
  drupal_alter('media_wysiwyg_allowed_view_modes', $view_modes, $file);
514
  // Invoke the deprecated/misspelled alter hook as well.
515
  drupal_alter('media_wysiwyg_wysiwyg_allowed_view_modes', $view_modes, $file);
516
  return $view_modes;
517
}
518

    
519
/**
520
 * Implements hook_file_displays_alter().
521
 */
522
function media_wysiwyg_file_displays_alter(&$displays, $file, $view_mode) {
523
  // Override the fields of the file when requested by the WYSIWYG.
524
  if (isset($file->override) && isset($file->override['fields'])) {
525
    $instance = field_info_instances('file', $file->type);
526
    foreach ($file->override['fields'] as $field_name => $value) {
527
      if (!isset($instance[$field_name]['settings']) || !isset($instance[$field_name]['settings']['wysiwyg_override']) || $instance[$field_name]['settings']['wysiwyg_override']) {
528
        $file->{$field_name} = $value;
529
      }
530
    }
531
  }
532
}