<?php
/* Events & the page lifecycle. $baseUrl is in scope (loadContent). */
$B = htmlspecialchars(rtrim((string) ($baseUrl ?? ''), '/'));
// A reusable "where do I paste this?" label. $lang = 'php' | 'js'.
if (!function_exists('pp_where')) {
    function pp_where(string $path, string $lang = 'php'): string {
        $l = $lang === 'js' ? 'JS' : 'PHP';
        return '<div class="help-where"><span class="help-where-tag"><i class="bi bi-geo-alt-fill"></i> Where</span>'
             . '<span class="help-where-path">' . $path . '</span>'
             . '<span class="help-where-lang ' . htmlspecialchars($lang) . '">' . $l . '</span></div>';
    }
}
?>
<h1><i class="bi bi-diagram-3-fill"></i> Events &amp; the page lifecycle</h1>
<p class="lead">Your app runs your code at <strong>events</strong> — precise moments in a page's life. This guide
shows every event, when it fires, and <strong>exactly where to paste your code</strong>. Two kinds:
<strong>Server</strong> events run in <span class="help-where-lang php">PHP</span> on the server;
<strong>Client</strong> events run in <span class="help-where-lang js">JS</span> in the browser.</p>

<div class="help-callout help-callout-info">
    <i class="bi bi-signpost-2"></i>
    <div><strong>Two places to write events.</strong> Most live in the <strong>Events</strong> module (open your
        project → <em>Events</em>). A few client-side ones can also be typed right on the component — e.g. a
        <a href="<?= $B ?>/help/component_custom_button">Custom&nbsp;Button</a>'s three code boxes. Wherever you write
        it, the app records it as one event.</div>
</div>

<h2>Contents</h2>
<ul>
    <li><a href="#lifecycle">The page lifecycle</a></li>
    <li><a href="#where">Where each event lives in the Events module</a></li>
    <li><a href="#page">Page events (server · PHP)</a></li>
    <li><a href="#client">Client events (browser · JS)</a></li>
    <li><a href="#field">Field events</a></li>
    <li><a href="#button">Button events</a></li>
    <li><a href="#global">Global events</a></li>
    <li><a href="#examples">Worked examples (with “Where”)</a></li>
</ul>

<h2 id="lifecycle">The page lifecycle</h2>
<p>When a visitor opens a page, events fire in order. A record being <strong>saved</strong> on the Add page, for
example, runs:</p>
<div class="help-life">
    <span class="step js">onPageInit (JS)</span><span class="arw">→</span>
    <span class="step php">Before Add Load (PHP)</span><span class="arw">→</span>
    <span class="step js">Before Form Submit (JS)</span><span class="arw">→</span>
    <span class="step php">Before Add Save (PHP)</span><span class="arw">→</span>
    <span class="step">DB insert</span><span class="arw">→</span>
    <span class="step php">After Add Save (PHP)</span>
</div>
<p>Pick the event by <em>what you need</em>: change what the user sees before they type → a <em>Before … Load</em>
event; validate or change data before it's written → a <em>Before … Save</em> event; react after it's stored (email,
log, redirect) → an <em>After … Save</em> event.</p>

<h2 id="where">Where each event lives in the Events module</h2>
<p>Open <strong>Events</strong> in your project. Events are grouped so you always know where to click:</p>
<table class="help-table">
    <thead><tr><th>You want…</th><th>Go to</th></tr></thead>
    <tbody>
        <tr><td>Something on one table's List/Add/Edit/View/Print/Export/Import</td><td><b>Table</b> → pick the table → <b>Page Events</b> (PHP) or <b>Client Events</b> (JS)</td></tr>
        <tr><td>Change the rows a list shows (filter/sort)</td><td><b>Table</b> → <b>SQL Modifiers</b> → Custom WHERE / ORDER BY</td></tr>
        <tr><td>React when one field changes / format one field</td><td><b>Table</b> → <b>Fields</b> → pick the field → <b>Client</b> (On Change…) or <b>Server</b> (Calculate…)</td></tr>
        <tr><td>Login, register, email, app start-up</td><td><b>Global Events</b> → Authentication / Email / Application…</td></tr>
        <tr><td>A named routine you call from JS</td><td><b>Custom Functions</b> → PHP (<code>action_&lt;name&gt;</code>) — call it with <code>pp.run('name', {…})</code></td></tr>
    </tbody>
</table>

<h2 id="page">Page events — server (PHP)</h2>
<p>Reached at <b>Events → &lt;Table&gt; → Page Events</b>. Each hands you variables to work with.</p>
<table class="help-table">
    <thead><tr><th>Event</th><th>Page</th><th>Fires</th><th>Key variables</th></tr></thead>
    <tbody>
        <tr><td><b>After List Load</b></td><td>List</td><td>after the rows are read</td><td><code>$rows</code></td></tr>
        <tr><td><b>Before Add Load</b></td><td>Add</td><td>before the empty form shows</td><td><code>$data</code> (defaults)</td></tr>
        <tr><td><b>Before Add Save</b></td><td>Add</td><td>before insert — validate/alter</td><td><code>$data</code> (by ref), <code>$errors</code></td></tr>
        <tr><td><b>After Add Save</b></td><td>Add</td><td>after insert — email/log</td><td><code>$data</code>, <code>$id</code></td></tr>
        <tr><td><b>Before Edit Load</b></td><td>Edit</td><td>before the form is filled</td><td><code>$data</code>, <code>$id</code></td></tr>
        <tr><td><b>Before Edit Save</b></td><td>Edit</td><td>before update</td><td><code>$data</code> (by ref), <code>$old</code>, <code>$id</code>, <code>$errors</code></td></tr>
        <tr><td><b>After Edit Save</b></td><td>Edit</td><td>after update</td><td><code>$data</code>, <code>$old</code>, <code>$id</code></td></tr>
        <tr><td><b>Before / After Delete</b></td><td>List/View</td><td>around a delete</td><td><code>$id</code></td></tr>
        <tr><td><b>Before View Load</b></td><td>View</td><td>before the record shows</td><td><code>$data</code>, <code>$id</code></td></tr>
        <tr><td><b>Before Search</b></td><td>List</td><td>before a search runs</td><td><code>$searchFor</code></td></tr>
        <tr><td><b>Before / After Export</b> · <b>Import</b></td><td>Export/Import</td><td>around data transfer</td><td><code>$data</code> / rows</td></tr>
        <tr><td><b>On Print</b></td><td>Print/PDF</td><td>when a printable page renders</td><td><code>$data</code></td></tr>
        <tr><td><b>Process Record Values</b></td><td>List/View</td><td>to reshape a value for display</td><td><code>$data</code></td></tr>
    </tbody>
</table>

<h2 id="client">Client events — browser (JS)</h2>
<p>Reached at <b>Events → &lt;Table&gt; → Client Events</b>. Here the <a href="<?= $B ?>/help/PPjs">Runner / pp.js API</a> shines.</p>
<table class="help-table">
    <thead><tr><th>Event</th><th>Page</th><th>Fires</th></tr></thead>
    <tbody>
        <tr><td><b>On Page Init</b></td><td>any</td><td>as soon as the page is ready — your “on load” hook</td></tr>
        <tr><td><b>After List Render</b></td><td>List</td><td>after the grid is drawn (colour rows, add handlers)</td></tr>
        <tr><td><b>On Row Click</b> · <b>On Row Select</b></td><td>List</td><td>when a row is clicked / ticked</td></tr>
        <tr><td><b>Before Form Submit</b></td><td>Add/Edit</td><td>before the form posts — <code>return false</code> to stop it</td></tr>
        <tr><td><b>After Delete Success</b></td><td>List/View</td><td>after a delete completes</td></tr>
    </tbody>
</table>

<h2 id="field">Field events</h2>
<p>Per-field, at <b>Events → &lt;Table&gt; → Fields → &lt;field&gt;</b>. <strong>Server (PHP):</strong>
<em>Format</em>, <em>Calculate</em>, <em>Validate</em>, <em>Before Set</em>, <em>After Set</em>.
<strong>Client (JS):</strong> <em>On Change</em>, <em>On Focus</em>, <em>On Blur</em>, <em>On Key Up</em>.</p>
<?= pp_where('Events → <b>orders</b> → Fields → <b>quantity</b> → <b>On Change</b> (Client)', 'js') ?>
<pre><code>// recompute the line total whenever quantity changes
var qty = +Runner.getControlValue('quantity') || 0;
var price = +Runner.getControlValue('price') || 0;
Runner.setControlValue('line_total', (qty * price).toFixed(2));</code></pre>

<h2 id="button">Button events</h2>
<p>A <a href="<?= $B ?>/help/component_custom_button"><strong>Custom&nbsp;Button</strong></a> has its own 3-stage
flow — Client Before (JS) → Server (PHP) → Client After (JS) — typed right in the button's Properties panel (and
mirrored into the Events module). See its guide for the full story.</p>

<h2 id="global">Global events</h2>
<p>App-wide, at <b>Global Events</b>: <em>Authentication</em> (Before/After Login, After Register…),
<em>Email</em> (Before/After Send), <em>Application</em> (App Init, Before Display, JS OnLoad, Menu Modify),
<em>File</em>, <em>API</em>. Use these for cross-cutting logic that isn't tied to one table.</p>
<?= pp_where('Global Events → Authentication → <b>After Login</b>', 'php') ?>
<pre><code>// stamp the user's last login time
dbExecute('UPDATE users SET last_login = ? WHERE id = ?', [now(), $user['id']]);</code></pre>

<h2 id="examples">Worked examples (with “Where”)</h2>

<h3>Set a default value on a new record</h3>
<?= pp_where('Events → <b>orders</b> → Page Events → <b>Before Add Load</b>', 'php') ?>
<pre><code>$data['status']     = 'draft';
$data['created_by'] = \PpPhp\Core\Security::CurrentUsername();
$data['order_date'] = today();</code></pre>

<h3>Validate before saving</h3>
<?= pp_where('Events → <b>orders</b> → Page Events → <b>Before Add Save</b>', 'php') ?>
<pre><code>if (($data['total'] ?? 0) &lt;= 0) {
    $errors[] = 'Total must be greater than zero.';
    return false;   // stops the save and shows the error
}</code></pre>

<h3>Email the customer after an order is created</h3>
<?= pp_where('Events → <b>orders</b> → Page Events → <b>After Add Save</b>', 'php') ?>
<pre><code>pp_send_email($data['customer_email'], 'Order received', 'Thanks! Your order #' . $id . ' is being prepared.');</code></pre>

<h3>Keep an audit trail of edits</h3>
<?= pp_where('Events → <b>orders</b> → Page Events → <b>After Edit Save</b>', 'php') ?>
<pre><code>dbExecute('INSERT INTO audit_log (table_name, record_id, changed_by, changed_at) VALUES (?,?,?,?)',
          ['orders', $id, \PpPhp\Core\Security::CurrentUsername(), now()]);</code></pre>

<h3>Focus the first field when the Add form opens</h3>
<?= pp_where('Events → <b>orders</b> → Client Events → <b>On Page Init</b>', 'js') ?>
<pre><code>if (Runner.getPageMode() === 'add') Runner.getControl(Runner.fields()[0]).focus();</code></pre>

<h3>Confirm before the form submits</h3>
<?= pp_where('Events → <b>orders</b> → Client Events → <b>Before Form Submit</b>', 'js') ?>
<pre><code>if (!await pp.dialog.confirm('Submit this order?', 'You can’t edit it afterwards.')) return false;</code></pre>

<div class="help-callout help-callout-info">
    <i class="bi bi-journal-code"></i>
    <div>Every example here also <strong>autocompletes in the Events editor</strong> — start typing
        <code>Runner.</code>, <code>pp.</code>, <code>db…</code> and pick from the suggestions, each with its own
        example. See the <a href="<?= $B ?>/help/PPjs">PP.js reference</a> and
        <a href="<?= $B ?>/help/DB">Database Helpers</a> for the full API.</div>
</div>
