outlayer-8.x-1.4/src/OutlayerManager.php
src/OutlayerManager.php
<?php
namespace Drupal\outlayer;
use Drupal\Component\Serialization\Json;
use Drupal\gridstack\GridStackManager;
use Drupal\outlayer\Entity\Outlayer;
/**
* Provides outlayer manager.
*/
class OutlayerManager extends GridStackManager implements OutlayerManagerInterface {
/**
* {@inheritdoc}
*/
protected static $namespace = 'outlayer';
/**
* The Outlayer optionset.
*
* @var \Drupal\outlayer\Entity\Outlayer
*/
protected $outLayerOptionset;
/**
* Supports the new native CSS Grid layout, or disable here if broken.
*
* @var bool
*/
protected $supportGridNative = TRUE;
/**
* {@inheritdoc}
*/
public function prepareAttributes(array &$build) {
$attributes = parent::prepareAttributes($build);
$settings = &$build['#settings'];
$outlayers = $settings['outlayers'] ?? NULL;
$plugin_id = $settings['plugin_id'] ?? NULL;
$instance_id = $settings['instance_id'] ?? NULL;
$attributes['class'][] = 'outlayer';
$js = isset($this->outLayerOptionset) ? $this->outLayerOptionset->getOptions() : [];
$this->massageOptions($js, $settings);
if ($outlayers) {
$instance_id = $outlayers->get('view.base_id') ?: $instance_id;
}
// Pass data to template.
$plugin = 'isotope';
$layout = $js['layoutMode'];
if ($plugin_id == 'outlayer_grid') {
$plugin = $settings['style'];
if (!empty($js[$layout])) {
foreach ($js[$layout] as $key => $value) {
$js[$key] = $value;
}
}
unset($js['layoutMode'], $js[$layout]);
}
// Take over Masonry/Packery JS with just native CSS Grid if configured so.
// Except for Isotope which might combine both for its layout and filtering.
if ($this->supportGridNative && in_array($plugin, ['masonry', 'packery'])) {
$attributes['class'][] = 'outlayer--native';
}
else {
// Regular Masonry/Packery/Isotope JS layout applies.
$attributes['class'][] = 'outlayer--' . $plugin;
$defaults = Outlayer::defaultSettings();
$js = array_diff_assoc($js, $defaults);
$attributes['data-outlayer-' . $plugin] = Json::encode($js);
// Sync filters, sorters with the main grid display via similar ID.
if ($instance_id) {
$attributes['data-instance-id'] = $instance_id;
}
}
return $attributes;
}
/**
* {@inheritdoc}
*/
public function extractGridCustom(array $settings): array {
$dimensions = [];
if (!empty($settings['grid_custom'])) {
$values = array_map('trim', explode(" ", $settings['grid_custom']));
foreach ($values as $value) {
$width = $value;
$height = 0;
if (strpos($value, 'x') !== FALSE) {
[$width, $height] = array_pad(array_map('trim', explode("x", $value, 2)), 2, NULL);
}
$dimensions[] = ['width' => (int) $width, 'height' => (int) $height];
}
}
return $dimensions;
}
/**
* {@inheritdoc}
*/
public function getIsotopeExtraLibrary(array $attach): ?string {
$layout = empty($attach['layoutMode']) ? '' : $attach['layoutMode'];
foreach (OutlayerDefault::extraLayouts() as $name => $id) {
if ($layout == $name) {
return 'outlayer/isotope-' . $id;
}
}
return NULL;
}
/**
* {@inheritdoc}
*/
public function prepareSettings(array &$settings) {
parent::prepareSettings($settings);
$settings += OutlayerDefault::htmlSettings();
if (isset($this->outLayerOptionset)) {
$settings['layoutMode'] = $this->outLayerOptionset->getOption('layoutMode');
$settings['fluid'] = $this->outLayerOptionset->getOption('percentPosition');
}
$gridstacks = $settings['gridstacks'];
$engine = $gridstacks->get('engine');
$ungridstack = $gridstacks->is('ungridstack');
$use_gridnative = $gridstacks->use('gridnative');
$this->supportGridNative = $this->supportGridNative && $use_gridnative;
$this->outLayerOptionset = Outlayer::loadSafely($settings['outlayer']);
if (!$this->supportGridNative) {
// Tells Gridstack to not load any asset with this.
$ungridstack = !empty($settings['grid_custom']);
if ($ungridstack) {
$engine = 'outlayer_ungridstack';
}
}
$gridstacks->set('engine', $engine)
->set('is.ungridstack', $ungridstack)
->set('use.gridnative', $use_gridnative);
}
/**
* {@inheritdoc}
*/
protected function attachments(array &$load, array $attach, $blazies): void {
$attach['blazy'] = TRUE;
parent::attachments($load, $attach, $blazies);
// Masonry and Packery might be replaced by native CSS Grid entirely.
// No JS libraries are needed for static grid display. CSS Grid takes over.
// However Isotope still needs extra JS for filtering, or sorting.
if (!empty($attach['plugin_id'])) {
switch ($attach['plugin_id']) {
case 'outlayer_grid':
if (!empty($attach['style']) && !$this->supportGridNative) {
$load['library'][] = 'outlayer/load.' . $attach['style'];
}
break;
case 'outlayer_isotope':
if ($layout = $this->getIsotopeExtraLibrary($attach)) {
$load['library'][] = $layout;
}
$load['library'][] = 'outlayer/load.isotope';
break;
default:
break;
}
}
if ($this->supportGridNative) {
$load['library'][] = 'outlayer/native';
}
$js = Outlayer::defaultSettings();
foreach (['columnWidth', 'gutter', 'rowHeight'] as $key) {
if (isset($js['layout'][$key]) && is_numeric($js['layout'][$key])) {
$js['layout'][$key] = (int) $js['layout'][$key];
}
}
$load['drupalSettings']['outLayer'] = $js;
$this->moduleHandler->alter('outlayer_attach', $load, $attach, $blazies);
}
/**
* Massages the options.
*/
protected function massageOptions(array &$js, array &$settings) {
Outlayer::massageOptions($js);
$layout = $js['layoutMode'];
// Have no option for this as we don't offer many templates.
if (empty($js['itemSelector'])) {
$js['itemSelector'] = '.gridstack__box';
}
// If having stamps, provides relevant classes.
if (!empty($settings['stamp'])) {
$js['stamp'] = '.box--stamp';
$js['itemSelector'] = '.gridstack__box:not(.box--stamp)';
}
// Provides sorters.
if (!empty($settings['sorters'])) {
$sorts = [];
foreach ($settings['sorters'] as $key) {
$sorts[$key] = '[data-srtr-' . $key . ']';
}
$js['getSortData'] = $sorts;
// @todo extract correct data.
if (!empty($settings['sortBy'])) {
$js['sortBy'] = $settings['sortBy'];
}
}
// Sizing options columnWidth, rowHeight, and gutter can be set with an
// element. The size of the element is then used as the value of the option.
foreach (['columnWidth', 'gutter', 'rowHeight'] as $key) {
if (!empty($js[$layout][$key])) {
if (is_numeric($js[$layout][$key])) {
$js[$layout][$key] = (int) $js[$layout][$key];
}
else {
$settings[$key . 'Sizer'] = str_replace('.', '', $js[$layout][$key]);
}
}
}
foreach (['stagger', 'transitionDuration'] as $key) {
if (!empty($js[$key]) && is_numeric($js[$key])) {
$js[$key] = (int) $js[$key];
}
}
}
}
