Issue #1830754 by Lukas von Blarer: Fixed Not being applied to images loaded via...
[project/resp_img.git] / resp_img.module
1 <?php
2
3 define('RESP_IMG_CLASS', 'resp-img-picture');
4 define('RESP_IMG_SEPARATOR', '__');
5 define('RESP_IMG_STYLE_PREFIX', 'resp_img__');
6
7 /**
8 * Implements hook_permission().
9 */
10 function resp_img_permission() {
11 return array(
12 'administer responsive images and styles' => array(
13 'title' => t('Administer Responsive Images and Styles'),
14 'description' => t('Administer responsive images and styles'),
15 ),
16 );
17 }
18
19 /**
20 * Implements hook_menu().
21 */
22 function resp_img_menu() {
23 $items = array();
24
25 // @todo: link to all breakpoints and a list of all groups
26 // cf theme settings page
27 $items['admin/config/media/resp_img'] = array(
28 'title' => 'Responsive images and styles',
29 'description' => 'Manage Responsive Images and Styles',
30 'page callback' => 'drupal_get_form',
31 'page arguments' => array('resp_img_admin_breakpoints'),
32 'access arguments' => array('administer responsive images and styles'),
33 'file' => 'resp_img.admin.inc',
34 );
35
36 $items['admin/config/media/resp_img/create_style'] = array(
37 'title' => 'Add responsive style',
38 'description' => 'Add a responsive image style',
39 'page callback' => 'drupal_get_form',
40 'page arguments' => array('resp_img_add_style_form'),
41 'access arguments' => array('administer responsive images and styles'),
42 'file' => 'resp_img.admin.inc',
43 'type' => MENU_LOCAL_TASK,
44 'weight' => 30,
45 );
46
47 $items['admin/config/media/resp_img/groups'] = array(
48 'title' => 'Groups',
49 'type' => MENU_DEFAULT_LOCAL_TASK,
50 'weight' => 10,
51 );
52
53 $items['admin/config/media/resp_img/groups/global'] = array(
54 'title' => 'Map breakpoints and image styles',
55 'type' => MENU_DEFAULT_LOCAL_TASK,
56 'weight' => -1,
57 );
58 $items['admin/config/media/resp_img/groups/import'] = array(
59 'title' => 'Import mappings',
60 'page arguments' => array('resp_img_admin_import_form'),
61 'type' => MENU_LOCAL_TASK,
62 'access arguments' => array('administer responsive images and styles'),
63 'file' => 'resp_img.admin.inc',
64 'weight' => 999,
65 );
66
67 $breakpoint_groups = breakpoints_breakpoint_group_load_all();
68 foreach ($breakpoint_groups as $breakpoint_group_name => $breakpoint_group) {
69 if (!empty($breakpoint_group->machine_name)) {
70 $items['admin/config/media/resp_img/groups/' . $breakpoint_group->machine_name] = array(
71 'title' => $breakpoint_group->name,
72 'page arguments' => array('resp_img_admin_breakpoints', $breakpoint_group->machine_name),
73 'type' => MENU_LOCAL_TASK,
74 'access arguments' => array('administer responsive images and styles'),
75 'file' => 'resp_img.admin.inc',
76 'weight' => 15,
77 );
78 $items['admin/config/media/resp_img/groups/' . $breakpoint_group->machine_name . '/export'] = array(
79 'title' => 'Export ' . check_plain($breakpoint_group->name) . ' mappings',
80 'page callback' => 'drupal_get_form',
81 'page arguments' => array('resp_img_admin_export_form', 'mappings.' . $breakpoint_group->machine_name),
82 'type' => MENU_LOCAL_ACTION,
83 'access arguments' => array('administer responsive images and styles', 'mappings.' . $breakpoint_group->machine_name),
84 'access callback' => 'resp_img_mappings_export_access',
85 'file' => 'resp_img.admin.inc',
86 'weight' => 15,
87 );
88 }
89 }
90
91 return $items;
92 }
93
94 /**
95 * Access callback.
96 */
97 function resp_img_mappings_export_access($perm, $mapping_name) {
98 return resp_img_mapping_load($mapping_name) && user_access($perm);
99 }
100
101 /**
102 * Load mappings.
103 */
104 function resp_img_mapping_load($name = NULL) {
105 ctools_include('export');
106 if ($name) {
107 $mappings = ctools_export_load_object('resp_img_mapping', 'names', array($name));
108 $mapping = isset($mappings[$name]) ? $mappings[$name] : FALSE;
109 return $mapping;
110 }
111 return ctools_export_load_object('resp_img_mapping');
112 }
113
114
115 /**
116 * Save mappings.
117 */
118 function resp_img_mapping_save(&$mapping) {
119 ctools_include('export');
120 $update = isset($mapping->id) ? array('id') : array();
121 $style = image_style_load(RESP_IMG_STYLE_PREFIX . $mapping->breakpoint_group);
122 if ($style) {
123 image_style_flush($style);
124 }
125 return drupal_write_record('resp_img_mapping', $mapping, $update);
126 }
127
128 /**
129 * Validate mappings.
130 */
131 function resp_img_mapping_validate($mapping) {
132 if (!is_object($mapping)) {
133 return FALSE;
134 }
135 foreach (array('machine_name', 'breakpoint_group', 'mapping') as $property) {
136 if (!property_exists($mapping, $property)) {
137 return FALSE;
138 }
139 }
140 return TRUE;
141 }
142
143 /**
144 * Add javascript for older browser support
145 */
146 function resp_img_add_js() {
147 static $added = FALSE;
148 if (!$added) {
149 $added = TRUE;
150 drupal_add_js(drupal_get_path('module', 'resp_img') . '/picturefill/matchmedia.js', array('type' => 'file', 'weight' => -10, 'group' => JS_DEFAULT));
151 drupal_add_js(drupal_get_path('module', 'resp_img') . '/picturefill/picturefill.js', array('type' => 'file', 'weight' => -10, 'group' => JS_DEFAULT));
152 drupal_add_js(drupal_get_path('module', 'resp_img') . '/resp_img.js', array('type' => 'file', 'weight' => -10, 'group' => JS_DEFAULT));
153 }
154 }
155
156 /**
157 * Implements hook_theme().
158 */
159 function resp_img_theme() {
160 return array(
161 'picture' => array(
162 'variables' => array(
163 'style_name' => NULL,
164 'path' => NULL,
165 'width' => NULL,
166 'height' => NULL,
167 'alt' => '',
168 'title' => NULL,
169 'attributes' => array(),
170 'breakpoints' => array(),
171 ),
172 ),
173 'picture_formatter' => array(
174 'variables' => array(
175 'item' => NULL,
176 'path' => NULL,
177 'image_style' => NULL,
178 'breakpoints' => array(),
179 ),
180 ),
181 'colorbox_picture_formatter' => array(
182 'variables' => array(
183 'item' => NULL,
184 'node' => NULL,
185 'field' => array(),
186 'display_settings' => array(),
187 'breakpoints' => array(),
188 ),
189 ),
190 'colorbox_picturefield' => array(
191 'variables' => array(
192 'image' => array(),
193 'path' => NULL,
194 'title' => NULL,
195 'gid' => NULL,
196 'breakpoints' => array(),
197 ),
198 ),
199 );
200 }
201
202 /**
203 * Implements hook_entity_info_alter().
204 */
205 function resp_img_entity_info_alter(&$info) {
206 if (isset($info['file'])) {
207 foreach (breakpoints_breakpoint_group_load_all() as $group) {
208 $info['file']['view modes']['media_responsive_' . $group->machine_name] = array(
209 'label' => t('@group (Responsive)', array('@group' => $group->name)),
210 'custom settings' => TRUE,
211 );
212 }
213 }
214 }
215
216 /**
217 * Implements hook_ctools_plugin_api().
218 *
219 * Lets CTools know which plugin APIs are implemented by resp_img module.
220 */
221 function resp_img_ctools_plugin_api($owner, $api) {
222 static $api_versions = array(
223 'file_entity' => array(
224 'file_default_displays' => 1,
225 ),
226 );
227 if (isset($api_versions[$owner][$api])) {
228 return array('version' => $api_versions[$owner][$api]);
229 }
230 }
231
232 /**
233 * Implements hook_file_default_displays().
234 */
235 function resp_img_file_default_displays() {
236 $default_image_styles = array();
237 foreach (breakpoints_breakpoint_group_load_all() as $group) {
238 $default_image_styles['media_responsive_' . $group->machine_name] = RESP_IMG_STYLE_PREFIX . $group->machine_name;
239 }
240 $default_displays = array();
241
242 foreach ($default_image_styles as $view_mode => $image_style) {
243 $display_name = 'image__' . $view_mode . '__file_image';
244 $default_displays[$display_name] = (object) array(
245 'api_version' => 1,
246 'name' => $display_name,
247 'status' => 1,
248 'weight' => 5,
249 'settings' => array('image_style' => $image_style),
250 );
251 }
252
253 return $default_displays;
254 }
255
256 /**
257 * Implements hook_preprocess_field().
258 */
259 function resp_img_field_attach_view_alter(&$output, $context) {
260 $view = module_exists('views') ? views_get_current_view() : FALSE;
261 foreach (element_children($output) as $field_name) {
262 $element = &$output[$field_name];
263 $vars = array();
264 if (isset($element['#formatter'])) {
265 if ($element['#formatter'] == 'image') {
266 $vars['image_style'] = 'image_style';
267 $vars['#formatter'] = 'picture';
268 $vars['#theme'] = 'picture_formatter';
269 }
270 elseif ($element['#formatter'] == 'colorbox') {
271 $vars['image_style'] = 'colorbox_node_style';
272 $vars['#formatter'] = 'picture';
273 $vars['#theme'] = 'colorbox_picture_formatter';
274 }
275 elseif ($element['#formatter'] == 'slideshow') {
276 $vars['image_style'] = 'slideshow_image_style';
277 $vars['#formatter'] = 'slideshow';
278 $vars['#theme'] = 'field_slideshow';
279 }
280
281 if (!empty($vars)) {
282 $instance = field_info_instance($element['#entity_type'], $element['#field_name'], $element['#bundle']);
283 if ($view && isset($view->query->pager->display->handler->handlers['field'][$element['#field_name']])) {
284 $settings = $view->query->pager->display->handler->handlers['field'][$element['#field_name']]->options['settings'];
285 }
286 elseif (isset($instance['display'][$context['view_mode']]['settings'][$vars['image_style']]) && !empty($instance['display'][$context['view_mode']]['settings'][$vars['image_style']])) {
287 $settings = $instance['display'][$context['view_mode']]['settings'];
288 }
289 else {
290 $settings = $instance['display']['default']['settings'];
291 }
292 if (isset($settings[$vars['image_style']]) && strpos($settings[$vars['image_style']], RESP_IMG_STYLE_PREFIX) !== FALSE) {
293 $group_name = drupal_substr($settings[$vars['image_style']], drupal_strlen(RESP_IMG_STYLE_PREFIX));
294 $breakpoint_styles = _resp_img_get_breakpoint_styles($group_name);
295 if (!empty($breakpoint_styles)) {
296 // Change the formatter so it uses ours.
297 $element['#formatter'] = $vars['#formatter'];
298
299 // Change the formatter on all items as well.
300 $num_fields = ($element['#formatter'] != 'slideshow') ? count($element['#items']) : 1;
301 for ($delta = 0; $delta < $num_fields; $delta++) {
302 $element[$delta]['#theme'] = $vars['#theme'];
303 // Change the image style to the first in use.
304 $reset = reset($breakpoint_styles['mapping']);
305 $element[$delta]['#image_style'] = reset($reset);
306 $element[$delta]['#breakpoints'] = $breakpoint_styles;
307 }
308 }
309 else {
310 watchdog('Responsive images', 'You have to map at least 1 style for ' . check_plain($group_name) . '.');
311 }
312 }
313 }
314 }
315 }
316 }
317
318 function theme_picture_formatter($variables) {
319 if (!isset($variables['breakpoints']) || empty($variables['breakpoints'])) {
320 return theme('image_formatter', $variables);
321 }
322
323 $item = $variables['item'];
324
325 // Do not output an empty 'title' attribute.
326 if (isset($item['title']) && drupal_strlen($item['title']) == 0) {
327 unset($item['title']);
328 }
329
330 $item['style_name'] = $variables['image_style'];
331 $item['breakpoints'] = $variables['breakpoints'];
332
333 if (!isset($item['path']) && isset($variables['uri'])) {
334 $item['path'] = $variables['uri'];
335 }
336 $output = theme('picture', $item);
337
338 if (isset($variables['path']['path'])) {
339 $path = $variables['path']['path'];
340 $options = isset($variables['path']['options']) ? $variables['path']['options'] : array();
341 $options['html'] = TRUE;
342 $output = l($output, $path, $options);
343 }
344 return $output;
345 }
346
347 /**
348 * Theme a picture element.
349 */
350 function theme_picture($variables) {
351 resp_img_add_js();
352 // Add classes to ease styling
353 if (!isset($variables['attributes'])) {
354 $variables['attributes'] = array();
355 }
356 if (!isset($variables['attributes']['class'])) {
357 $variables['attributes']['class'] = array();
358 }
359 $variables['attributes']['class'][] = RESP_IMG_CLASS;
360
361 // Make sure that width and height are proper values
362 // If they exists we'll output them
363 // @see http://www.w3.org/community/respimg/2012/06/18/florians-compromise/
364 if (isset($variables['width']) && empty($variables['width'])) {
365 unset($variables['width']);
366 unset($variables['height']);
367 }
368 elseif (isset($variables['height']) && empty($variables['height'])) {
369 unset($variables['width']);
370 unset($variables['height']);
371 }
372
373 // Use path or uri untill D7 uses one in all places.
374 if (!isset($variables['path']) || empty($variables['path'])) {
375 $variables['path'] = ($variables['uri']);
376 }
377 if (!isset($variables['uri']) || empty($variables['uri'])) {
378 $variables['uri'] = ($variables['path']);
379 }
380
381 $images = array();
382 $output = array();
383
384 // Fallback image.
385 if (isset($variables['image_style']) && !empty($variables['image_style'])) {
386 $img = theme('image_style', $variables);
387 $img = str_replace('<img', '', $img);
388 $img = str_replace('/>', '', $img);
389 $images[] = array(
390 'image' => $img,
391 );
392 }
393
394 // All breakpoints and multipliers.
395 if (isset($variables['breakpoints']['mapping'])) {
396 foreach ($variables['breakpoints']['mapping'] as $breakpoint_name => $multipliers) {
397 $breakpoint = breakpoints_breakpoint_load_by_fullkey($breakpoint_name);
398 if ($breakpoint) {
399 $new_images = array();
400 foreach ($multipliers as $multiplier => $image_style) {
401 $new_image = $variables;
402 // Add classes to ease styling
403 $new_image['attributes']['class'][] = RESP_IMG_CLASS . '-' . drupal_clean_css_identifier($breakpoint->name);
404 $new_image['style_name'] = $image_style;
405 $new_image['#multiplier'] = $multiplier;
406 $new_images[] = $new_image;
407 }
408 $img = theme('image_style', $new_images[0]);
409 $img = str_replace('<img', '', $img);
410 $img = str_replace('/>', '', $img);
411
412 // Only one image, output as src.
413 if (count($new_images) == 1) {
414 $images[] = array(
415 'image' => $img,
416 'media' => $breakpoint->breakpoint,
417 );
418 }
419 else {
420 // Mutliple images, output as srcset.
421 $srcset = array();
422 foreach ($new_images as $new_image) {
423 $srcset[] = image_style_url($new_image['style_name'], $new_image['uri']) . ' ' . $new_image['#multiplier'];
424 }
425 $img = preg_replace('/src="[^"]*"/', '', $img);
426 $images[] = array(
427 'srcset' => implode(', ', $srcset),
428 'media' => $breakpoint->breakpoint,
429 'image' => $img,
430 );
431 }
432 }
433 }
434 }
435
436 if (!empty($images)) {
437 $output[] = '<picture class="' . RESP_IMG_CLASS . '" alt="' . check_plain($variables['alt']) . '" title="' . check_plain($variables['title']) . '">';
438
439 // add variants to the output
440 foreach ($images as $image) {
441 if (isset($image['media']) && !empty($image['media'])) {
442 if (!isset($image['srcset'])) {
443 $output[] = '<!-- <source media="' . $image['media'] . '" ' . $image['image'] . ' /> -->';
444 $output[] = '<source media="' . $image['media'] . '" ' . $image['image'] . ' />';
445 }
446 else {
447 $output[] = '<!-- <source media="' . $image['media'] . '" srcset="' . $image['srcset'] . '" ' . $image['image'] . ' /> -->';
448 $output[] = '<source media="' . $image['media'] . '" srcset="' . $image['srcset'] . '" ' . $image['image'] . ' />';
449 }
450 }
451 else {
452 $output[] = '<!-- <source ' . $image['image'] . ' /> -->';
453 $output[] = '<source ' . $image['image'] . ' />';
454 }
455 }
456
457 // output the default image as fallback
458 // $output .= '<img src="' . image_style_url($variables['style_name'], $variables['uri']) . '" alt="' . check_plain($variables['alt']) . '" />';
459 $output[] = '<noscript><img ' . $images[0]['image'] . '/></noscript>';
460 $output[] = '</picture>';
461 return implode("\n", $output);
462 }
463 }
464
465 /**
466 * colorbox_picture_formatter similar to colorbox_image_formatter.
467 *
468 * only differences are:
469 * 'breakpoints' => $variables['breakpoints'],
470 * is the last line.
471 */
472 function theme_colorbox_picture_formatter($variables) {
473 $item = $variables['item'];
474 $node = $variables['node'];
475 $field = $variables['field'];
476 $settings = $variables['display_settings'];
477
478 $image = array(
479 'path' => $item['uri'],
480 'alt' => $item['alt'],
481 'title' => $item['title'],
482 'style_name' => $settings['colorbox_node_style'],
483 'breakpoints' => $variables['breakpoints'],
484 );
485
486 if (isset($item['width']) && isset($item['height'])) {
487 $image['width'] = $item['width'];
488 $image['height'] = $item['height'];
489 }
490
491 switch ($settings['colorbox_caption']) {
492 case 'auto':
493 // If the title is empty use alt or the node title in that order.
494 if (!empty($image['title'])) {
495 $caption = $image['title'];
496 }
497 elseif (!empty($image['alt'])) {
498 $caption = $image['alt'];
499 }
500 elseif (!empty($node->title)) {
501 $caption = $node->title;
502 }
503 else {
504 $caption = '';
505 }
506 break;
507 case 'title':
508 $caption = $image['title'];
509 break;
510 case 'alt':
511 $caption = $image['alt'];
512 break;
513 case 'node_title':
514 $caption = $node->title;
515 break;
516 case 'custom':
517 $caption = token_replace($settings['colorbox_caption_custom'], array('node' => $node));
518 break;
519 default:
520 $caption = '';
521 }
522
523 // Shorten the caption for the example styles or when caption shortening is active.
524 $colorbox_style = variable_get('colorbox_style', 'default');
525 $trim_length = variable_get('colorbox_caption_trim_length', 75);
526 if (((strpos($colorbox_style, 'colorbox/example') !== FALSE) || variable_get('colorbox_caption_trim', 0)) && (drupal_strlen($caption) > $trim_length)) {
527 $caption = drupal_substr($caption, 0, $trim_length - 5) . '...';
528 }
529
530 // Build the gallery id.
531 $nid = !empty($node->nid) ? $node->nid : 'nid';
532 switch ($settings['colorbox_gallery']) {
533 case 'post':
534 $gallery_id = 'gallery-' . $nid;
535 break;
536 case 'page':
537 $gallery_id = 'gallery-all';
538 break;
539 case 'field_post':
540 $gallery_id = 'gallery-' . $nid . '-' . $field['field_name'];
541 break;
542 case 'field_page':
543 $gallery_id = 'gallery-' . $field['field_name'];
544 break;
545 case 'custom':
546 $gallery_id = $settings['colorbox_gallery_custom'];
547 break;
548 default:
549 $gallery_id = '';
550 }
551
552 if ($style_name = $settings['colorbox_image_style']) {
553 $path = image_style_url($style_name, $image['path']);
554 }
555 else {
556 $path = file_create_url($image['path']);
557 }
558
559 return theme('colorbox_picturefield', array('image' => $image, 'path' => $path, 'title' => $caption, 'gid' => $gallery_id));
560 }
561
562 /**
563 * theme_colorbox_picturefield similar to theme_colorbox_imagefield.
564 *
565 * only difference is: $image = theme('picture', $variables['image']);.
566 */
567 function theme_colorbox_picturefield($variables) {
568 $class = array('colorbox');
569
570 if ($variables['image']['style_name'] == 'hide') {
571 $image = '';
572 $class[] = 'js-hide';
573 }
574 elseif (!empty($variables['image']['style_name'])) {
575 $image = theme('picture', $variables['image']);
576 }
577 else {
578 $image = theme('image', $variables['image']);
579 }
580
581 $options = array(
582 'html' => TRUE,
583 'attributes' => array(
584 'title' => $variables['title'],
585 'class' => implode(' ', $class),
586 'rel' => $variables['gid'],
587 )
588 );
589
590 return l($image, $variables['path'], $options);
591 }
592
593 /**
594 * Implements hook_field_formatter_info_alter().
595 */
596 function resp_img_field_formatter_info_alter(&$info) {
597 foreach ($info as $formatter_key => &$formatter) {
598 if ($formatter_key == 'image') {
599 if (!isset($formatter['settings']) || !is_array($formatter['settings'])) {
600 $formatter['settings'] = array();
601 }
602 }
603 }
604 }
605
606 /**
607 * Implements hook_image_default_styles().
608 */
609 function resp_img_image_default_styles() {
610 $styles = array();
611 // Provide fake responsive image styles for users to select.
612 $breakpoint_groups = breakpoints_breakpoint_group_load_all();
613 if ($breakpoint_groups && !empty($breakpoint_groups)) {
614 foreach (array_keys($breakpoint_groups) as $machine_name) {
615 $styles[RESP_IMG_STYLE_PREFIX . $machine_name] = array(
616 'effects' => array(),
617 );
618 }
619 }
620 return $styles;
621 }
622
623 /**
624 * Implements hook_image_styles_alter().
625 */
626 function resp_img_image_styles_alter(&$styles) {
627 $breakpoint_groups = breakpoints_breakpoint_group_load_all();
628 if ($breakpoint_groups && !empty($breakpoint_groups)) {
629 foreach ($breakpoint_groups as $machine_name => $breakpoint_group) {
630 $mapping = _resp_img_get_breakpoint_styles($machine_name);
631 $first_style = FALSE;
632 if (!empty($mapping)) {
633 $first_style = reset(reset($mapping['mapping']));
634 }
635 if ($first_style) {
636 $first_style = isset($styles[$first_style]) ? $styles[$first_style] : FALSE;
637 }
638 if ($first_style) {
639 $new_effects = array();
640 foreach ($first_style['effects'] as $effect) {
641 $new_effect = $effect;
642 unset($new_effect['isid']);
643 unset($new_effect['ieid']);
644 $new_effects[] = $new_effect;
645 }
646 $styles[RESP_IMG_STYLE_PREFIX . $machine_name]['effects'] = $new_effects;
647 }
648 }
649 }
650 }
651
652 /**
653 * Implements MODULE_preprocess_HOOK().
654 */
655 function resp_img_preprocess_image_style_list(&$variables) {
656 $variables['styles'] = array_filter($variables['styles'], '_resp_img_filter_styles');
657 }
658
659 /**
660 * array_filter callback.
661 */
662 function _resp_img_filter_styles($var) {
663 return strpos(is_array($var) ? $var['name'] : $var, RESP_IMG_STYLE_PREFIX) !== 0;
664 }
665
666 /**
667 * Implements hook_field_formatter_settings_summary_alter().
668 */
669 function resp_img_field_formatter_settings_summary_alter(&$summary, $context) {
670 if (isset($context['field']['type']) && $context['field']['type'] === 'image') {
671 $settings = $context['instance']['display'][$context['view_mode']]['settings'];
672 if (isset($settings['image_style']) && strpos($settings['image_style'], RESP_IMG_STYLE_PREFIX) !== FALSE) {
673 $group_name = drupal_substr($settings['image_style'], drupal_strlen(RESP_IMG_STYLE_PREFIX));
674 $summary = 'Responsive mode activated using ' . $group_name;
675 }
676 if (isset($settings['colorbox_node_style']) && strpos($settings['colorbox_node_style'], RESP_IMG_STYLE_PREFIX) !== FALSE) {
677 $group_name = drupal_substr($settings['colorbox_node_style'], drupal_strlen(RESP_IMG_STYLE_PREFIX));
678 $summary .= '<br />Responsive mode activated using ' . $group_name;
679 }
680 }
681 }
682
683 function resp_img_entity_view_alter(&$build, $type) {
684 foreach (element_children($build) as $child) {
685 if (isset($build[$child]['#field_name'])) {
686 $build[$child]['#post_render'][] = 'resp_img_post_render';
687 }
688 }
689 }
690
691 /**
692 * #post_render callback.
693 */
694 function resp_img_post_render($content, $element) {
695 return _resp_img_replace_picture($content);
696 }
697
698 function _resp_img_replace_picture($content) {
699 $result = array();
700 preg_match_all('/<img[^>]*>/i', $content, $result);
701 $orig_imgs = $imgs = $result[0];
702 $vars['image_style'] = 'image_style';
703 $vars['#formatter'] = 'picture';
704 $vars['#theme'] = 'picture_formatter';
705 foreach ($imgs as &$img) {
706 if (strpos($img, RESP_IMG_STYLE_PREFIX) !== FALSE) {
707 $xml = simplexml_load_string('<image>' . html_entity_decode($img, ENT_QUOTES, "utf-8") . '</image>');
708 if (isset($xml->img[0]) && is_object($xml->img[0])) {
709 $attributes = array();
710 foreach ($xml->img[0]->attributes() as $a => $b) {
711 $attributes[$a] = (string)$b;
712 }
713 }
714
715 if (isset($attributes['src']) && !empty($attributes['src'])) {
716 $group_name = drupal_substr($attributes['src'], strpos($attributes['src'], RESP_IMG_STYLE_PREFIX));
717 $group_name = str_replace(RESP_IMG_STYLE_PREFIX, '', drupal_substr($group_name, 0, strpos($group_name, '/')));
718 $breakpoint_styles = _resp_img_get_breakpoint_styles($group_name);
719
720 // @todo: Ugly! Find a better way?
721 $src = drupal_substr($attributes['src'], strpos($attributes['src'], RESP_IMG_STYLE_PREFIX . $group_name) + drupal_strlen(RESP_IMG_STYLE_PREFIX . $group_name) + 1);
722 $src = preg_replace('/\//', '://', $src, 1);
723 unset($attributes['src']);
724 $variables = array(
725 'path' => $src,
726 'breakpoints' => $breakpoint_styles,
727 );
728 if (isset($attributes['width'])) {
729 $variables['width'] = $attributes['width'];
730 unset($attributes['width']);
731 }
732 if (isset($attributes['height'])) {
733 $variables['height'] = $attributes['height'];
734 unset($attributes['height']);
735 }
736 $variables['attributes'] = $attributes;
737 if (isset($variables['attributes']['class'])) {
738 $variables['attributes']['class'] = explode(' ', $variables['attributes']['class']);
739 }
740 $variables['style_name'] = RESP_IMG_STYLE_PREFIX . $group_name;
741 $img = theme('picture', $variables);
742 }
743 }
744 }
745 $content = str_replace($orig_imgs, $imgs, $content);
746 return $content;
747 }
748
749 function _resp_img_get_breakpoint_styles($group_name) {
750 $active_breakpoints = &drupal_static('resp_img_breakpoints', FALSE);
751 if (!$active_breakpoints) {
752 $active_breakpoints = breakpoints_breakpoint_load_all_active();
753 }
754 $breakpoint_styles = array();
755 if ($mappings = resp_img_mapping_load('mappings.' . $group_name)) {
756 $group = breakpoints_breakpoint_group_load($group_name);
757 $breakpoints = array_intersect_key(drupal_map_assoc($group->breakpoints), $active_breakpoints);
758 $mappings->mapping = array_intersect_key($mappings->mapping, $breakpoints);
759 foreach ($mappings->mapping as $breakpoint_name => $multipliers) {
760 $settings = breakpoints_settings();
761 $existing_multipliers = drupal_map_assoc($settings->multipliers);
762 $multipliers = array_intersect_key($multipliers, array_intersect_key($existing_multipliers, array_filter($active_breakpoints[$breakpoint_name]->multipliers)));
763 if (!empty($multipliers) && is_array($multipliers)) {
764 foreach ($multipliers as $multiplier => $image_style) {
765 if (!empty($image_style)) {
766 if (!isset($breakpoint_styles['mapping'][$breakpoint_name])) {
767 $breakpoint_styles['mapping'][$breakpoint_name] = array();
768 }
769 $breakpoint_styles['mapping'][$breakpoint_name][$multiplier] = $image_style;
770 }
771 }
772 }
773 }
774 }
775 return $breakpoint_styles;
776 }