View source
<?php
namespace Drupal\gridstack;
use Drupal\Core\Cache\Cache;
use Drupal\Core\Render\Element;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Component\Utility\NestedArray;
use Drupal\blazy\BlazyManagerBase;
use Drupal\blazy\BlazyManagerInterface;
use Drupal\gridstack\Entity\GridStack;
class GridStackManager extends BlazyManagerBase implements BlazyManagerInterface, GridStackManagerInterface {
use StringTranslationTrait;
protected $skinDefinition;
protected $skinOptions;
public function getSkins() {
if (!isset($this->skinDefinition)) {
$this->skinDefinition = $this
->buildSkins('gridstack', '\\Drupal\\gridstack\\GridStackSkin');
}
return $this->skinDefinition;
}
public function getSkinOptions() {
if (!isset($this->skinOptions)) {
$this->skinOptions = [];
foreach ($this
->getSkins() as $skin => $properties) {
$this->skinOptions[$skin] = isset($properties['name']) ? strip_tags($properties['name']) : $skin;
}
}
return $this->skinOptions;
}
public function attach($attach = []) {
$attach += [
'skin' => FALSE,
];
$load = parent::attach($attach);
if (!empty($attach['use_js'])) {
$customized = $this
->configLoad('customized', 'gridstack.settings');
$load['library'][] = empty($customized) ? 'gridstack/load' : 'gridstack/customized';
if (!empty($attach['width']) && $attach['width'] < 12) {
$load['library'][] = 'gridstack/gridstack.' . $attach['width'];
}
if (!empty($attach['breakpoints'])) {
foreach ($attach['breakpoints'] as $breakpoint) {
if (!empty($breakpoint['column']) && $breakpoint['column'] < 12) {
$load['library'][] = 'gridstack/gridstack.' . $breakpoint['column'];
}
}
}
$load['drupalSettings']['gridstack'] = GridStack::load('default')
->getOptions('settings');
}
if (!empty($attach['library'])) {
$load['library'][] = $attach['library'];
}
if ($skin = $attach['skin']) {
$skins = $this
->getSkins();
$provider = isset($skins[$skin]['provider']) ? $skins[$skin]['provider'] : 'gridstack';
$load['library'][] = 'gridstack/' . $provider . '.' . $skin;
}
$this->moduleHandler
->alter('gridstack_attach', $load, $attach);
return $load;
}
public function setBoxAttributes(array &$settings = [], $current = 'grids', $optionset = NULL) {
$attributes = [];
$breakpoint = isset($settings['breakpoint']) ? $settings['breakpoint'] : 'lg';
$breakpoints = isset($settings['breakpoints']) ? $settings['breakpoints'] : [];
$id = isset($settings['delta']) ? $settings['delta'] : 0;
$nid = isset($settings['nested_delta']) ? $settings['nested_delta'] : NULL;
$use_js = empty($settings['use_framework']) && !empty($settings['root']) || !empty($settings['_admin']);
if ($use_js) {
$end_grids = $optionset
->getEndBreakpointGrids($current);
$grids = isset($breakpoints[$breakpoint]) && isset($breakpoints[$breakpoint][$current]) ? $breakpoints[$breakpoint][$current] : $end_grids;
if (empty($grids)) {
return $attributes;
}
if (isset($settings['nested_delta']) && $current == 'nested') {
foreach ([
'x',
'y',
'width',
'height',
] as $key) {
if (!isset($grids[$id][$nid])) {
continue;
}
$value = isset($grids[$id][$nid][$key]) ? $grids[$id][$nid][$key] : 0;
$attributes['data-gs-' . $key] = $value;
}
}
else {
foreach ([
'x',
'y',
'width',
'height',
] as $key) {
$value = isset($grids[$id][$key]) ? $grids[$id][$key] : 0;
$attributes['data-gs-' . $key] = $value;
}
}
return $attributes;
}
$framework = $settings['framework'];
$points = [
'xs' => 'xsmall',
'sm' => 'small',
'md' => 'medium',
'lg' => 'large',
'xl' => 'xlarge',
];
$regions = isset($settings['regions']) ? $settings['regions'] : [];
$region = $current == 'nested' ? 'gridstack_' . $id . '_' . $nid : 'gridstack_' . $id;
if (!empty($regions[$region])) {
if (isset($regions[$region]['attributes']) && !empty($regions[$region]['attributes'])) {
$attributes = $optionset::parseAttributes($regions[$region]['attributes']);
unset($settings['regions'][$region]['attributes']);
}
$old_classes = !empty($regions[$region]['classes']) ? $regions[$region]['classes'] : '';
$new_classes = !empty($regions[$region]['wrapper_classes']) ? $regions[$region]['wrapper_classes'] : $old_classes;
if (!empty($new_classes)) {
$classes = explode(' ', $new_classes);
foreach ($classes as $class) {
$attributes['class'][] = trim($class);
}
unset($settings['regions'][$region]['wrapper_classes']);
}
}
if ($framework == 'bootstrap') {
$attributes['class'][] = 'col';
}
elseif ($framework == 'foundation') {
unset($points['xs'], $points['xl']);
}
$unique = $optionset::optimizeGridWidths($settings, $current);
foreach ($points as $point => $label) {
if (!isset($unique[$point])) {
continue;
}
$prefix = $suffix = '';
if (strpos($framework, 'bootstrap') !== FALSE) {
$prefix = 'col-' . $point . '-';
if ($framework == 'bootstrap' && $point == 'xs') {
$prefix = 'col-';
}
}
elseif ($framework == 'foundation') {
$prefix = $label . '-';
$suffix = ' columns';
}
$attributes['class'][] = $prefix . $unique[$point] . $suffix;
}
return $attributes;
}
public function setIpeAttributes(array &$box = [], array $block = []) {
if ($block && !empty($block['#prefix'])) {
$box['#prefix'] = $block['#prefix'];
foreach (Element::children($box) as $id) {
if (isset($block[$id]['#attributes']['data-block-id'])) {
$box[$id]['#attributes']['data-block-id'] = $block[$id]['#attributes']['data-block-id'];
}
}
}
}
public function buildItems(array $build = [], array $regions = []) {
$optionset = $build['optionset'];
$items = $build['items'];
$settings = $build['settings'];
$grids = $optionset
->getEndBreakpointGrids();
$content = [];
$settings['wrapper'] = '';
foreach ($items as $delta => $item) {
$clone_box = isset($item['box']) ? $item['box'] : [];
$attributes = isset($item['attributes']) ? $item['attributes'] : [];
$settings = isset($item['settings']) ? array_merge($settings, $item['settings']) : $settings;
$region = 'gridstack_' . $delta;
$clone = [
'box' => $clone_box,
'caption' => isset($item['caption']) ? $item['caption'] : [],
];
$settings['delta'] = $delta;
if ($grids) {
if (!isset($grids[$delta])) {
continue;
}
if (isset($regions[$region]['#attributes']) && is_array($regions[$region]['#attributes'])) {
$attributes = array_merge($attributes, $regions[$region]['#attributes']);
$attributes['class'][] = 'layout-builder--layout__region layout__region layout__region--' . $region;
if (isset($regions[$region]['layout_builder_add_block'])) {
$clone['box'][] = $regions[$region]['layout_builder_add_block'];
}
}
$main_attributes = $this
->setBoxAttributes($settings, 'grids', $optionset);
$nested_grids = $optionset
->getNestedGridsByDelta($delta);
$is_nested = array_filter($nested_grids);
$root_settings = $settings;
$clone['attributes'] = NestedArray::mergeDeep($attributes, $main_attributes);
$root_settings['wrapper'] = '';
if (isset($settings['regions']) && !empty($settings['regions'][$region]['wrapper'])) {
$root_settings['wrapper'] = $settings['regions'][$region]['wrapper'];
}
if (!empty($clone['box']) && !empty($settings['_access_ipe']) && isset($regions[$region])) {
$this
->setIpeAttributes($clone['box'], $regions[$region]);
}
$clone['settings'] = $root_settings;
if (!empty($is_nested)) {
$clone['attributes']['class'][] = 'box--nester';
$settings['root'] = FALSE;
$settings['nested'] = $root_settings['nested'] = TRUE;
$settings['nester'] = FALSE;
$clone['settings'] = $root_settings;
$nested = $clone_box;
if (!empty($nested) && isset($nested[0]['box'])) {
foreach ($nested_grids as $nid => $nested_grid) {
$nested_region = $delta . '_' . $nid;
$region = 'gridstack_' . $nested_region;
if (!empty($nested[$nid]['box']) && !empty($settings['_access_ipe']) && isset($regions[$region])) {
$this
->setIpeAttributes($nested[$nid]['box'], $regions[$region]);
}
$settings['nested_delta'] = $nid;
$nested[$nid]['settings'] = isset($nested[$nid]['settings']) ? array_merge($settings, $nested[$nid]['settings']) : $settings;
$nested[$nid]['settings']['wrapper'] = '';
if (isset($settings['regions'][$region]) && !empty($settings['regions'][$region]['wrapper'])) {
$nested[$nid]['settings']['wrapper'] = $settings['regions'][$region]['wrapper'];
}
$nested[$nid]['settings']['nested_id'] = $delta + 1 . '-' . ($nid + 1);
$nested_attributes = isset($nested[$nid]['attributes']) ? $nested[$nid]['attributes'] : [];
if (isset($regions[$region]['#attributes']) && is_array($regions[$region]['#attributes'])) {
$nested_attributes = array_merge($nested_attributes, $regions[$region]['#attributes']);
$nested_attributes['class'][] = 'layout-builder--layout__region layout__region layout__region--' . $region;
if (isset($regions[$region]['layout_builder_add_block'])) {
$nested[$nid]['box'][] = $regions[$region]['layout_builder_add_block'];
}
}
$nested[$nid]['attributes'] = NestedArray::mergeDeep($nested_attributes, $this
->setBoxAttributes($settings, 'nested', $optionset));
$nested[$nid]['attributes']['class'][] = 'box--nested';
}
$box = [];
if (isset($item['prefix'])) {
$box['prefix'] = $item['prefix'];
}
$box['content'] = [
'#theme' => 'gridstack',
'#items' => $nested,
'#grids' => $nested_grids,
'#optionset' => $optionset,
'#settings' => $settings,
'#attributes' => isset($item['wrapper_attributes']) ? $item['wrapper_attributes'] : [],
];
$clone['box'] = $box;
$clone['settings'] = $root_settings;
}
}
}
$content[] = $clone;
unset($clone);
}
return $content;
}
public function build(array $build = []) {
foreach ([
'attached',
'grids',
'items',
'optionset',
'settings',
] as $key) {
$build[$key] = isset($build[$key]) ? $build[$key] : [];
}
if (empty($build['items'])) {
return [];
}
$layout = isset($build['layout']) ? $build['layout'] : [];
$gridstack = [
'#theme' => 'gridstack',
'#items' => [],
'#build' => $build,
'#pre_render' => [
[
$this,
'preRenderGridStack',
],
],
'#layout' => $layout,
];
if ($layout) {
foreach ($layout
->getRegions() as $region => $info) {
$gridstack[$region] = [];
}
}
else {
$gridstack['items'] = [];
}
$settings = $build['settings'];
if (!empty($settings['_layout_builder'])) {
}
$max_age = $this
->configLoad('cache.page.max_age', 'system.performance');
$max_age = empty($settings['cache']) ? $max_age : $settings['cache'];
$id = empty($settings['id']) ? 'gridstack-' . $settings['optionset'] : $settings['id'];
$settings['id'] = $id = GridStack::getHtmlId('gridstack', $id);
$suffixes[] = count($build['items']);
$suffixes[] = count(array_filter($settings));
$suffixes[] = $max_age;
$cache['tags'] = Cache::buildTags('gridstack:' . $id, $suffixes, '.');
$cache['contexts'] = [
'languages',
];
$cache['max-age'] = $max_age;
$cache['keys'] = isset($settings['cache_metadata']['keys']) ? $settings['cache_metadata']['keys'] : [
$id,
];
if (!empty($settings['cache_tags'])) {
$cache['tags'] = Cache::mergeTags($cache['tags'], $settings['cache_tags']);
}
$gridstack['#cache'] = $cache;
return $gridstack;
}
public function preRenderGridStack($element) {
$build = $element['#build'];
unset($element['#build']);
if (empty($build['items'])) {
return [];
}
$defaults = GridStack::htmlSettings();
$settings = $build['settings'] ? array_merge($defaults, $build['settings']) : $defaults;
$optionset = $build['optionset'] ?: GridStack::load($settings['optionset']);
if (empty($optionset)) {
$optionset = $build['optionset'] = GridStack::load('default');
}
$settings = array_merge($settings, $optionset
->getOptions('settings'));
$is_admin = !empty($settings['_layout_builder']) || !empty($settings['_ipe']);
$is_builder = !empty($settings['_layout_builder']) && isset($element['#attributes']) && isset($element['#attributes']['data-layout-delta']);
$is_ipe = !empty($settings['_ipe']) && isset($element['#prefix']) && strpos($element['#prefix'], 'panels-ipe-content') !== FALSE;
$settings['use_js'] = empty($settings['_admin']);
$settings['framework'] = $this
->configLoad('framework', 'gridstack.settings');
$settings['library'] = $is_admin ? $this
->configLoad('library', 'gridstack.settings') : '';
$settings['use_framework'] = !empty($settings['framework']) && $optionset
->getOption('use_framework');
$settings['_access_ipe'] = FALSE;
if ($settings['use_framework']) {
$settings['background'] = $settings['use_js'] = FALSE;
$settings['use_framework'] = empty($settings['_admin']);
}
$attachments = $this
->attach($settings);
if (empty($settings['breakpoints'])) {
$optionset
->gridsJsonToArray($settings);
}
if (!empty($settings['root'])) {
if (empty($build['grids'])) {
$build['grids'] = $optionset
->getEndBreakpointGrids();
}
if (!empty($settings['attributes'])) {
$element['#attributes'] = $optionset::parseAttributes($settings['attributes']);
}
if (!empty($settings['use_framework'])) {
if (!empty($settings['wrapper_classes']) && is_string($settings['wrapper_classes'])) {
$classes = explode(' ', $settings['wrapper_classes']);
foreach ($classes as $class) {
$element['#attributes']['class'][] = trim($class);
}
}
}
}
$settings['attributes'] = $settings['wrapper_classes'] = '';
$regions = [];
$children = Element::children($element);
if (isset($element['#attached'])) {
$build['attached'] = NestedArray::mergeDeep($build['attached'], $element['#attached']);
}
if ($is_admin) {
$settings['_access_ipe'] = $is_ipe || $is_builder;
foreach ($children as $child) {
if ($child == 'items') {
continue;
}
$regions[$child] = $element[$child];
}
$build['attached']['library'][] = 'gridstack/admin_base';
}
$element['#optionset'] = $optionset;
$element['#grids'] = $build['grids'];
$element['#settings'] = $build['settings'] = $settings;
$element['#columns'] = empty($build['columns']) ? $optionset
->getJson('breakpoints') : $build['columns'];
$element['#attached'] = empty($build['attached']) ? $attachments : NestedArray::mergeDeep($build['attached'], $attachments);
$element['#items'] = $this
->buildItems($build, $regions);
if ($children) {
foreach ($children as $child) {
unset($element[$child]);
}
}
return $element;
}
public function libraryInfoBuild() {
$libraries = [];
if ($skins = $this
->getSkins()) {
foreach ($skins as $key => $skin) {
$provider = isset($skin['provider']) ? $skin['provider'] : 'gridstack';
$id = $provider . '.' . $key;
foreach ([
'css',
'js',
'dependencies',
] as $property) {
if (isset($skin[$property]) && is_array($skin[$property])) {
$libraries[$id][$property] = $skin[$property];
}
}
$libraries[$id]['dependencies'][] = 'gridstack/skin';
}
}
foreach (range(1, 12) as $key) {
$libraries['gridstack.' . $key] = [
'css' => [
'layout' => [
'css/layout/grid-stack-' . $key . '.css' => [],
],
],
];
}
return $libraries;
}
public static function configSchemaInfoAlter(array &$definitions) {
if (isset($definitions['layout_plugin.settings'])) {
self::mapConfigSchemaInfoAlter($definitions['layout_plugin.settings'], 'panelizer');
}
if (isset($definitions['core.entity_view_display.*.*.*.third_party.ds'])) {
self::mapConfigSchemaInfoAlter($definitions['core.entity_view_display.*.*.*.third_party.ds']['mapping']['layout']['mapping']['settings']);
}
}
public static function mapConfigSchemaInfoAlter(array &$mappings, $source = '') {
$common = [
'attributes',
'extras',
'skin',
'wrapper',
'wrapper_classes',
];
if ($source == 'panelizer') {
$common = array_merge($common, [
'classes',
]);
}
foreach ($common as $key) {
$mappings['mapping'][$key]['type'] = 'string';
$mappings['mapping'][$key]['label'] = ucwords($key);
}
$mappings['mapping']['regions']['type'] = 'sequence';
$mappings['mapping']['regions']['label'] = 'Regions';
$mappings['mapping']['regions']['sequence'][0]['type'] = 'mapping';
$mappings['mapping']['regions']['sequence'][0]['label'] = 'Region';
foreach ($common as $key) {
$mappings['mapping']['regions']['sequence'][0]['mapping'][$key]['type'] = 'string';
$mappings['mapping']['regions']['sequence'][0]['mapping'][$key]['label'] = ucwords($key);
}
}
public function fieldFormatterInfoAlter(array &$info) {
$common = [
'quickedit' => [
'editor' => 'disabled',
],
'provider' => 'gridstack',
];
if ($this
->getModuleHandler()
->moduleExists('video_embed_media')) {
$info['gridstack_file'] = $common + [
'id' => 'gridstack_file',
'label' => $this
->t('GridStack Image with Media'),
'description' => $this
->t('Display the images associated to VEM/ME as a simple mix of GridStack image/video.'),
'class' => 'Drupal\\gridstack\\Plugin\\Field\\FieldFormatter\\GridStackFileFormatter',
'field_types' => [
'entity_reference',
'image',
],
];
$info['gridstack_media'] = $common + [
'id' => 'gridstack_media',
'label' => $this
->t('GridStack Media'),
'description' => $this
->t('Display the VEM/ME as a simple mix of GridStack image/video.'),
'class' => 'Drupal\\gridstack\\Plugin\\Field\\FieldFormatter\\GridStackMediaFormatter',
'field_types' => [
'entity_reference',
],
];
}
if (function_exists('paragraphs_theme')) {
$info['gridstack_paragraphs'] = $common + [
'id' => 'gridstack_paragraphs',
'label' => $this
->t('GridStack Paragraphs'),
'description' => $this
->t('Display the Paragraphs as a GridStack.'),
'class' => 'Drupal\\gridstack\\Plugin\\Field\\FieldFormatter\\GridStackParagraphsFormatter',
'field_types' => [
'entity_reference_revisions',
],
];
}
}
}