Pathologic was missing because of a .git folder inside.
[yaffs-website] / web / modules / contrib / advagg / advagg_mod / advagg_mod.module
1 <?php
2
3 /**
4  * @file
5  * Advanced aggregation modifier module.
6  */
7
8 // Core hook implementations.
9 /**
10  * Implements hook_js_alter().
11  */
12 function advagg_mod_js_alter(&$js) {
13   if (\Drupal::moduleHandler()->moduleExists('advagg') && !advagg_enabled()) {
14     return;
15   }
16   $config = \Drupal::config('advagg_mod.settings');
17
18   $css_defer = $config->get('css_defer');
19
20   // Use the current file system path for advagg_mod.
21   $module_path = drupal_get_path('module', 'advagg_mod');
22   if (advagg_mod_css_defer_active() && isset($js[$module_path . '/js/loadCSS.js'])) {
23     if ($css_defer == 3) {
24       $js[$module_path . '/js/loadCSS.js']['scope'] = 'header';
25       $js[$module_path . '/js/css_defer.js']['scope'] = 'header';
26     }
27     $css_defer_js_code = $config->get('css_defer_js_code');
28     if ($css_defer_js_code == 0) {
29       $js[$module_path . '/js/loadCSS.js']['inline'] = TRUE;
30       $js[$module_path . '/js/css_defer.js']['inline'] = TRUE;
31     }
32     elseif ($css_defer_js_code == 4) {
33       $js[$module_path . '/js/loadCSS.js']['type'] = 'external';
34       $js[$module_path . '/js/loadCSS.js']['data'] = '//cdn.rawgit.com/filamentgroup/loadCSS/master/src/loadCSS.js';
35     }
36   }
37
38   // Change sort order so aggregates do not get split up.
39   if ($config->get('js_adjust_sort_external') || $config->get('js_adjust_sort_browsers')) {
40     advagg_mod_sort_css_js($js, 'js');
41   }
42
43   // Move JS to the footer.
44   if ($config->get('js_footer')) {
45     advagg_mod_js_move_to_footer($js);
46   }
47
48   // Force all JS to be preprocessed.
49   if ($config->get('js_preprocess')) {
50     foreach ($js as $path => &$values) {
51       // However CKEditor must not be combined or errors *will* occur.
52       if ($path == 'core/assets/vendor/ckeditor/ckeditor.js') {
53         continue;
54       }
55       $values['preprocess'] = TRUE;
56       $values['cache'] = TRUE;
57     }
58     unset($values);
59   }
60
61   // Add the defer or the async tag to JS.
62   advagg_mod_js_async_defer($js);
63
64   // Move all async JS to the header.
65   if ($config->get('js_async_in_header')) {
66     foreach ($js as &$values) {
67       // Skip if not file or external.
68       if ($values['type'] !== 'file' && $values['type'] !== 'external') {
69         continue;
70       }
71       // Skip if not async.
72       if (empty($values['async']) && empty($values['attributes']['async'])) {
73         continue;
74       }
75
76       // Move to the header with a group of 1000.
77       $values['scope'] = 'header';
78       $values['group'] = 1000;
79     }
80     unset($values);
81   }
82 }
83
84 /**
85  * Implements hook_css_alter().
86  */
87 function advagg_mod_css_alter(&$css) {
88   if (\Drupal::moduleHandler()->moduleExists('advagg') && !advagg_enabled()) {
89     return;
90   }
91   $config = \Drupal::config('advagg_mod.settings');
92   if ($config->get('css_adjust_sort_external') || $config->get('css_adjust_sort_browsers')) {
93     advagg_mod_sort_css_js($css, 'css');
94   }
95
96   // Force all CSS to be preprocessed.
97   if ($config->get('css_preprocess')) {
98     foreach ($css as &$values) {
99       $values['preprocess'] = TRUE;
100     }
101     unset($values);
102   }
103 }
104
105 /**
106  * Implements hook_page_attachments_alter().
107  */
108 function advagg_mod_page_attachments_alter(array &$page) {
109   if (advagg_mod_css_defer_active()) {
110     $page['#attached']['library'][] = 'advagg_mod/css_defer';
111   }
112 }
113
114 // AdvAgg hook implementations.
115 /**
116  * Implements hook_advagg_current_hooks_hash_array_alter().
117  */
118 function advagg_mod_advagg_current_hooks_hash_array_alter(array &$aggregate_settings) {
119   $aggregate_settings['variables']['advagg_mod'] = \Drupal::config('advagg_mod.settings')->get();
120 }
121
122 /**
123  * Implements hook_advagg_asset_render_alter().
124  */
125 function advagg_mod_advagg_asset_render_alter(&$assets, $render_type, $asset_type) {
126   if (!advagg_enabled()) {
127     return;
128   }
129
130   if ($render_type == 'html') {
131     if ($asset_type == 'styles') {
132       foreach ($assets as &$value) {
133         if (!empty($value['#inline'])) {
134           $value['#value'] = @file_get_contents($value['#attributes']['href']);
135           if ($value['#value']) {
136             unset($value['#attributes']['href']);
137           }
138         }
139         elseif (advagg_mod_css_defer_active()) {
140           // Skip prefetch links and inline styles.
141           if ($value['#tag'] == 'style') {
142             continue;
143           }
144           $value['#attributes']['class'][] = 'advagg-css-defer';
145           $value['#noscript'] = TRUE;
146         }
147       }
148       unset($value);
149     }
150     elseif ($asset_type == 'scripts' || $asset_type == 'scripts_bottom') {
151       foreach ($assets as &$value) {
152         if (!empty($value['#inline'])) {
153           $value['#value'] = @file_get_contents($value['#attributes']['src']);
154           if ($value['#value']) {
155             unset($value['#attributes']['src']);
156           }
157         }
158       }
159     }
160   }
161 }
162
163 /**
164  * Implements hook_advagg_hooks_implemented_alter().
165  */
166 function advagg_mod_advagg_hooks_implemented_alter(&$hooks, $all) {
167   if ($all) {
168     $hooks += [
169       'advagg_mod_get_lists_alter' => [],
170     ];
171   }
172 }
173
174 /**
175  * Implements hook_advagg_asset_path_alter().
176  */
177 function advagg_mod_advagg_asset_path_alter(&$path, $extension) {
178   if ($dir = rtrim(\Drupal::config('advagg_mod.settings')->get('unified_multisite_dir'), '/')) {
179     if ($extension == 'js') {
180       $path = $dir . '/js';
181     }
182     elseif ($extension == 'css') {
183       $path = $dir . '/css';
184     }
185   }
186 }
187
188 // Helper Functions.
189 /**
190  * Generate a list of rules and exceptions for js files.
191  *
192  * Controls no async/defer file list.
193  *
194  * @return array
195  *   A multidimensional array.
196  */
197 function advagg_mod_get_lists() {
198   $lists = &drupal_static(__FUNCTION__);
199   if (!isset($lists)) {
200     // Do not defer/async list.
201     $no_async_defer_list = [
202       // Wistia js.
203       '//fast.wistia.',
204       // Maps.
205       '//maps.googleapis.com',
206       '//dev.virtualearth.net',
207       '//api.maps.yahoo.com',
208     ];
209     $no_move = [
210       '//cdn.rawgit.com/stubbornella/csslint/master/release/csslint.js',
211     ];
212
213     // Allow other modules to add/edit the above lists.
214     // Call hook_advagg_mod_get_lists_alter().
215     $lists = [
216       $no_async_defer_list,
217       $no_move,
218     ];
219     \Drupal::moduleHandler()->alter('advagg_mod_get_lists', $lists);
220   }
221   return $lists;
222 }
223
224 /**
225  * Move JS to the footer.
226  *
227  * @param array $js
228  *   JS array.
229  */
230 function advagg_mod_js_move_to_footer(array &$js) {
231   // Move all JS to the footer.
232   $move_js_to_footer = \Drupal::config('advagg_mod.settings')->get('js_footer');
233   $core_header_js = [
234     'core/assets/vendor/modernizr/modernizr.min.js' => 0,
235     'core/assets/vendor/html5shiv/html5shiv.min.js' => 0,
236   ];
237
238   foreach ($js as $key => &$values) {
239     // Skip if a core header file and configured to do so.
240     if ($move_js_to_footer == 3 && isset($core_header_js[$key])) {
241       continue;
242     }
243
244     // Skip if the scope has been locked.
245     if (!empty($values['scope_lock'])) {
246       continue;
247     }
248
249     // If JS is not in the header decrease weight by 10000.
250     if ($values['scope'] === 'header') {
251       $values['weight'] -= 10000;
252     }
253     // If JS is already in the footer decrease weight by 10000.
254     if ($values['scope'] !== 'footer') {
255       $values['weight'] -= 10000;
256     }
257     $values['scope'] = 'footer';
258   }
259   unset($values);
260 }
261
262 /**
263  * Add the defer and or the async tag to js.
264  *
265  * @param array $js
266  *   JS array.
267  */
268 function advagg_mod_js_async_defer(array &$js) {
269   // Return early if this is disabled.
270   $config = \Drupal::config('advagg_mod.settings');
271   $defer = $config->get('js_defer');
272   $async = $config->get('js_async');
273   list($no_async_defer_list) = advagg_mod_get_lists();
274
275   // Make all scripts defer and/or async.
276   foreach ($js as $name => &$values) {
277     $values['attributes'] = [];
278     // Defer all scripts.
279     if ($defer) {
280       $values['attributes']['defer'] = TRUE;
281
282       // Do not defer external scripts setting.
283       if ($defer == 2 && $values['type'] === 'external') {
284         unset($values['attributes']['defer']);
285       }
286     }
287
288     // Async all scripts. On most browsers this will run instead of defer.
289     // On some older browsers if defer is also set they will run that instead
290     // if they don't support async.
291     if ($async) {
292       $values['attributes']['async'] = TRUE;
293     }
294
295     // No async defer list.
296     foreach ($no_async_defer_list as $search_string) {
297       if (strpos($name, $search_string) !== FALSE) {
298         // Do not defer/async the loading this script.
299         if ($defer) {
300           unset($values['attributes']['async'], $values['attributes']['defer']);
301         }
302       }
303     }
304   }
305   unset($values);
306 }
307
308 /**
309  * Rearrange CSS/JS so that aggregates are better grouped.
310  *
311  * This can move all external assets to the top, thus in one group.
312  * This can move all browser conditional assets together.
313  *
314  * @param array $assets
315  *   The CSS or JS array.
316  * @param string $type
317  *   String: css or js.
318  */
319 function advagg_mod_sort_css_js(array &$assets, $type) {
320   $config = \Drupal::config('advagg_mod.settings');
321   if ($config->get($type . '_adjust_sort_external')) {
322     // Find all external items.
323     $external = [];
324     $group = NULL;
325     $weight = NULL;
326     foreach ($assets as $key => $value) {
327       // Set values if not set.
328       if (is_null($group)) {
329         $group = $value['group'];
330       }
331       if (is_null($weight)) {
332         $weight = $value['weight'];
333       }
334
335       // Find "lightest" item.
336       if ($value['group'] < $group) {
337         $group = $value['group'];
338       }
339       if ($value['weight'] < $weight) {
340         $weight = $value['weight'];
341       }
342
343       list(, $no_move) = advagg_mod_get_lists();
344       if (!empty($value['type']) && $value['type'] === 'external' && !in_array($key, $no_move) && empty($value['movable'])) {
345         $external[$key] = $value;
346         unset($assets[$key]);
347       }
348     }
349     // Sort the array so that it appears in the correct order.
350     advagg_drupal_sort_css_js_stable($external);
351
352     // Group all external together.
353     $offset = 0.0001;
354     $weight -= 1;
355     $group -= 10;
356     $found_jquery = FALSE;
357     foreach ($external as $key => $value) {
358
359       // If bootstrap is used, it must be loaded after jquery. Don't move
360       // bootstrap if jquery is not above it.
361       if ($key == 'assets/vendor/jquery/jquery.min.js') {
362         $found_jquery = TRUE;
363       }
364       if (!$found_jquery && (strpos($value['data'], 'bootstrap.min.js') !== FALSE || strpos($value['data'], 'bootstrap.js') !== FALSE)) {
365         $assets[$key] = $value;
366         continue;
367       }
368       $value['group'] = $group;
369       $value['weight'] = $weight;
370       $weight += $offset;
371       $assets[$key] = $value;
372     }
373   }
374
375   if ($config->get($type . '_adjust_sort_browsers')) {
376     // Get a list of browsers.
377     $browsers_list = [];
378     foreach ($assets as $key => $value) {
379       if (isset($value['browsers']['IE']) && $value['browsers']['IE'] !== TRUE) {
380         $browsers_list['IE'][] = $value['browsers']['IE'];
381       }
382     }
383
384     // Group browsers CSS together.
385     if (isset($browsers_list['IE'])) {
386       $browsers_list['IE'] = array_values(array_unique($browsers_list['IE']));
387       foreach ($browsers_list['IE'] as $browser) {
388         $browsers = [];
389         $group = NULL;
390         $weight = NULL;
391         foreach ($assets as $key => $value) {
392           if (isset($value['browsers']['IE']) && $browser === $value['browsers']['IE']) {
393             // Set values if not set.
394             if (is_null($group)) {
395               $group = $value['group'];
396             }
397             if (is_null($weight)) {
398               $weight = $value['weight'];
399             }
400
401             // Find "heaviest" item.
402             if ($value['group'] > $group) {
403               $group = $value['group'];
404             }
405             if ($value['weight'] > $weight) {
406               $weight = $value['weight'];
407             }
408
409             $browsers[$key] = $value;
410             unset($assets[$key]);
411           }
412         }
413
414         // Sort the array so that it appears in the correct order.
415         advagg_drupal_sort_css_js_stable($browsers);
416
417         // Group all browsers together.
418         $offset = 0.0001;
419         $group += 1000;
420         foreach ($browsers as $key => $value) {
421           if (isset($value['movable']) && empty($value['movable'])) {
422             $assets[$key] = $value;
423             continue;
424           }
425           $value['group'] = $group;
426           $value['weight'] = $weight;
427           $weight += $offset;
428           $assets[$key] = $value;
429         }
430       }
431     }
432   }
433 }
434
435 /**
436  * Determines whether css defering should be active for the current request.
437  */
438 function advagg_mod_css_defer_active() {
439   $config = \Drupal::config('advagg_mod.settings');
440   if (!$config->get('css_defer')) {
441     return FALSE;
442   }
443   $admin_route = \Drupal::service('router.admin_context')->isAdminRoute();
444   if ($admin_route && !$config->get('css_defer_admin')) {
445     return FALSE;
446   }
447   return TRUE;
448 }