summaryrefslogtreecommitdiffstats
path: root/core/modules/breakpoint/src/BreakpointManager.php
diff options
context:
space:
mode:
Diffstat (limited to 'core/modules/breakpoint/src/BreakpointManager.php')
-rw-r--r--core/modules/breakpoint/src/BreakpointManager.php274
1 files changed, 274 insertions, 0 deletions
diff --git a/core/modules/breakpoint/src/BreakpointManager.php b/core/modules/breakpoint/src/BreakpointManager.php
new file mode 100644
index 0000000..757f2cf
--- /dev/null
+++ b/core/modules/breakpoint/src/BreakpointManager.php
@@ -0,0 +1,274 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\breakpoint\BreakpointManager.
+ */
+
+namespace Drupal\breakpoint;
+
+use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheBackendInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Extension\ThemeHandlerInterface;
+use Drupal\Core\Plugin\DefaultPluginManager;
+use Drupal\Core\Plugin\Discovery\ContainerDerivativeDiscoveryDecorator;
+use Drupal\Core\Plugin\Discovery\YamlDiscovery;
+use Drupal\Core\Plugin\Factory\ContainerFactory;
+use Drupal\Core\StringTranslation\StringTranslationTrait;
+use Drupal\Core\StringTranslation\TranslationInterface;
+
+/**
+ * Defines a breakpoint plugin manager to deal with breakpoints.
+ *
+ * Extension can define breakpoints in a EXTENSION_NAME.breakpoints.yml file
+ * contained in the extension's base directory. Each breakpoint has the
+ * following structure:
+ * @code
+ * MACHINE_NAME:
+ * label: STRING
+ * mediaQuery: STRING
+ * weight: INTEGER
+ * multipliers:
+ * - STRING
+ * @endcode
+ * For example:
+ * @code
+ * bartik.mobile:
+ * label: mobile
+ * mediaQuery: '(min-width: 0px)'
+ * weight: 0
+ * multipliers:
+ * - 1x
+ * - 2x
+ * @endcode
+ * Optionally a breakpoint can provide a group key. By default an extensions
+ * breakpoints will be placed in a group labelled with the extension name.
+ *
+ * @see \Drupal\breakpoint\Breakpoint
+ * @see \Drupal\breakpoint\BreakpointInterface
+ * @see plugin_api
+ */
+class BreakpointManager extends DefaultPluginManager implements BreakpointManagerInterface {
+ use StringTranslationTrait;
+
+ /**
+ * {@inheritdoc}
+ */
+ protected $defaults = array(
+ // Human readable label for breakpoint.
+ 'label' => '',
+ // The media query for the breakpoint.
+ 'mediaQuery' => '',
+ // Weight used for ordering breakpoints.
+ 'weight' => 0,
+ // Breakpoint multipliers.
+ 'multipliers' => array(),
+ // The breakpoint group.
+ 'group' => '',
+ // Default class for breakpoint implementations.
+ 'class' => 'Drupal\breakpoint\Breakpoint',
+ // The plugin id. Set by the plugin system based on the top-level YAML key.
+ 'id' => '',
+ );
+
+ /**
+ * The theme handler.
+ *
+ * @var \Drupal\Core\Extension\ThemeHandlerInterface
+ */
+ protected $themeHandler;
+
+ /**
+ * Static cache of breakpoints keyed by group.
+ *
+ * @var array
+ */
+ protected $breakpointsByGroup;
+
+ /**
+ * The plugin instances.
+ *
+ * @var array
+ */
+ protected $instances = array();
+
+ /**
+ * Constructs a new BreakpointManager instance.
+ *
+ * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
+ * The module handler.
+ * @param \Drupal\Core\Extension\ThemeHandlerInterface $theme_handler
+ * The theme handler.
+ * @param \Drupal\Core\Cache\CacheBackendInterface $cache_backend
+ * The cache backend.
+ * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
+ * The string translation service.
+ */
+ public function __construct(ModuleHandlerInterface $module_handler, ThemeHandlerInterface $theme_handler, CacheBackendInterface $cache_backend, TranslationInterface $string_translation) {
+ $this->discovery = new YamlDiscovery('breakpoints', $module_handler->getModuleDirectories() + $theme_handler->getThemeDirectories());
+ $this->discovery = new ContainerDerivativeDiscoveryDecorator($this->discovery);
+ $this->factory = new ContainerFactory($this);
+ $this->moduleHandler = $module_handler;
+ $this->themeHandler = $theme_handler;
+ $this->setStringTranslation($string_translation);
+ $this->alterInfo('breakpoints');
+ $this->setCacheBackend($cache_backend, 'breakpoints', array('breakpoints' => TRUE));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function processDefinition(&$definition, $plugin_id) {
+ parent::processDefinition($definition, $plugin_id);
+ // Allow custom groups and therefore more than one group per extension.
+ if (empty($definition['group'])) {
+ $definition['group'] = $definition['provider'];
+ }
+ // Ensure a 1x multiplier exists.
+ if (!in_array('1x', $definition['multipliers'])) {
+ $definition['multipliers'][] = '1x';
+ }
+ // Ensure that multipliers are sorted correctly.
+ sort($definition['multipliers']);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function findDefinitions() {
+ $definitions = $this->discovery->getDefinitions();
+ foreach ($definitions as $plugin_id => &$definition) {
+ $this->processDefinition($definition, $plugin_id);
+ }
+ if ($this->alterHook) {
+ $this->moduleHandler->alter($this->alterHook, $definitions);
+ }
+ // If this plugin was provided by a module that does not exist, remove the
+ // plugin definition.
+ foreach ($definitions as $plugin_id => $plugin_definition) {
+ // If the plugin definition is an object, attempt to convert it to an
+ // array, if that is not possible, skip further processing.
+ if (is_object($plugin_definition) && !($plugin_definition = (array) $plugin_definition)) {
+ continue;
+ }
+ // Allow themes to provide breakpoints.
+ if (isset($plugin_definition['provider']) && !in_array($plugin_definition['provider'], array('core', 'component')) && !$this->moduleHandler->moduleExists($plugin_definition['provider']) && !$this->themeHandler->themeExists($plugin_definition['provider'])) {
+ unset($definitions[$plugin_id]);
+ }
+ }
+ return $definitions;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getBreakpointsByGroup($group) {
+ if (!isset($this->breakpointsByGroup[$group])) {
+ if ($cache = $this->cacheBackend->get($this->cacheKey . ':' . $group)) {
+ $this->breakpointsByGroup[$group] = $cache->data;
+ }
+ else {
+ $breakpoints = array();
+ foreach ($this->getDefinitions() as $plugin_id => $plugin_definition) {
+ if ($plugin_definition['group'] == $group) {
+ $breakpoints[$plugin_id] = $plugin_definition;
+ }
+ }
+ uasort($breakpoints, array('Drupal\Component\Utility\SortArray', 'sortByWeightElement'));
+ $this->cacheBackend->set($this->cacheKey . ':' . $group, $breakpoints, Cache::PERMANENT, array('breakpoints' => TRUE));
+ $this->breakpointsByGroup[$group] = $breakpoints;
+ }
+ }
+ $instances = array();
+ foreach ($this->breakpointsByGroup[$group] as $plugin_id => $definition) {
+ if (!isset($this->instances[$plugin_id])) {
+ $this->instances[$plugin_id] = $this->createInstance($plugin_id);
+ }
+ $instances[$plugin_id] = $this->instances[$plugin_id];
+ }
+ return $instances;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getGroups() {
+ // Use a double colon so as to not clash with the cache for each group.
+ if ($cache = $this->cacheBackend->get($this->cacheKey . '::groups')) {
+ $groups = $cache->data;
+ }
+ else {
+ $groups = array();
+ foreach ($this->getDefinitions() as $plugin_definition) {
+ if (!isset($groups[$plugin_definition['group']])) {
+ $groups[$plugin_definition['group']] = $plugin_definition['group'];
+ }
+ }
+ $this->cacheBackend->set($this->cacheKey . '::groups', $groups, Cache::PERMANENT, array('breakpoints' => TRUE));
+ }
+ // Get the labels. This is not cacheable due to translation.
+ $group_labels = array();
+ foreach ($groups as $group) {
+ $group_labels[$group] = $this->getGroupLabel($group);
+ }
+ asort($group_labels);
+ return $group_labels;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getGroupProviders($group) {
+ $providers = array();
+ $breakpoints = $this->getBreakpointsByGroup($group);
+ foreach ($breakpoints as $breakpoint) {
+ $provider = $breakpoint->getProvider();
+ $extension = FALSE;
+ if ($this->moduleHandler->moduleExists($provider)) {
+ $extension = $this->moduleHandler->getModule($provider);
+ }
+ elseif ($this->themeHandler->themeExists($provider)) {
+ $extension = $this->themeHandler->getTheme($provider);
+ }
+ if ($extension) {
+ $providers[$extension->getName()] = $extension->getType();
+ }
+ }
+ return $providers;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function clearCachedDefinitions() {
+ parent::clearCachedDefinitions();
+ $this->breakpointsByGroup = NULL;
+ $this->instances = array();
+ }
+
+ /**
+ * Gets the label for a breakpoint group.
+ *
+ * @param string $group
+ * The breakpoint group.
+ *
+ * @return string
+ * The label.
+ */
+ protected function getGroupLabel($group) {
+ // Extension names are not translatable.
+ if ($this->moduleHandler->moduleExists($group)) {
+ $label = $this->moduleHandler->getName($group);
+ }
+ elseif ($this->themeHandler->themeExists($group)) {
+ $label = $this->themeHandler->getName($group);
+ }
+ else {
+ // Custom group label that should be translatable.
+ $label = $this->t($group, array(), array('context' => 'breakpoint'));
+ }
+ return $label;
+ }
+
+}