diff --git a/demos/_includes/CustomCard.php b/demos/_includes/CustomCard.php
new file mode 100644
index 0000000000..2f53508c79
--- /dev/null
+++ b/demos/_includes/CustomCard.php
@@ -0,0 +1,25 @@
+btnContainer) {
+ // $this->btnContainer = $this->addExtraContent(new View(['ui' => 'buttons']));
+ $this->btnContainer = $this->add(new View(['ui' => 'buttons bottom attached'])); // attach buttons to bottom
+ $this->getButtonContainer()->addClass('wrapping');
+ if ($this->hasFluidButton) {
+ $this->getButtonContainer()->addClass('fluid');
+ }
+ }
+
+ return $this->btnContainer;
+ }
+}
diff --git a/demos/collection/card-deck.php b/demos/collection/card-deck.php
index e0b3bee9de..77c918b7e6 100644
--- a/demos/collection/card-deck.php
+++ b/demos/collection/card-deck.php
@@ -6,15 +6,17 @@
use Atk4\Data\Model;
use Atk4\Ui\Button;
+use Atk4\Ui\Card;
use Atk4\Ui\CardDeck;
use Atk4\Ui\Form;
use Atk4\Ui\Header;
use Atk4\Ui\UserAction\ExecutorFactory;
+use Atk4\Ui\View;
/** @var \Atk4\Ui\App $app */
require_once __DIR__ . '/../init-app.php';
-Header::addTo($app, ['Card Deck', 'size' => 1, 'subHeader' => 'Card can be display in a deck, also using model action.']);
+Header::addTo($app, ['Card Deck - Booking', 'size' => 1, 'subHeader' => 'Card can be display in a deck, also using model action.']);
$countries = new Country($app->db);
$countries->addCalculatedField('cost', ['type' => 'atk4_money', 'expr' => function (Country $country) {
@@ -50,3 +52,20 @@
$deck = CardDeck::addTo($app, ['noRecordScopeActions' => ['request_info'], 'singleScopeActions' => ['book']]);
$deck->setModel($countries, ['cost'], [$countries->fieldName()->iso, $countries->fieldName()->iso3]);
+
+// Another Card Deck example below
+Header::addTo($app, ['Card Deck - Editable', 'size' => 1, 'subHeader' => 'Cards can also use custom templates and have full editing support like Grid.']);
+
+$countries = new Country($app->db);
+$countries->addCalculatedField('iso_lower', ['expr' => function (Country $m) {return strtolower($m->get($m->fieldName()->iso)); }]);
+$deck = CardDeck::addTo($app, [
+ 'cardHolder' => [View::class, 'ui' => 'cards six'],
+ 'ipp' => 6 * 2,
+ 'card' => [
+ CustomCard::class,
+ 'ui' => 'card atk-card blue',
+ 'addFields' => false,
+ 'defaultTemplate' => __DIR__ . '/templates/card.html',
+ ],
+]);
+$deck->setModel($countries);
diff --git a/demos/collection/templates/card.html b/demos/collection/templates/card.html
new file mode 100644
index 0000000000..a98cd9696b
--- /dev/null
+++ b/demos/collection/templates/card.html
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+ {$Image}
+ {$Content}
+ {$Section}
+ {$ExtraContent}
+
diff --git a/src/Card.php b/src/Card.php
index efb7399b67..8e29911c4c 100644
--- a/src/Card.php
+++ b/src/Card.php
@@ -64,15 +64,21 @@ class Card extends View
/** @var View|null The button Container for Button */
public $btnContainer;
+ /** @var bool Do we want to add fields in section or just set values in template */
+ public $addFields = true;
+
/** @var bool Display model field as table inside card holder content */
public $useTable = false;
- /** @var bool Use Field label with value data. */
+ /** @var bool Use Field label with value data */
public $useLabel = false;
- /** @var string Default executor class. */
+ /** @var string Default executor class */
public $executor = UserAction\ModalExecutor::class;
+ /** @var View|null Header view, useful to add additional views to it, icons for example */
+ public $headerView;
+
protected function init(): void
{
parent::init();
@@ -166,7 +172,18 @@ public function addContent(View $view)
}
/**
- * If Fields are past with $model that field will be add
+ * Returns array of names of fields to automatically include them in view.
+ * This includes all editable or visible fields of the model.
+ *
+ * @return array
+ */
+ protected function getModelFields(Model $model)
+ {
+ return array_keys($model->getFields(['editable', 'visible']));
+ }
+
+ /**
+ * If Fields are past with $model that field will be added
* to the main section of this card.
*
* @param array|null $fields
@@ -178,13 +195,17 @@ public function setModel(Model $entity, array $fields = null): void
parent::setModel($entity);
if ($fields === null) {
- $fields = array_keys($this->model->getFields(['editable', 'visible']));
+ $fields = $this->getModelFields($entity);
}
$this->template->trySet('dataId', (string) $this->model->getId());
- View::addTo($this->getSection(), [$entity->getTitle(), 'class.header' => true]);
- $this->getSection()->addFields($entity, $fields, $this->useLabel, $this->useTable);
+ $this->headerView = View::addTo($this->getSection(), [$entity->getTitle(), 'class.header' => true]);
+ if ($this->addFields) {
+ $this->getSection()->addFields($entity, $fields, $this->useLabel, $this->useTable);
+ } else {
+ $this->template->set($this->model);
+ }
}
/**
diff --git a/src/CardDeck.php b/src/CardDeck.php
index cb1cb5db64..f7236cecdf 100644
--- a/src/CardDeck.php
+++ b/src/CardDeck.php
@@ -22,7 +22,7 @@ class CardDeck extends View
public $defaultTemplate = 'card-deck.html';
- /** @var class-string Card type inside this deck. */
+ /** @var class-string|array Card type inside this deck. */
public $card = Card::class;
/** @var bool Whether card should use table display or not. */
@@ -85,10 +85,10 @@ class CardDeck extends View
];
/** @var array A collection of menu button added in Menu. */
- private $menuActions = [];
+ protected $menuActions = [];
/** @var string|null The current search query string. */
- private $query;
+ protected $query;
protected function init(): void
{
@@ -99,11 +99,7 @@ protected function init(): void
$this->container = $this->add($this->container);
if ($this->menu !== false && !is_object($this->menu)) {
- $this->menu = $this->add(Factory::factory([Menu::class, 'activateOnClick' => false], $this->menu), 'Menu');
-
- if ($this->search !== false) {
- $this->addMenuBarSeach();
- }
+ $this->addMenuBar();
}
$this->cardHolder = $this->container->add($this->cardHolder);
@@ -114,6 +110,15 @@ protected function init(): void
}
}
+ protected function addMenuBar(): void
+ {
+ $this->menu = $this->add(Factory::factory([Menu::class, 'activateOnClick' => false], $this->menu), 'Menu');
+
+ if ($this->search !== false) {
+ $this->addMenuBarSeach();
+ }
+ }
+
protected function addMenuBarSeach(): void
{
$view = View::addTo($this->menu->addMenuRight()->addItem()->setElement('div'));
@@ -147,7 +152,7 @@ public function setModel(Model $model, array $fields = null, array $extra = null
if ($count) {
foreach ($this->model as $m) {
/** @var Card */
- $c = $this->cardHolder->add(Factory::factory([$this->card], ['useLabel' => $this->useLabel, 'useTable' => $this->useTable]));
+ $c = $this->cardHolder->add(Factory::factory((array) $this->card, ['useLabel' => $this->useLabel, 'useTable' => $this->useTable]));
$c->setModel($m, $fields);
if ($extra) {
$c->addExtraFields($m, $extra, $this->extraGlue);
@@ -262,7 +267,7 @@ protected function jsCreateNotifier(Model\UserAction $action, string $msg = null
*
* @return mixed
*/
- private function getReloadArgs()
+ protected function getReloadArgs()
{
$args = [];
if ($this->paginator !== false) {
@@ -278,7 +283,7 @@ private function getReloadArgs()
/**
* Return proper action need to setup menu or action column.
*/
- private function getModelActions(string $appliesTo): array
+ protected function getModelActions(string $appliesTo): array
{
if ($appliesTo === Model\UserAction::APPLIES_TO_SINGLE_RECORD && $this->singleScopeActions !== []) {
$actions = array_map(fn ($v) => $this->model->getUserAction($v), $this->singleScopeActions);
diff --git a/src/CardSection.php b/src/CardSection.php
index 083667b815..cb8d3cf6df 100644
--- a/src/CardSection.php
+++ b/src/CardSection.php
@@ -64,15 +64,15 @@ public function addFields(Model $model, array $fields, bool $useLabel = false, b
/**
* Add fields label and value to section.
*/
- private function addSectionFields(Model $model, array $fields, bool $useLabel = false): void
+ protected function addSectionFields(Model $model, array $fields, bool $useLabel = false): void
{
foreach ($fields as $field) {
if ($model->titleField === $field) {
continue;
}
- $label = $model->getField($field)->getCaption();
$value = $this->getApp()->uiPersistence->typecastSaveField($model->getField($field), $model->get($field));
if ($useLabel) {
+ $label = $model->getField($field)->getCaption();
$value = $label . $this->glue . $value;
}
@@ -85,7 +85,7 @@ private function addSectionFields(Model $model, array $fields, bool $useLabel =
/**
* Add field into section using a CardTable View.
*/
- private function addTableSection(Model $model, array $fields): void
+ protected function addTableSection(Model $model, array $fields): void
{
$cardTable = CardTable::addTo($this, ['class' => $this->tableClass]);
$cardTable->setModel($model, $fields);
diff --git a/src/HtmlTemplate.php b/src/HtmlTemplate.php
index 0a3a2480d4..62a6d92f8f 100644
--- a/src/HtmlTemplate.php
+++ b/src/HtmlTemplate.php
@@ -157,7 +157,7 @@ protected function _setOrAppend($tag, string $value = null, bool $encodeHtml = t
// in this case we don't throw exception if tags don't exist
if (is_array($tag) && $value === null) {
foreach ($tag as $k => $v) {
- $this->_setOrAppend($k, $v, $encodeHtml, $append, false);
+ $this->_setOrAppend($k, (string) $v, $encodeHtml, $append, false);
}
return;