(#2) - forms improvements
This commit is contained in:
@@ -5,24 +5,34 @@ namespace Reservair\Forms;
|
||||
/**
|
||||
* Fluent builder for WordPress admin settings forms.
|
||||
*
|
||||
* Renders a <table class="form-table"> with one row per field.
|
||||
* Hidden inputs and datalist elements are emitted before the table;
|
||||
* notices before, submit button after.
|
||||
* Renders a self-contained "form-wrap" card: an optional heading and a <form>
|
||||
* wrapping a <table class="form-table"> with one row per field. Hidden inputs
|
||||
* and datalist elements are emitted before the table; notices before the card,
|
||||
* submit button after the fields.
|
||||
*
|
||||
* Usage:
|
||||
* echo RsvFormBuilder::create()
|
||||
* echo RsvFormBuilder::create('settings', $action, 'PATCH', 'Saved.')
|
||||
* ->heading('Settings')
|
||||
* ->text('name', 'Name', required: true)
|
||||
* ->email('email', 'Email')
|
||||
* ->submit('Save');
|
||||
*/
|
||||
class RsvFormBuilder
|
||||
{
|
||||
private string $form_id = "";
|
||||
private string $form_id;
|
||||
|
||||
/** Where the form submits, and how RsvAdminForm should send it. */
|
||||
private string $action;
|
||||
private string $rest_method;
|
||||
private string $success_msg;
|
||||
|
||||
/** Optional heading shown inside the card. */
|
||||
private string $heading = '';
|
||||
|
||||
/** @var string[] Rendered before the table (hidden inputs, datalists). */
|
||||
private array $before = [];
|
||||
|
||||
/** @var string[] WP admin notice banners rendered before the table. */
|
||||
/** @var string[] WP admin notice banners rendered before the card. */
|
||||
private array $notices = [];
|
||||
|
||||
/** @var string[] <tr> elements inside the table. */
|
||||
@@ -33,9 +43,29 @@ class RsvFormBuilder
|
||||
|
||||
private function __construct() {}
|
||||
|
||||
public static function create(string $id): static
|
||||
/**
|
||||
* @param string $rest_method Verb sent via data-method (POST, PUT, PATCH…).
|
||||
* @param string $success_msg Message RsvAdminForm shows on success.
|
||||
*/
|
||||
public static function create(
|
||||
string $id,
|
||||
string $action,
|
||||
string $rest_method = 'POST',
|
||||
string $success_msg = ''
|
||||
): static {
|
||||
$builder = new static();
|
||||
$builder->form_id = $id;
|
||||
$builder->action = $action;
|
||||
$builder->rest_method = $rest_method;
|
||||
$builder->success_msg = $success_msg;
|
||||
return $builder;
|
||||
}
|
||||
|
||||
/** Heading shown inside the card, above the fields. */
|
||||
public function heading(string $text): static
|
||||
{
|
||||
return new static();
|
||||
$this->heading = $text;
|
||||
return $this;
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
@@ -206,6 +236,13 @@ class RsvFormBuilder
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** WordPress nonce field, emitted inside the form before the table. */
|
||||
public function nonce(string $action, string $name): static
|
||||
{
|
||||
$this->before[] = wp_nonce_field($action, $name, true, false);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* <datalist> element for email/text suggestions — emitted before the table.
|
||||
*
|
||||
@@ -257,15 +294,27 @@ class RsvFormBuilder
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
$html = implode('', $this->notices);
|
||||
$html .= implode('', $this->before);
|
||||
$inner = implode('', $this->before);
|
||||
|
||||
if (!empty($this->rows)) {
|
||||
$html .= '<table class="form-table"><tbody>' . implode('', $this->rows) . '</tbody></table>';
|
||||
$inner .= '<table class="form-table"><tbody>' . implode('', $this->rows) . '</tbody></table>';
|
||||
}
|
||||
|
||||
$html .= implode('', $this->after);
|
||||
return $html;
|
||||
$inner .= implode('', $this->after);
|
||||
|
||||
$success = $this->success_msg !== '' ? ' data-success-msg="' . esc_attr($this->success_msg) . '"' : '';
|
||||
$form = '<form id="' . esc_attr($this->form_id) . '"'
|
||||
. ' action="' . esc_url($this->action) . '"'
|
||||
. ' method="post"'
|
||||
. ' data-method="' . esc_attr($this->rest_method) . '"'
|
||||
. $success . '>'
|
||||
. $inner
|
||||
. '</form>';
|
||||
|
||||
$heading = $this->heading !== '' ? '<h2>' . esc_html($this->heading) . '</h2>' : '';
|
||||
|
||||
return implode('', $this->notices)
|
||||
. '<div class="form-wrap">' . $heading . $form . '</div>';
|
||||
}
|
||||
|
||||
public function output(): void
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace Reservair\Layout;
|
||||
|
||||
/**
|
||||
* Fluent builder for multi-column admin page layouts.
|
||||
*
|
||||
* Lets a page declare the shape it wants (e.g. a two-column split) without
|
||||
* committing to any markup or styling. Each column's content is supplied as a
|
||||
* callable that echoes — inline HTML and <script> blocks work as usual.
|
||||
*
|
||||
* Usage:
|
||||
* RsvColumnLayout::split('1:2')
|
||||
* ->column(function () { ?>
|
||||
* <h2>Add timetable</h2>
|
||||
* ...
|
||||
* <?php })
|
||||
* ->column(function () { ?>
|
||||
* <div id="availability_table"></div>
|
||||
* ...
|
||||
* <?php })
|
||||
* ->output();
|
||||
*/
|
||||
class RsvColumnLayout
|
||||
{
|
||||
/** @var list<callable():void> Column content, in left-to-right order. */
|
||||
private array $columns = [];
|
||||
|
||||
/** @var list<int> Relative column weights, parsed from the ratio. */
|
||||
private array $weights;
|
||||
|
||||
private function __construct(string $ratio)
|
||||
{
|
||||
$this->weights = array_map('intval', explode(':', $ratio));
|
||||
}
|
||||
|
||||
/**
|
||||
* Side-by-side columns that stack on narrow screens.
|
||||
*
|
||||
* @param string $ratio Relative column widths, e.g. '1:1', '1:2'.
|
||||
*/
|
||||
public static function split(string $ratio = '1:1'): static
|
||||
{
|
||||
return new static($ratio);
|
||||
}
|
||||
|
||||
/** Adds the next column. $render echoes the column's content. */
|
||||
public function column(callable $render): static
|
||||
{
|
||||
$this->columns[] = $render;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render(): string
|
||||
{
|
||||
$cols = '';
|
||||
foreach ($this->columns as $i => $render) {
|
||||
$grow = $this->weights[$i] ?? end($this->weights) ?: 1;
|
||||
$cols .= '<div class="rsv-col" style="--rsv-col-grow:' . (int) $grow . '">'
|
||||
. $this->capture($render)
|
||||
. '</div>';
|
||||
}
|
||||
return '<div class="rsv-cols">' . $cols . '</div>';
|
||||
}
|
||||
|
||||
public function output(): void
|
||||
{
|
||||
echo $this->render();
|
||||
}
|
||||
|
||||
/** Runs an echoing callable and returns what it printed. */
|
||||
private function capture(callable $render): string
|
||||
{
|
||||
ob_start();
|
||||
$render();
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user