rotationBlocksKey = $blocksKey; } return $this; } /** * Gather ordered blocks * @return static */ protected function beforeRenderRotation() { if ($this->rotationBlocksKey && is_array($this->data)) { $this->data[$this->rotationBlocksKey] = $this->orderedBlocks(); } return $this; } /** * Get ordered enabled blocks * @return string[]|Block[] */ public function orderedBlocks() { $name = $this->rotationSettingOrdersName; $blocks = []; $divider = $this->rotationDivider(); if ($divider) { $n = $this->rotationSettingDividersName; $dividerData = $this->$n ?? []; } $prev = ''; foreach ($this->$name ?? [] as $key => $enabled) { if (! $enabled) { continue; } $block = $this->data[$key] ?? null; if ($block instanceof Block) { $index = $block->getKey(); if ($block->prerenderable()) { $html = trim($block->render()); if ($html) { $blocks[$index] = $html; $prev = $index; } } else { $blocks[$index] = $block; $prev = $index; } } elseif (mb_strpos($key, $this->rotationDividerKeyPrefix) !== false) { $k = (int)mb_substr($key, mb_strlen($this->rotationDividerKeyPrefix)); if (isset($dividerData[$k])) { $blocks[$key] = $divider->with($dividerData[$k])->render(); if (mb_strpos($prev, $this->rotationDividerKeyPrefix) !== false) { unset($blocks[$prev]); # 2 dividers successively - leave first one } $prev = $key; } } } return $blocks; } /** * Enable/disable block(s) rotation * @param string|string[] $key block(s) key * @param bool $rotate * @param array $opts ['checked' => 'always'] * @return static */ public function rotateBlock($key, $rotate = true, array $opts = []) { if (is_array($key)) { foreach ($key as $k) { $this->rotateBlock($k, $rotate, $opts); } return $this; } $this->setRotatableBlockOptions($key, array_merge([ 'rotate' => $rotate, 'checked' => true, ], $opts)); return $this; } /** * Set block rotation options * @param string|string[] $key * @param array $opts * @return static */ public function setRotatableBlockOptions($key, array $opts) { if (is_array($key)) { foreach ($key as $k) { $this->setRotatableBlockOptions($k, $opts); } return $this; } if (array_key_exists($key, $this->rotatableBlocks)) { $this->rotatableBlocks[$key] = array_merge($this->rotatableBlocks[$key], $opts); } else { $this->rotatableBlocks[$key] = $opts; } return $this; } /** * Blocks divider * @return Block|null */ public function rotationDivider() { if ($this->rotationDivider) { if ($this->rotationDivider instanceof Closure) { $this->rotationDivider = ($this->rotationDivider)(); } if (is_object($this->rotationDivider)) { return $this->rotationDivider; } } return null; } /** * Set blocks divider * @param string $class * @param callable|null $callback function ($block) {} * @param callable|null $preload function ($form) {} */ public function setRotationDividerBlock($class, $callback = null, $preload = null) { $this->rotationDivider = function () use ($class, $callback) { if (class_exists($class)) { $this->rotationDivider = new $class(); $this->rotationDivider->setParent($this); if (is_callable($callback)) { $callback($this->rotationDivider); } return $this->rotationDivider; } return null; }; $this->rotationDividerPreload = $preload; } /** * Init rotation settings * @param Form $form * @return void */ public function rotationSettingsForm($form) { if (empty($this->rotationBlocksKey)) { return; } $tab = $this->rotationSettingsInTab || is_a($this, Page::class); if ($divider = $this->rotationDivider()) { if ($tab) { $form->tab($this->rotationSettingDividersTabName, $this->rotationSettingDividersTabTitle ?: _t('@', 'Dividers'), ['priority' => 99]); } $form->group( $this->rotationSettingDividersName, _t('@', 'Add Divider'), !$tab ? ($this->rotationSettingDividersTabTitle ?: _t('@', 'Dividers')) : '', ['plus' => ['position' => 'after']] ) ->param('sortable', false); $divider->settingsForm($form); if (is_callable($this->rotationDividerPreload)) { call_user_func($this->rotationDividerPreload, $form); } $form->endGroup() ->tip(_t('@', 'Save and reload settings to use dividers in Order section')); } if ($tab) { $form->tab($this->rotationSettingOrdersTabName, $this->rotationSettingOrdersTabTitle ?: _t('@', 'Order'), ['priority' => 100]); } $form->checkboxList($this->rotationSettingOrdersName, _t('@', 'Display and Order of Blocks'), function () use ($divider, $form) { $options = []; $priority = 10; $this->blocksIterator(function (Block $block, $key) use (&$options, &$priority) { $def = $this->rotatableBlocks[$key] ?? ['rotate' => true]; if (empty($def['rotate'])) { return; } $options[] = [ 'id' => $key, 'title' => $block->getTitle(), 'checked' => (bool)($def['checked'] ?? true), 'priority' => $priority, ]; $priority += 10; }); if ($divider) { $dividers = $form->value($this->rotationSettingDividersName); if (! empty($dividers)) { foreach ($dividers as $k => $v) { $key = $this->rotationDividerKeyPrefix . $k; $p = $priority; if (! empty($v['before'])) { foreach ($options as $o) { if ($o['id'] == $v['before']) { $p = $o['priority'] - 2; break; } } } $options[] = [ 'id' => $key, 'title' => '--- ' . (($v['title'] ?? '') ?: 'divider ' . $k) . ' ---', 'checked' => $v['checked'] ?? true, 'priority' => $p, ]; $priority += 10; } } func::sortByPriority($options); } return $options; }) ->param('sortable', true) ->hidden(function ($field) use ($tab) { /** @var $field CheckboxList */ return ! $tab && empty($field->options()); }) ->classAdd('j-rotation-block-' . $this->rotationSettingOrdersName) ->jsOnReady(function () { ?>onValidate(function ($p){ if (! is_array($p['value'])) { return false; } foreach ($p['value'] as $k => & $v) { if (! isset($this->rotatableBlocks[$k])) { continue; } $r = $this->rotatableBlocks[$k]; if (($r['checked'] ?? '') === 'always') { $v = 1; } } unset($v); return true; }) ; } /** * Get rotation settings values * @param Form $form * @return array */ public function rotationSettingsValues($form) { $result = []; do { if (empty($this->rotationBlocksKey)) { break; } $tab = $this->rotationSettingsInTab || is_a($this, Page::class); if ($this->rotationDivider) { $result[$this->rotationSettingDividersName] = $form->value( ($tab ? $this->rotationSettingDividersTabName . '/' : '') . $this->rotationSettingDividersName, null, null ); } $result[$this->rotationSettingOrdersName] = $form->value( ($tab ? $this->rotationSettingOrdersTabName . '/' : '') . $this->rotationSettingOrdersName, null, null ); } while (false); return $result; } }