/** * {@inheritdoc} */ public function alter(&$types, &$context1 = NULL, &$context2 = NULL) { // Sort the types for easier debugging. ksort($types, SORT_NATURAL); $process_manager = new ProcessManager($this->theme); $pre_render_manager = new PrerenderManager($this->theme); foreach (array_keys($types) as $type) { $element =& $types[$type]; // Ensure elements that have a base type with the #input set match. if (isset($element['#base_type']) && isset($types[$element['#base_type']]) && isset($types[$element['#base_type']]['#input'])) { $element['#input'] = $types[$element['#base_type']]['#input']; } // Core does not actually use the "description_display" property on the // "details" or "fieldset" element types because the positioning of the // description is never used in core templates. However, the form builder // automatically applies the value of "after", thus making it impossible // to detect a valid value later in the rendering process. It looks better // for the "details" and "fieldset" element types to display as "before". // @see \Drupal\Core\Form\FormBuilder::doBuildForm() if ($type === 'details' || $type === 'fieldset') { $element['#description_display'] = 'before'; $element['#panel_type'] = 'default'; } // Add extra variables to all elements. foreach (Bootstrap::extraVariables() as $key => $value) { if (!isset($variables["#{$key}"])) { $variables["#{$key}"] = $value; } } // Only continue if the type isn't "form" (as it messes up AJAX). if ($type !== 'form') { $regex = "/^{$type}/"; // Add necessary #process callbacks. $element['#process'][] = [get_class($process_manager), 'process']; $definitions = $process_manager->getDefinitionsLike($regex); foreach ($definitions as $definition) { Bootstrap::addCallback($element['#process'], [$definition['class'], 'process'], $definition['replace'], $definition['action']); } // Add necessary #pre_render callbacks. $element['#pre_render'][] = [get_class($pre_render_manager), 'preRender']; foreach ($pre_render_manager->getDefinitionsLike($regex) as $definition) { Bootstrap::addCallback($element['#pre_render'], [$definition['class'], 'preRender'], $definition['replace'], $definition['action']); } } } }
/** * Preprocess theme hook variables. * * @param array $variables * The variables array, passed by reference. * @param string $hook * The name of the theme hook. * @param array $info * The theme hook info. */ public static function preprocess(array &$variables, $hook, array $info) { static $theme; if (!isset($theme)) { $theme = self::getTheme(); } static $preprocess_manager; if (!isset($preprocess_manager)) { $preprocess_manager = new PreprocessManager($theme); } // Ensure that any default theme hook variables exist. Due to how theme // hook suggestion alters work, the variables provided are from the // original theme hook, not the suggestion. if (isset($info['variables'])) { $variables = NestedArray::mergeDeepArray([$info['variables'], $variables], TRUE); } // Add extra variables to all theme hooks. foreach (Bootstrap::extraVariables() as $key => $value) { if (!isset($variables[$key])) { $variables[$key] = $value; } } // Add active theme context. // @see https://www.drupal.org/node/2630870 if (!isset($variables['theme'])) { $variables['theme'] = $theme->getInfo(); $variables['theme']['name'] = $theme->getName(); $variables['theme']['path'] = $theme->getPath(); $variables['theme']['title'] = $theme->getTitle(); $variables['theme']['settings'] = $theme->settings()->get(); $variables['theme']['has_glyphicons'] = $theme->hasGlyphicons(); $variables['theme']['query_string'] = \Drupal::getContainer()->get('state')->get('system.css_js_query_string') ?: '0'; } // Invoke necessary preprocess plugin. if (isset($info['bootstrap preprocess'])) { if ($preprocess_manager->hasDefinition($info['bootstrap preprocess'])) { $class = $preprocess_manager->createInstance($info['bootstrap preprocess'], ['theme' => $theme]); /** @var \Drupal\bootstrap\Plugin\Preprocess\PreprocessInterface $class */ $class->preprocess($variables, $hook, $info); } } }