Implements hook_advagg_modify_css_pre_render_alter().

Related topics

File

advagg_mod/advagg_mod.module, line 905

Code

function advagg_mod_advagg_modify_css_pre_render_alter(&$children, &$elements) {
    // Skip if there is no css.
    if (empty($children)) {
        return;
    }
    if (!module_exists('advagg') || !advagg_enabled()) {
        return;
    }
    // Return early if this setting is disabled.
    list(, , , , , , , , , , $css_defer) = advagg_mod_get_lists(array(), $elements['#items']);
    if (empty($css_defer)) {
        return;
    }
    $critical_css = FALSE;
    // Only check for the critical-css key if configured to do so.
    if (variable_get('advagg_mod_css_defer_visibility', ADVAGG_MOD_VISIBILITY_LISTED) == ADVAGG_MOD_VISIBILITY_FILE_CONTROLLED) {
        foreach ($elements['#items'] as $item) {
            if ($item['type'] === 'inline' && !empty($item['critical-css'])) {
                $critical_css = TRUE;
                break;
            }
        }
        // Return early if there's no critical css for the path and deferring is
        // file controlled.
        if (!$critical_css) {
            return;
        }
    }
    if (!$critical_css) {
        // Return early if we're in a page that is not specified in the settings for
        // specific pages.
        if (!advagg_mod_css_defer_page()) {
            return;
        }
        // Return early if we're in the admin theme and this setting is disabled.
        $css_defer_admin = variable_get('advagg_mod_css_defer_admin', ADVAGG_MOD_CSS_DEFER_ADMIN);
        if (empty($css_defer_admin) && path_is_admin(current_path())) {
            return;
        }
    }
    // Modify css.
    static $added;
    advagg_mod_add_loadcss_js_lib(array(), $elements['#items']);
    // Wrap CSS in noscript tags.
    $defer_skip_first_file = variable_get('advagg_mod_css_defer_skip_first_file', ADVAGG_MOD_CSS_DEFER_SKIP_FIRST_FILE);
    $options = array(
        'type' => 'inline',
        'scope' => $css_defer >= 5 ? 'footer' : 'header',
        'scope_lock' => TRUE,
        'group' => $css_defer == 1 ? JS_LIBRARY - 1 : JS_DEFAULT,
        'weight' => $css_defer == 1 ? -50000 : 0,
        'movable' => $css_defer == 1 ? FALSE : TRUE,
    );
    // Get the key of the last css file that will use loadcss.
    $last_key = NULL;
    foreach ($children as $children_key => $values) {
        // Do not count inline styles.
        if ($values['#tag'] === 'style' || empty($values['#attributes']['href'])) {
            continue;
        }
        // Only use if no browser conditionals.
        if (isset($values['#browsers']['!IE']) && $values['#browsers']['!IE'] === TRUE && isset($values['#browsers']['IE']) && $values['#browsers']['IE'] === TRUE && isset($values['#attributes']['media']) && $values['#attributes']['media'] !== 'print' && $values['#attributes']['media'] !== 'none') {
            $last_key = $children_key;
        }
    }
    // If all css uses a browser conditional, then use the last one to release.
    if ($last_key === NULL) {
        $last_key = $children_key;
    }
    $preload_array = array();
    foreach ($children as $children_key => &$values) {
        // Do not defer inline styles.
        if ($values['#tag'] === 'style' || empty($values['#attributes']['href'])) {
            continue;
        }
        if (empty($preload_array) && $defer_skip_first_file == 2) {
            $preload_array[] = array();
            continue;
        }
        // If this is the last CSS file release the hold on jquery.ready.
        $onload_extra = '';
        if ($last_key === $children_key) {
            // Run holdready once it is defined.
            $holdready_script = 'window.advagg_mod_loadcss = function() {if (window.jQuery) {if (jQuery.isFunction(jQuery.holdReady)){jQuery.holdReady(false);}} else {setTimeout(advagg_mod_loadcss, 100);}};';
            $onload_extra = "{$holdready_script}setTimeout(advagg_mod_loadcss, 200);";
            $GLOBALS['advagg_mod_loadcss_jquery_holdready'] = TRUE;
        }
        $id = "advagg_loadcss_{$children_key}";
        if ($css_defer == 4) {
            $copy = $values;
            $copy['#attributes']['rel'] = 'preload';
            $copy['#attributes']['as'] = 'style';
            $copy['#attributes']['onload'] = "{$onload_extra}this.onload=null;this.rel='stylesheet'";
            $preload_array[$children_key] = $copy;
        }
        else {
            // Add browsers to the js options.
            if (isset($values['#browsers'])) {
                $options['browsers'] = $values['#browsers'];
            }
            // Create loadCSS wrapper code.
            $inline = "loadCSS(\"{$values['#attributes']['href']}\", document.getElementById(\"{$id}\")";
            if ($values['#attributes']['media'] !== 'all') {
                $inline .= ", \"{$values['#attributes']['media']}\"";
            }
            if (!empty($values['#attributes']['crossorigin'])) {
                $inline .= ", \"{$values['#attributes']['crossorigin']}\"";
            }
            $inline .= ')';
            // Create onloadCSS wrapper code.
            if (!empty($values['#attributes']['onloadCSS'])) {
                $inline = "onloadCSS({$inline}, function() {{$onload_extra}{$values['#attributes']['onloadCSS']}});";
            }
            elseif (!empty($onload_extra)) {
                $inline = "onloadCSS({$inline}, function() {{$onload_extra}});";
            }
            // Make code work if loader code is below loadcss calls.
            $matches[2] = $matches[0] = $inline;
            $inline = advagg_mod_wrap_inline_js($matches, "window.loadCSS", 40);
            // Add in script tags to load css via js.
            if (!isset($added[$values['#attributes']['href']])) {
                drupal_add_js($inline, $options);
                $added[$values['#attributes']['href']] = TRUE;
            }
        }
        // Wrap current css in noscript tags.
        $values['#prefix'] = "<noscript id=\"{$id}\">\n";
        $values['#suffix'] = '</noscript>';
        // Reset for next item in loop.
        if (isset($options['browsers'])) {
            unset($options['browsers']);
        }
    }
    unset($values);
    // Add in the element after the noscript element keeping the css order.
    $new_elements = array();
    foreach ($elements as $elements_key => $elements_value) {
        // Build old array.
        if (is_numeric($elements_key)) {
            $new_elements[] = $elements_value;
        }
        else {
            $new_elements[$elements_key] = $elements_value;
        }
        // Splice in new data.
        if (isset($preload_array[$elements_key])) {
            $new_elements[] = $preload_array[$elements_key];
        }
    }
    $elements = $new_elements;
    unset($new_elements);
}