Project

General

Profile

Paste
Download (15.5 KB) Statistics
| Branch: | Revision:

root / drupal7 / sites / all / modules / media / modules / media_wysiwyg / media_wysiwyg.module @ 1f623f01

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_wysiwyg_profile_form_alter(&$form, &$form_state) {
155
  // Add warnings if the media filter is disabled for the WYSIWYG's text format.
156
  $form['buttons']['drupal']['media']['#element_validate'][] = 'media_wysiwyg_wysiwyg_button_element_validate';
157
  $form['buttons']['drupal']['media']['#after_build'][] = 'media_wysiwyg_wysiwyg_button_element_validate';
158
  form_load_include($form_state, 'inc', 'media_wysiwyg', 'wysiwyg_plugins/media');
159
}
160

    
161
/**
162
 * Element validate callback for the media WYSIWYG button.
163
 */
164
function media_wysiwyg_wysiwyg_button_element_validate($element, &$form_state) {
165
  if (!empty($element['#value'])) {
166
    $format = filter_format_load($form_state['build_info']['args'][0]->format);
167
    $filters = filter_list_format($format->format);
168
    if (empty($filters['media_filter']->status)) {
169
      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(
170
        '@format-link' => url('admin/config/content/formats/' . $format->format, array('query' => array('destination' => $_GET['q']))),
171
        '@format' => $format->name,
172
      )));
173
    }
174
  }
175

    
176
  return $element;
177
}
178

    
179
/**
180
 * Implements hook_form_FORM_ID_alter().
181
 */
182
function media_wysiwyg_form_media_admin_config_browser_alter(&$form, &$form_state) {
183
  $form['wysiwyg'] = array(
184
    '#type' => 'fieldset',
185
    '#title' => t('WYSIWYG configuration'),
186
    '#collapsible' => TRUE,
187
    '#collapsed' => FALSE,
188
  );
189
  $form['wysiwyg']['media_wysiwyg_wysiwyg_browser_plugins'] = array(
190
    '#type' => 'checkboxes',
191
    '#title' => t('Enabled browser plugins'),
192
    '#options' => array(),
193
    '#required' => FALSE,
194
    '#default_value' => variable_get('media_wysiwyg_wysiwyg_browser_plugins', array()),
195
    '#description' => t('If no plugins are selected, they will all be available.'),
196
  );
197

    
198
  $plugins = media_get_browser_plugin_info();
199

    
200
  foreach ($plugins as $key => $plugin) {
201
    $form['wysiwyg']['media_wysiwyg_wysiwyg_browser_plugins']['#options'][$key] = !empty($plugin['title']) ? $plugin['title'] : $key;
202
  }
203

    
204
  $form['wysiwyg']['media_wysiwyg_wysiwyg_upload_directory'] = array(
205
    '#type' => 'textfield',
206
    '#title' => t("File directory for uploaded media"),
207
    '#default_value' => variable_get('media_wysiwyg_wysiwyg_upload_directory', ''),
208
    '#description' => t('Optional subdirectory within the upload destination where files will be stored. Do not include preceding or trailing slashes.'),
209
  );
210

    
211
  if (module_exists('token')) {
212
    $form['wysiwyg']['media_wysiwyg_wysiwyg_upload_directory']['#description'] .= t('This field supports tokens.');
213
    $form['wysiwyg']['tokens'] = array(
214
      '#theme' => 'token_tree',
215
      '#dialog' => TRUE,
216
    );
217
  }
218

    
219
  $form['wysiwyg']['media_wysiwyg_default_render'] = array(
220
    '#type' => 'radios',
221
    '#title' => t('How should file entities be rendered within a text field?'),
222
    '#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."),
223
    '#options' => array(
224
      'file_entity' => 'Full file entity rendering',
225
      'field_attach' => 'Legacy rendering (using field attach)',
226
    ),
227
    '#default_value' => variable_get('media_wysiwyg_default_render', 'file_entity'),
228
  );
229

    
230
  $form['wysiwyg']['media_wysiwyg_wysiwyg_allowed_types'] = array(
231
    '#type' => 'checkboxes',
232
    '#title' => t('Allowed types in WYSIWYG'),
233
    '#options' => file_entity_type_get_names(),
234
    '#default_value' => variable_get('media_wysiwyg_wysiwyg_allowed_types', array('audio', 'image', 'video', 'document')),
235
  );
236

    
237
  $form['#submit'][] = 'media_wysiwyg_admin_config_browser_pre_submit';
238
}
239

    
240
/**
241
 * Manipulate values before form is submitted.
242
 */
243
function media_wysiwyg_admin_config_browser_pre_submit(&$form, &$form_state) {
244
  $wysiwyg_browser_plugins = array_unique(array_values($form_state['values']['media_wysiwyg_wysiwyg_browser_plugins']));
245
  if (empty($wysiwyg_browser_plugins[0])) {
246
    variable_del('media_wysiwyg_wysiwyg_browser_plugins');
247
    unset($form_state['values']['media_wysiwyg_wysiwyg_browser_plugins']);
248
  }
249
}
250

    
251
/**
252
 * Implements hook_filter_info().
253
 */
254
function media_wysiwyg_filter_info() {
255
  $filters['media_filter'] = array(
256
    'title' => t('Convert Media tags to markup'),
257
    '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.'),
258
    'process callback' => 'media_wysiwyg_filter',
259
    'weight' => 2,
260
    // @TODO not implemented
261
    'tips callback' => 'media_filter_tips',
262
  );
263

    
264
  return $filters;
265
}
266

    
267
/**
268
 * Implements hook_wysiwyg_include_directory().
269
 */
270
function media_wysiwyg_wysiwyg_include_directory($type) {
271
  switch ($type) {
272
    case 'plugins':
273
      return 'wysiwyg_plugins';
274

    
275
      break;
276
  }
277
}
278

    
279
/**
280
 * Returns the default set of allowed attributes for use with WYSIWYG.
281
 *
282
 * @return array
283
 *   An array of whitelisted attributes.
284
 */
285
function _media_wysiwyg_wysiwyg_allowed_attributes_default() {
286
  return array(
287
    'alt',
288
    'title',
289
    'height',
290
    'width',
291
    'hspace',
292
    'vspace',
293
    'border',
294
    'align',
295
    'style',
296
    'class',
297
    'id',
298
    'usemap',
299
    'data-picture-group',
300
    'data-picture-align',
301
    'data-picture-mapping',
302
  );
303
}
304

    
305
/**
306
 * Returns a drupal_render() array for just the file portion of a file entity.
307
 *
308
 * Optional custom settings can override how the file is displayed.
309
 */
310
function media_wysiwyg_get_file_without_label($file, $view_mode, $settings = array(), $langcode = NULL) {
311
  $file->override = $settings;
312

    
313
  $element = file_view_file($file, $view_mode, $langcode);
314

    
315
  // Field Translation Support.
316
  if (field_has_translation_handler('file')) {
317
    if ($field_items = field_get_items('file', $file, 'field_file_image_alt_text', $langcode)) {
318
      $value = field_view_value('file', $file, 'field_file_image_alt_text', $field_items[0], array(), $langcode);
319
      $element['#alt'] = isset($value['#markup']) ? $value['#markup'] : '';
320
    }
321
  }
322

    
323
  // The formatter invoked by file_view_file() can use $file->override to
324
  // customize the returned render array to match the requested settings. To
325
  // support simple formatters that don't do this, set the element attributes to
326
  // what was requested, but not if the formatter applied its own logic for
327
  // element attributes.
328
  if (isset($settings['attributes'])) {
329
    if (empty($element['#attributes'])) {
330
      $element['#attributes'] = $settings['attributes'];
331
    }
332

    
333
    // While this function may be called for any file type, images are a common
334
    // use-case, and image theme functions have their own structure for render
335
    // arrays.
336
    if (isset($element['#theme'])) {
337
      // theme_image() and theme_image_style() require the 'alt' attributes to
338
      // be passed separately from the 'attributes' array. (see
339
      // http://drupal.org/node/999338). Until that's fixed, implement this
340
      // special-case logic. Image formatters using other theme functions are
341
      // responsible for their own 'alt' attribute handling. See
342
      // theme_media_formatter_large_icon() for an example.
343
      if (in_array($element['#theme'], array('image', 'image_style'))) {
344
        if (empty($element['#alt']) && isset($settings['attributes']['alt'])) {
345
          $element['#alt'] = $settings['attributes']['alt'];
346
        }
347
      }
348
      // theme_image_formatter() and any potential replacements, such as
349
      // theme_colorbox_image_formatter(), also require attribute handling.
350
      elseif (strpos($element['#theme'], 'image_formatter') !== FALSE) {
351
        // theme_image_formatter() requires the attributes to be
352
        // set on the item rather than the element itself.
353
        if (empty($element['#item']['attributes'])) {
354
          $element['#item']['attributes'] = $settings['attributes'];
355
        }
356

    
357
        // theme_image_formatter() also requires alt, title, height, and
358
        // width attributes to be set on the item rather than within its
359
        // attributes array.
360
        foreach (array('alt', 'title', 'width', 'height') as $attr) {
361
          if (isset($settings['attributes'][$attr])) {
362
            $element['#item'][$attr] = $settings['attributes'][$attr];
363
          }
364
        }
365
      }
366
    }
367
  }
368

    
369
  return $element;
370
}
371

    
372
/**
373
 * Returns an array containing the names of all fields that perform text filtering.
374
 */
375
function media_wysiwyg_filter_fields_with_text_filtering($entity_type, $entity) {
376
  list($entity_id, $revision_id, $bundle) = entity_extract_ids($entity_type, $entity);
377
  $fields = field_info_instances($entity_type, $bundle);
378

    
379
  // Get all of the fields on this entity that allow text filtering.
380
  $fields_with_text_filtering = array();
381
  foreach ($fields as $field_name => $field) {
382
    if (!empty($field['settings']['text_processing'])) {
383
      $fields_with_text_filtering[] = $field_name;
384
    }
385
  }
386

    
387
  return $fields_with_text_filtering;
388
}
389

    
390
/**
391
 * Return a list of view modes allowed for a file type.
392
 *
393
 * @param string $file_type
394
 *   A file type machine name.
395
 *
396
 * @return array
397
 *   An array of view modes that can be used on the file type.
398
 */
399
function media_wysiwyg_get_file_type_view_mode_options($file_type) {
400
  $enabled_view_modes = &drupal_static(__FUNCTION__, array());
401

    
402
  // @todo Add more caching for this.
403
  if (!isset($enabled_view_modes[$file_type])) {
404
    $enabled_view_modes[$file_type] = array();
405

    
406
    // Add the default view mode by default.
407
    $enabled_view_modes[$file_type]['default'] = t('Default');
408

    
409
    $entity_info = entity_get_info('file');
410
    $view_mode_settings = field_view_mode_settings('file', $file_type);
411
    foreach ($entity_info['view modes'] as $view_mode => $view_mode_info) {
412
      // Do not show view modes that don't have their own settings and will
413
      // only fall back to the default view mode.
414
      if (empty($view_mode_settings[$view_mode]['custom_settings'])) {
415
        continue;
416
      }
417

    
418
      // Don't present the user with an option to choose a view mode in which
419
      // the file is hidden.
420
      $extra_fields = field_extra_fields_get_display('file', $file_type, $view_mode);
421
      if (empty($extra_fields['file']['visible'])) {
422
        continue;
423
      }
424

    
425
      // Add the view mode to the list of enabled view modes.
426
      $enabled_view_modes[$file_type][$view_mode] = $view_mode_info['label'];
427
    }
428
  }
429

    
430
  return $enabled_view_modes[$file_type];
431
}
432

    
433
/**
434
 * Return a list of view modes allowed for a file embedded in the WYSIWYG.
435
 *
436
 * @param object $file
437
 *   A file entity.
438
 *
439
 * @return array
440
 *   An array of view modes that can be used on the file when embedded in the
441
 *   WYSIWYG.
442
 */
443
function media_wysiwyg_get_file_view_mode_options($file) {
444
  $view_modes = media_wysiwyg_get_file_type_view_mode_options($file->type);
445
  drupal_alter('media_wysiwyg_allowed_view_modes', $view_modes, $file);
446
  // Invoke the deprecated/misspelled alter hook as well.
447
  drupal_alter('media_wysiwyg_wysiwyg_allowed_view_modes', $view_modes, $file);
448
  return $view_modes;
449
}