diff --git a/js.module b/js.module index d6bd9f5..c3ee318 100644 --- a/js.module +++ b/js.module @@ -88,11 +88,28 @@ function js_preprocess_html() { /** * Implements hook_custom_theme(). - * - * Used to set the theme to be used for JS requests. */ function js_custom_theme() { global $_js; + + // During a full bootstrap, hook_custom_theme() is invoked just before + // hook_init(). Here we can make sure that hook_init() implementations + // provided by callback dependencies are not invoked twice, in case a full + // bootstrap is performed after invoking them in js_callback_bootstrap(). + if (!empty($_js['module']) && !empty($_js['callback'])) { + $info = js_get_callback($_js['module'], $_js['callback']); + if (!$info['skip init'] && $info['dependencies']) { + $implementations = &drupal_static('module_implements'); + // After a global cache clear, hook implementation info is not available + // yet, so we explicitly rebuild it. + if (!isset($implementations['init'])) { + module_implements('init'); + } + $implementations['init'] = array_diff_key($implementations['init'], array_flip($info['dependencies'])); + } + } + + // Set the theme to be used for JS requests. if (!empty($_js['theme'])) { return $_js['theme']; } @@ -669,6 +686,12 @@ function js_deliver($result, array $info = NULL) { module_load_include('inc', 'js', 'includes/json'); } + // Since most callbacks act at a bootstrap level lower than full, that is + // without loading all modules, we need to make sure hook implementation cache + // is never written while processing a JS request. + $implementations = &drupal_static('module_implements'); + unset($implementations['#write_cache']); + // Deliver the results. The delivery callback is responsible for setting the // appropriate headers, handling the result returned from the callback and // exiting the script properly.