plus-8.x-4.x-dev/plus.7.php

plus.7.php
<?php

/**
 * @file
 * Drupal 7 module hooks/alters for the Drupal+ module.
 */

use Drupal\plus\Utility\Element;

/**
 * Implements hook_boot().
 */
function plus_boot() {
  // Because drupal_theme_initialize() is invoked before hook_init(), it adds
  // any theme JavaScript using drupal_add_js(), which in turn invokes
  // drupal_add_library() to add jQuery to the page. In order to prevent any
  // premature invocation of drupal_add_library(), set the static now and
  // just go ahead and define the default drupalSettings which is a backport
  // from Drupal 8.
  $javascript = &drupal_static('drupal_add_js', []);
  drupal_static('drupal_add_js:jquery_added', TRUE);
  $javascript = drupal_array_merge_deep($javascript, [
    'settings' => [
      'data' => [],
      'type' => 'setting',
      'scope' => 'header',
      'scope_lock' => TRUE,
      'group' => JS_CORE,
      'every_page' => TRUE,
    ],
  ]);
}

/**
 * Implements hook_page_delivery_callback_alter().
 *
 * {@inheritdoc}
 */
function plus_page_delivery_callback_alter(&$callback) {
  if (variable_get('plus_deliver_html_drupal8', TRUE)) {
    switch ($callback) {
      case 'drupal_deliver_html_page':
        $callback = 'plus_deliver_html_page';
        break;

      case 'ajax_deliver':
        $callback = 'plus_ajax_deliver';
        break;
    }
  }
}

/**
 * Delivers an HTML response.
 *
 * @param $page_callback_result
 *   The page callback result.
 *
 * @todo Use Drupal 8 HTML delivery to take advantage of render array and
 * library/asset improvements.
 */
function plus_deliver_html_page($page_callback_result) {
  drupal_deliver_html_page($page_callback_result);
}

/**
 * Delivers an Ajax response.
 *
 * @param $page_callback_result
 *   The page callback result.
 *
 * @todo Use Drupal 8 ajax delivery to take advantage of render array and
 * library/asset improvements.
 */
function plus_ajax_deliver($page_callback_result) {
  ajax_deliver($page_callback_result);
}

/**
 * Callback for dynamically invoking Drupal 7 #pre_render callbacks.
 *
 * @param array $element
 *   The render array element.
 *
 * @return array
 *   The modified render array element.
 *
 * @see \Drupal\plus\Utility\Element::addCallback()
 */
function plus_element_pre_render_callback(array $element) {
  $callbacks = Element::reference($element)->getProperty('plus_pre_render', []);
  foreach ($callbacks as $callback) {
    $element = call_user_func_array($callback, [$element]);
  }
  return $element;
}

/**
 * Implements hook_js_settings_alter().
 */
function plus_js_settings_alter(array &$settings) {
  global $language;
  global $theme;

  // url() generates the prefix using hook_url_outbound_alter(). Instead of
  // running the hook_url_outbound_alter() again here, extract the prefix
  // from url().
  $path_prefix = '';
  url('', ['prefix' => &$path_prefix]);

  $base_path = base_path();
  $current_path = current_path();

  $path_settings = [
    'baseUrl' => $base_path,
    'pathPrefix' => $path_prefix,
    'currentPath' => $current_path,
    'currentPathIsAdmin' => path_is_admin($current_path),
    'isFront' => drupal_is_front_page(),
    'currentLanguage' => $language->language,
  ];

  // Only set values that haven't been set already.
  foreach ($path_settings as $key => $value) {
    if (!isset($settings['path'][$key])) {
      $settings['path'][$key] = $value;
    }
  }

  // Add the theme token to ajaxPageState, ensuring the database is available
  // before doing so. Also add the loaded libraries to ajaxPageState.
  $libraries = plus_get_loaded_libraries();
  if (isset($settings['ajaxPageState']) || in_array('system/drupal.ajax', $libraries)) {
    // Provide the page with information about the theme that's used, so that
    // a later AJAX request can be rendered using the same theme.
    $settings['ajaxPageState']['theme'] = $theme;

    // The theme token is only validated when the theme requested is not the
    // default, so don't generate it unless necessary.
    if (!defined('MAINTENANCE_MODE') && $theme !== variable_get('theme_default', 'bartik')) {
      $settings['ajaxPageState']['theme_token'] = drupal_get_token($theme);
    }

    $settings['ajaxPageState']['libraries'] = $libraries;
  }
}

function plus_init_libraries() {

  // Unfortunately, in Drupal 7, hook_library() and hook_library_alter() do not
  // conform to the "normal" hook build/alter pattern. Nor are these hook info
  // definitions cached (at all). Every time either the drupal_add_library() or
  // drupal_get_library() functions are invoked, it starts the manual process
  // of retrieving and altering each module's libraries separately. This can
  // cause serious issues if a module needs to do some heavy computational
  // building or alters of library definitions. It also prevents a module from
  // altering all libraries, regardless of where they were defined, without
  // recursion issues (e.g. calling drupal_get_library() inside alters).
  $cid = 'plus:library_info';
  $libraries = &drupal_static('drupal_get_library', []);

  // Immediately set cached library info and return, if it exists.
  if (($cache = cache_get($cid)) && isset($cache->data) && is_array($cache->data)) {
    $libraries = $cache->data;
    return;
  }

  // Get all module libraries.
  foreach (module_implements('library') as $module) {
    // Skip AdvAgg's implementation as it's not really a hook implementation.
    // @see https://www.drupal.org/project/advagg/issues/2946751
    if ($module === 'advagg') {
      continue;
    }
    $libraries[$module] = module_invoke($module, 'library');
    if (empty($libraries[$module])) {
      $libraries[$module] = [];
    }
  }

  // Perform each individual module library info alters (like core does).
  foreach ($libraries as $module => &$module_libraries) {
    drupal_alter('library', $module_libraries, $module);
  }

  // Now let modules perform an alter for all defined libraries.
  drupal_alter('all_libraries', $libraries);

  // Add default elements to allow for easier processing.
  foreach ($libraries as $module => &$module_libraries) {
    foreach ($module_libraries as $key => $data) {
      if (is_array($data)) {
        $module_libraries[$key] += [
          'dependencies' => [],
          'js' => [],
          'css' => [],
        ];
        foreach ($module_libraries[$key]['js'] as $file => $options) {
          $module_libraries[$key]['js'][$file]['version'] = $module_libraries[$key]['version'];
        }
      }
    }
  }

  // Cache the library info definitions.
  cache_set($cid, $libraries);
}

/**
 * Implements hook_init().
 */
function plus_init() {
  // Reset JavaScript's drupalSettings. During the bootstrap phase, the
  // drupal_theme_initialize() function adds the theme and theme token in the
  // "ajaxPageState" prematurely. These are added back, correctly, if so needed
  // in plus_js_settings_alter().
  $javascript = &drupal_static('drupal_add_js', []);
  $javascript['settings']['data'] = [];

//    Drupal::service('library_info');

  // Initialize libraries.
  plus_init_libraries();

  // Add jQuery and the Drupal libraries if the site should always use theme.
  if (variable_get('javascript_always_use_jquery', TRUE)) {
    drupal_add_library('system', 'jquery');
    drupal_add_library('system', 'jquery.once');
    drupal_add_library('system', 'drupal');
  }
}

/**
 * Implements hook_all_libraries_alter().
 *
 * @see plus_init()
 */
function plus_all_libraries_alter(&$libraries) {
  $module_path = drupal_get_path('module', 'plus');

  // Create a Drupal 8 backport of the "core/drupal" library, but using this
  // module's replacement instead.
  $libraries['system']['drupal'] = [
    'title' => 'Drupal+',
    'version' => '1.0.0',
    'es6' => FALSE,
    'js' => [
      $module_path . '/js/Drupal.js' => [
        'es6' => FALSE,
        'group' => JS_CORE,
      ],
    ],
  ];

  // Add the new Drupal library as a dependency for all core libraries that
  // start with "drupal.".
  foreach ($libraries['system'] as $key => &$info) {
    if (strpos($key, 'drupal.') === 0) {
      if (!isset($info['dependencies'])) {
        $info['dependencies'] = [];
      }
      array_unshift($info['dependencies'], ['system', 'drupal']);
    }
  }

  // Add a default placeholder for ajaxPageState.
  $libraries['system']['drupal.ajax']['js'][] = [
    'type' => 'setting',
    'data' => ['ajaxPageState' => []],
  ];

  // Add a jQuery On/Off shim if necessary.
  $jquery_on_off_shim = TRUE;
  if (module_exists('jquery_update')) {
    $jquery_versions = explode('.', variable_get('jquery_update_jquery_version', '1.10'));
    if ((int) $jquery_versions[0] > 1 || ((int) $jquery_versions[0] === 1 && (int) $jquery_versions[1] > 6)) {
      $jquery_on_off_shim = FALSE;
    }
  }
  if ($jquery_on_off_shim) {
    $libraries['system']['jquery']['js'][$module_path . '/js/jquery.on.off.shim.js'] = $libraries['system']['jquery']['js']['misc/jquery.js'];
    unset($libraries['system']['jquery']['js'][$module_path . '/js/jquery.on.off.shim.js']['data']);
  }

  foreach ($libraries as $module => &$module_libraries) {
    foreach ($module_libraries as $key => &$info) {
      if (is_array($info) && !empty($info['js']) && _plus_is_library_es6($info, $libraries)) {
        // Add a dependency on the Drupal+ Asset Manager, but only if the module
        // being processed is not this module, since doing so can cause
        // dependency recursion.
        if ($module !== 'plus') {
          $info['dependencies'][] = ['plus', 'drupal.asset.manager'];
        }

        // Mark all JavaScript files as ES6 since this the whole library is ES6
        // (which may be because of an ES6 dependency).
        foreach ($info['js'] as &$data) {
          $data['es6'] = TRUE;
        }
      }
    }
  }
}

function _plus_is_library_es6(array &$info, array &$libraries) {
  // Immediately return if ES6 support was already determined or explicitly set.
  if (isset($info['es6'])) {
    return $info['es6'];
  }

  $info['es6'] = FALSE;
  if (!empty($info['dependencies'])) {
    foreach ($info['dependencies'] as $dependency) {
      list($dependency_module, $dependency_name) = $dependency;
      $dependency = isset($libraries[$dependency_module][$dependency_name]) ? $libraries[$dependency_module][$dependency_name] : [];
      $info['es6'] = $dependency ? _plus_is_library_es6($dependency, $libraries) : FALSE;
      if ($info['es6']) {
        break;
      }
    }
  }

  // If ES6 couldn't be determined by dependencies, check if this library's JS
  // has explicitly set "es6" or the filename ends with ".es6.js".
  if (!$info['es6'] && !empty($info['js'])) {
    foreach ($info['js'] as $file => &$data) {
      $file = (!isset($data['type']) || $data['type'] === 'file') && isset($data['data']) ? $data['data'] : $file;
      if (!empty($data['es6']) || preg_match('/\.es6\.js/', $file)) {
        $info['es6'] = TRUE;
        break;
      }
    }
  }

  return $info['es6'];
}

function plus_core_js_files() {
  $module_path = drupal_get_path('module', 'plus');

  $files = [
    'misc/jquery.js',
    $module_path . '/js/jquery.on.off.shim.js',
    'misc/jquery.once.js',
    $module_path . '/js/Drupal.js',
    'misc/ajax.js',
  ];
  return $files;
}

/**
 * Implements hook_element_info_alter().
 */
function plus_element_info_alter(&$types) {
  if (!isset($types['scripts']['#pre_render'])) {
    $types['scripts']['#pre_render'] = [];
  }

  foreach ($types as $type => &$info) {
    if (!isset($info['#pre_render'])) {
      $info['#pre_render'] = [];
    }
    if ($type === 'scripts') {
      array_unshift($types['scripts']['#pre_render'], 'plus_pre_render_scripts');
    }
    else {
      array_unshift($types['scripts']['#pre_render'], 'plus_pre_render_drupal_settings');
    }
  }
}

function plus_pre_render_drupal_settings(array $element) {
  // Immediately return if there are no attachments.
  if (!isset($element['#attached'])) {
    return $element;
  }

  $settings = isset($element['#attached']['drupalSettings']) ? $element['#attached']['drupalSettings'] : [];
  unset($element['#attached']['drupalSettings']);

  if (isset($element['#attached']['js'])) {
    foreach ($element['#attached']['js'] as $key => $info) {
      if (is_array($info) && isset($info['type']) && $info['type'] === 'setting') {
        $settings = drupal_array_merge_deep($settings, drupal_array_merge_deep_array($info['data']));
        unset($element['#attached']['js'][$key]);
      }
    }
  }

  if ($settings) {
    $element['#attached']['js'][] = [
      'type' => 'setting',
      'data' => $settings,
    ];
  }

  return $element;
}

/**
 * Implements hook_library().
 */
function plus_library() {
  $module_path = drupal_get_path('module', 'plus');
  $version = '1.0.0';

  $libraries['drupal.asset'] = [
    'title' => 'Drupal+ Asset',
    'version' => $version,
    'es6' => TRUE,
    'js' => [
      $module_path . '/js/Drupal.Asset.es6.js' => [
        'es6' => TRUE,
        'group' => JS_CORE,
      ],
    ],
    'dependencies' => [
      ['system', 'drupal'],
      ['plus', 'drupal.url'],
    ],
  ];

  $libraries['drupal.asset.manager'] = [
    'title' => 'Drupal+ Asset Manager',
    'version' => $version,
    'es6' => TRUE,
    'js' => [
      $module_path . '/js/Drupal.AssetManager.es6.js' => [
        'es6' => TRUE,
        'group' => JS_CORE,
      ],
    ],
    'dependencies' => [
      ['plus', 'drupal.asset'],
    ],
  ];

  $libraries['drupal.async.queue'] = [
    'title' => 'Drupal+ Asynchronous Queue',
    'version' => $version,
    'es6' => TRUE,
    'js' => [
      $module_path . '/js/Drupal.AsyncQueue.es6.js' => [
        'group' => JS_CORE,
      ],
    ],
    'dependencies' => [
      ['system', 'drupal'],
    ],
  ];

  $libraries['drupal.storage'] = [
    'title' => 'Drupal+ Storage',
    'version' => $version,
    'es6' => TRUE,
    'js' => [
      $module_path . '/js/Drupal.Storage.es6.js' => [
        'es6' => TRUE,
        'group' => JS_LIBRARY,
      ],
    ],
    'dependencies' => [
      ['system', 'drupal'],
    ],
  ];

  $libraries['drupal.url'] = [
    'title' => 'Drupal+ URL',
    'version' => $version,
    'es6' => TRUE,
    'js' => [
      $module_path . '/js/Drupal.Url.es6.js' => [
        'es6' => TRUE,
        'group' => JS_LIBRARY,
      ],
    ],
    'dependencies' => [
      ['system', 'drupal'],
    ],
  ];

  return $libraries;
}

function &_plus_find_element_by_key(&$elements, $key) {
  $element = NULL;
  foreach (element_children($elements) as $child) {
    if ($child === $key) {
      $element = &$elements[$child];
      break;
    }
    if ($element = &_plus_find_element_by_key($elements[$child], $key)) {
      break;
    }
  }
  return $element;
}

/**
 * Implements hook_module_implements_alter().
 */
function plus_module_implements_alter(&$implementations, $hook) {
  // Move plus to the bottom of the following hooks.
  $alter_hooks = [
    'init' => 'before',
    'element_info_alter' => 'after',
    'js_alter' => 'after',
  ];
  foreach ($alter_hooks as $alter_hook => $position) {
    if ($hook === $alter_hook && array_key_exists('plus', $implementations)) {
      $item = $implementations['plus'];
      unset($implementations['plus']);
      if ($position === 'after') {
        $implementations['plus'] = $item;
      }
      else {
        $implementations = ['plus' => $item] + $implementations;
      }
    }
  }
}

/**
 * Implements hook_form_alter().
 */
function plus_form_alter(&$form, &$form_state, $form_id) {
  // Immediately return if advagg settings shouldn't be managed.
  if (!variable_get('plus_manage_advagg_mod_settings', TRUE)) {
    return;
  }

  // Map the form identifier to the manage variable.
  $map = [
    'advagg_admin_settings_form' => 'plus_manage_advagg_settings',
    'advagg_bundler_admin_settings_form' => 'plus_manage_advagg_bundler_settings',
    'advagg_js_compress_admin_settings_form' => 'plus_manage_advagg_compressor_settings',
    'advagg_mod_admin_settings_form' => 'plus_manage_advagg_mod_settings',
  ];

  if (isset($map[$form_id]) && variable_get($map[$form_id], TRUE)) {
    $recommended = t('(recommended)');
    $managed = t('(managed by <a href="!plus">Drupal+</a>)', [
      // @todo Change URL to an admin UI page.
      '!plus' => url('https://www.drupal.org/project/plus'),
    ]);

    $settings = plus_manage_advagg_settings();
    foreach ($settings as $name => $value) {
      if ($element = &_plus_find_element_by_key($form, $name)) {
        if (strpos($element['#title'], $recommended) !== FALSE) {
          $element['#title'] = str_replace($recommended, $managed, $element['#title']);
        }
        else {
          $element['#title'] .= ' ' . $managed;
        }
        $element['#default_value'] = $value;
        $element['#disabled'] = TRUE;
        unset($element['#states']);
      }
    }
  }

}

/**
 * Implements hook_advagg_mod_get_lists_alter().
 */
function plus_advagg_mod_get_lists_alter(&$data) {
  // AdvAgg doesn't really provide a decent way to alter $all_in_footer_list.
  $all_in_footer_list = &$data[6];

  // Ensure all the core files are scope locked to the header.
  foreach (plus_core_js_files() as $file) {
    if (!isset($all_in_footer_list[$file])) {
      $all_in_footer_list[$file] = [$file];
    }
  }
}

/**
 * Provides AdvAgg setting overrides.
 *
 * Forcefully sets runtime AdvAgg settings that are not conducive with this
 * module's operation. Typically, these settings are configured incorrectly
 * anyway due to the lack of understanding and knowledge of how JavaScript
 * execution actually works in a browser.
 *
 * Thus, AdvAgg does a lot of unnecessary "wrapping" and "onload" event
 * modifications to the scripts in an effort to be a "catch all" for said
 * site developer.
 *
 * This is counter productive though and causes issues with this module which
 * aims to standardize everything using backports from Drupal 8 and new
 * libraries like Drupal.AssetManager and Drupal.AsyncBehaviors.
 *
 * @return array
 *   An array of the overridden AdvAgg settings.
 */
function plus_manage_advagg_settings() {
  global $conf;

  $settings = [];

  // AdvAgg JavaScript Settings.
  if (variable_get('plus_manage_advagg_settings', TRUE)) {
    $settings = array_merge($settings, [
      'advagg_core_groups' => FALSE,
    ]);
  }

  // AdvAgg JavaScript Bundler Settings.
  if (variable_get('plus_manage_advagg_bundler_settings', TRUE)) {
    $settings = array_merge($settings, [
      'advagg_bundler_active' => TRUE,
    ]);
  }

  // AdvAgg JavaScript Compressor Settings.
  if (variable_get('plus_manage_advagg_compressor_settings', TRUE)) {
    $settings = array_merge($settings, [
      'advagg_js_compressor' => 1,
      'advagg_js_compress_inline' => 1,
      'advagg_js_compress_add_license' => 3,
    ]);
  }

  // AdvAgg JavaScript Modification Settings.
  if (variable_get('plus_manage_advagg_mod_settings', TRUE)) {
    $settings = array_merge($settings, [
      'advagg_mod_ga_inline_to_file' => FALSE,
      'advagg_mod_prefetch' => FALSE,
      'advagg_mod_js_adjust_sort_browsers' => FALSE,
      'advagg_mod_js_adjust_sort_external' => FALSE,
      'advagg_mod_js_adjust_sort_inline' => FALSE,
      'advagg_mod_js_async' => FALSE,
      'advagg_mod_js_async_in_header' => FALSE,
      'advagg_mod_js_async_shim' => FALSE,
      'advagg_mod_js_defer' => 0,
      'advagg_mod_js_defer_inline_alter' => FALSE,
      'advagg_mod_js_footer' => 3,
      'advagg_mod_js_footer_inline_alter' => FALSE,
      'advagg_mod_js_head_extract' => TRUE,
      'advagg_mod_js_no_ajaxpagestate' => FALSE,
      'advagg_mod_js_preprocess' => TRUE,
      'advagg_mod_js_remove_unused' => FALSE,
    ]);
  }

  // Override runtime config.
  foreach ($settings as $name => $value) {
    $conf[$name] = $value;
  }

  return $settings;
}

/**
 * Implements hook_js_alter().
 */
function plus_js_alter(&$javascript) {
  // Use the advanced drupal_static() pattern, since this is called very often.
  static $drupal_static_fast;
  if (!isset($drupal_static_fast)) {
    $drupal_static_fast['es6'] = &drupal_static(__FUNCTION__ . ':es6', []);
    $drupal_static_fast['settings'] = &drupal_static(__FUNCTION__ . ':settings', []);

    // Override AdvAgg settings (only needs to be invoked once).
    plus_manage_advagg_settings();
  }
  $es6 = &$drupal_static_fast['es6'];
  $settings = &$drupal_static_fast['settings'];

  // Immediately return if this is rendering the ES6 files.
  if (!empty($javascript['es6_rendering'])) {
    unset($javascript['es6_rendering']);
    return;
  }

  // Capture all Drupal settings and remove them from the $javascript array.
  // They will be handled separately in plus_render_drupal_settings() as a
  // backport of Drupal 8's drupalSettings.
  foreach ($javascript as $key => $item) {
    if (isset($item['type']) && $item['type'] === 'setting') {
      $settings = array_merge($settings, isset($item['data']) && is_array($item['data']) ? $item['data'] : []);
      unset($javascript[$key]);
    }
  }

  $core_files = plus_core_js_files();

  // Find all ES6 JavaScript.
  foreach ($javascript as $key => $info) {
    $core_file = in_array($key, $core_files);

    // Move core files to their own group.
    if ($core_file) {
      $javascript[$key]['group'] = JS_CORE;
    }
    // Otherwise, defer the rest.
    elseif ($javascript[$key]['type'] === 'file' || $javascript[$key]['type'] === 'external') {
      $javascript[$key]['defer'] = TRUE;
    }

    // Remove ES6 files since this must must be conditionally loaded if the
    // browser supports ES6.
    if (!$core_file && (!empty($info['es6']) || ($info['type'] === 'file' && preg_match('/\.es6\.js/', $info['data'])))) {
      if (!isset($es6[$key])) {
        $es6[$key] = [];
      }
      $es6[$key] = drupal_array_merge_deep($es6[$key], $info);
      unset($javascript[$key]);
    }
  }
}

/**
 * Implements hook_page_alter().
 */
function plus_page_alter(&$page) {
  $element = [
    '#type' => 'html_tag',
    '#tag' => 'script',
    '#attributes' => [
      'type' => 'application/json',
      'data-drupal-selector' => 'drupal-settings-json',
    ],
    '#pre_render' => ['plus_render_drupal_settings'],
    '#value' => '{}',
  ];
  drupal_add_html_head($element, 'drupalSettings');

  // Implement a custom #attached callback to the page. This is necessary in
  // case any hook_page_build() or hook_page_alter() implementations attach
  // additional assets/libraries to the render array. It's also the last step
  // in the rendering process of drupal_render().
  $page['page_bottom']['plus']['#attached']['_plus_page_alter'] = [[]];
}

function plus_get_loaded_libraries() {
  // Backport of D8's indication of which libraries have been loaded.
  $libraries = [];
  foreach (drupal_static('drupal_add_library', []) as $module => $library) {
    foreach (array_keys(array_filter($library)) as $name) {
      $libraries[] = "$module/$name";
    }
  }
  natsort($libraries);
  return array_values($libraries);
}

/**
 * Callback for attaching ES6 files as a Drupal setting to the page.
 */
function _plus_page_alter() {
  $settings = [];

  $options = ['absolute' => TRUE];

  // Create a list of common files to load.
  $module_path = drupal_get_path('module', 'plus');
  $settings['loaderFiles'] = [
    // Drupal.Loader.es6.js must always be first!
    url($module_path . '/js/Drupal.Loader.es6.js', $options),
    url($module_path . '/js/Drupal.AsyncQueue.es6.js', $options),
    url($module_path . '/js/Drupal.Url.es6.js', $options),
    url($module_path . '/js/Drupal.Asset.es6.js', $options),
    url($module_path . '/js/Drupal.AssetManager.es6.js', $options),
    url($module_path . '/js/Drupal.Storage.es6.js', $options),
  ];

  // Backport of D8's indication of which libraries have been loaded.
  $settings['ajaxPageState']['library'] = plus_get_loaded_libraries();

  // Immediately return if ES6 support has been disabled.
  if ($es6 = drupal_static('plus_js_alter:es6', [])) {
    // Indicate that this is in the rendering phase so the alter doesn't recurse.
    $es6['es6_rendering'] = TRUE;

    // Generate the output for the files (absolute paths + aggregation).
    preg_match_all('/src="([^"]+)"/', drupal_get_js('header', $es6), $es6_matches);

    // Merge in any additional es6 files that should be loaded.
    $settings['loaderFiles'] = array_unique(array_merge($settings['loaderFiles'], $es6_matches[1]));
  }

  // Add the settings data.
  drupal_add_js($settings, 'setting');
}

function plus_pre_render_scripts(array $elements) {
  foreach ($elements['#items'] as $key => $info) {
    if (isset($info['type']) && $info['type'] === 'drupalSettings') {
      $elements[] = [
        '#type' => 'html_tag',
        '#tag' => 'script',
        '#attributes' => [
          'type' => 'application/json',
          'data-drupal-selector' => 'drupal-settings-json',
        ],
        '#context' => [
          'drupalSettings' => TRUE,
          'info' => $info,
        ],
        '#attached' => [
          'plus_render_drupal_settings' => [[]],
        ],
        '#value' => '{}',
      ];
      unset($elements['#items'][$key]);
    }
  }
  return $elements;
}

function plus_render_drupal_settings(array $element) {
  global $theme;
  global $language;

  drupal_get_js();

  // Backport similar JS cache id from Drupal 8, but just for drupalSettings.
  $libraries_to_load = plus_get_loaded_libraries();
  $runtime_settings = drupal_array_merge_deep_array(drupal_static('plus_js_alter:settings', []));
  $cid = 'plus:js:drupalSettings:' . $theme . ':' . $language->language . ':' . drupal_hash_base64(serialize($libraries_to_load));
  if (($cache = cache_get($cid)) && isset($cache->data) && is_array($cache->data)) {
    $settings = $cache->data;
  }
  else {
    // Pass the current runtime settings to the hooks, but only cache the
    // changes that were made to it as the entire runtime settings are likely
    // to change per page due to the nature of asset management in Drupal 7.
    $build_settings = $runtime_settings;
    foreach (module_implements('js_settings_build') as $module) {
      $function = $module . '_' . 'js_settings_build';
      $function($build_settings);
    }
    $settings = drupal_array_diff_assoc_recursive($build_settings, $runtime_settings);
    cache_set($cid, $settings);
  }

  // Merge built/cached settings with runtime settings.
  $settings = drupal_array_merge_deep($settings, $runtime_settings);

  // Allow modules and themes to alter the JS settings.
  drupal_alter('js_settings', $settings);

  if ($settings) {
    $element['#context']['drupalSettings'] = $settings;
    $element['#value'] = function_exists('advagg_json_encode') ? advagg_json_encode($settings) : drupal_json_encode($settings);

    // Gzip and base64 encode the settings.
    if (variable_get('plus_drupal_settings_gzip', TRUE) && variable_get('js_gzip_compression', TRUE) && extension_loaded('zlib')) {
      $element['#attributes']['data-drupal-gzip'] = 'true';
      $element['#value'] = base64_encode(gzencode($element['#value'], 9));
    }
  }

  return $element;
}

/**
 * Implements hook_theme().
 */
function plus_theme($existing, $type, $theme, $path) {
  return [
    'file_link__plus' => [
      'base hook' => 'file_link',
      'variables' => ['file' => NULL, 'icon_directory' => NULL, 'icon' => TRUE],
    ],
    'no_file_icon' => [],
  ];
}

/**
 * Do not show file icons, which can take up valuable space.
 */
function theme_no_file_icon() {
  return '';
}

/**
 * Override theme hook.
 */
function plus_preprocess_file_link(&$variables) {
  $variables['theme_hook_suggestions'][] = 'file_link__plus';
}

/**
 * Override file_link theme hook.
 */
function theme_file_link__plus($variables) {
  $file = $variables['file'];

  $url = file_create_url($file->uri);

  // Show icon.
  $icon = '';
  if ($variables['icon']) {
    // Human-readable names, for use as text-alternatives to icons.
    $mime_name = array(
      'application/msword' => t('Microsoft Office document icon'),
      'application/vnd.ms-excel' => t('Office spreadsheet icon'),
      'application/vnd.ms-powerpoint' => t('Office presentation icon'),
      'application/pdf' => t('PDF icon'),
      'video/quicktime' => t('Movie icon'),
      'audio/mpeg' => t('Audio icon'),
      'audio/wav' => t('Audio icon'),
      'image/jpeg' => t('Image icon'),
      'image/png' => t('Image icon'),
      'image/gif' => t('Image icon'),
      'application/zip' => t('Package icon'),
      'text/html' => t('HTML icon'),
      'text/plain' => t('Plain text icon'),
      'application/octet-stream' => t('Binary Data'),
    );

    $mimetype = file_get_mimetype($file->uri);

    $icon = theme('file_icon', array(
      'file' => $file,
      'icon_directory' => $variables['icon_directory'],
      'alt' => !empty($mime_name[$mimetype]) ? $mime_name[$mimetype] : t('File'),
    ));
  }

  if (!isset($file->extension)) {
    $info = pathinfo($file->filename);
    $file->extension = $info['extension'];
  }

  // Set options as per anchor format described at
  // http://microformats.org/wiki/file-format-examples
  $options = array(
    'attributes' => array(
      'data-basename' => basename($file->filename, '.' . $file->extension),
      'data-extension' => $file->extension,
      'data-fid' => $file->fid,
      'data-filename' => $file->filename,
      'data-filesize' => $file->filesize,
      'data-uid' => $file->uid,
      'type' => $file->filemime . '; length=' . $file->filesize,
    ),
  );

  // Use the description as the link text if available.
  if (empty($file->description)) {
    $link_text = $file->filename;
  }
  else {
    $link_text = $file->description;
    $options['attributes']['title'] = check_plain($file->filename);
  }

  return '<span class="file">' . $icon . l($link_text, $url, $options) . '</span>';
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc