PHP Classes

File: src/App/View/Helper/HtmlAttrHelper.php

Recommend this page to a friend!
  Packages of Thierry Feuzeu   Jaxon   src/App/View/Helper/HtmlAttrHelper.php   Download  
File: src/App/View/Helper/HtmlAttrHelper.php
Role: Class source
Content type: text/plain
Description: Class source
Class: Jaxon
Call PHP classes from JavaScript using AJAX
Author: By
Last change:
Date: 1 year ago
Size: 5,379 bytes
 

Contents

Class file image Download
<?php

namespace Jaxon\App\View\Helper;

/**
 * HtmlAttrHelper.php
 *
 * Formatter for Jaxon custom HTML attributes.
 *
 * @package jaxon-core
 * @author Thierry Feuzeu
 * @copyright 2024 Thierry Feuzeu <thierry.feuzeu@gmail.com>
 * @license https://opensource.org/licenses/BSD-3-Clause BSD 3-Clause License
 * @link https://github.com/jaxon-php/jaxon-core
 */

use Jaxon\App\Component\Pagination;
use Jaxon\App\NodeComponent;
use Jaxon\Di\ComponentContainer;
use Jaxon\Script\JsExpr;
use Jaxon\Script\Call\JxnCall;

use function array_reduce;
use function count;
use function htmlentities;
use function is_a;
use function is_string;
use function Jaxon\rq;
use function json_encode;
use function trim;

class HtmlAttrHelper
{
    /**
     * @var string|null
     */
    private string|null $sPaginationComponent = null;

    /**
     * The constructor
     *
     * @param ComponentContainer $cdi
     */
    public function __construct(protected ComponentContainer $cdi)
    {}

    /**
     * Get the component HTML code
     *
     * @param JxnCall $xJsCall
     *
     * @return string
     */
    public function html(JxnCall $xJsCall): string
    {
        $sClassName = $xJsCall->_class();
        if(!$sClassName)
        {
            return '';
        }

        $xComponent = $this->cdi->makeComponent($sClassName);
        return is_a($xComponent, NodeComponent::class) ?
            (string)$xComponent->html() : '';
    }

    /**
     * Attach a component to a DOM node
     *
     * @param JxnCall $xJsCall
     * @param string $item
     *
     * @return string
     */
    public function bind(JxnCall $xJsCall, string $item = ''): string
    {
        $item = trim($item);
        return 'jxn-bind="' . $xJsCall->_class() . (!$item ? '"' : '" jxn-item="' . $item . '"');
    }

    /**
     * Attach the pagination component to a DOM node
     *
     * @param JxnCall $xJsCall
     *
     * @return string
     */
    public function pagination(JxnCall $xJsCall): string
    {
        // The pagination is always rendered with the same Pagination component.
        $sComponent = $this->sPaginationComponent ?:
            ($this->sPaginationComponent = rq(Pagination::class)->_class());
        $sItem = $xJsCall->_class();
        return "jxn-bind=\"$sComponent\" jxn-item=\"$sItem\"";
    }

    /**
     * Set a selector for the next event handler
     *
     * @param string $sSelector
     *
     * @return EventAttr
     */
    public function select(string $sSelector): EventAttr
    {
        return new EventAttr($sSelector);
    }

    /**
     * Set an event handler
     *
     * @param string $event
     * @param JsExpr $xJsExpr
     *
     * @return string
     */
    public function on(string $event, JsExpr $xJsExpr): string
    {
        $event = trim($event);
        $sCall = htmlentities(json_encode($xJsExpr->jsonSerialize()));
        return "jxn-on=\"$event\" jxn-call=\"$sCall\"";
    }

    /**
     * Shortcut to set a click event handler
     *
     * @param JsExpr $xJsExpr
     *
     * @return string
     */
    public function click(JsExpr $xJsExpr): string
    {
        return $this->on('click', $xJsExpr);
    }

    /**
     * @param array $aHandler
     *
     * @return bool
     */
    private function eventIsValid(array $aHandler): bool
    {
        return count($aHandler) === 3 &&
            isset($aHandler[0]) && isset($aHandler[1]) && isset($aHandler[2]) &&
            is_string($aHandler[0]) && is_string($aHandler[1]) &&
            is_a($aHandler[2], JsExpr::class);
    }

    /**
     * @param array $aHandler
     * @param EventAttr|null $xAttr
     *
     * @return EventAttr|null
     */
    private function setEventHandler(array $aHandler, ?EventAttr $xAttr = null): EventAttr|null
    {
        if(!$this->eventIsValid($aHandler))
        {
            return $xAttr;
        }
        // The array content is valid.
        [$sSelector, $sEvent, $xJsExpr] = $aHandler;
        return !$xAttr ?
            $this->select($sSelector)->on($sEvent, $xJsExpr) :
            $xAttr->select($sSelector)->on($sEvent, $xJsExpr);
    }

    /**
     * Set an event handler
     *
     * @param array $aHandler
     *
     * @return string
     */
    public function event(array $aHandler): string
    {
        return $this->setEventHandler($aHandler)?->__toString() ?? '';
    }

    /**
     * Set event handlers
     *
     * @param array $aHandlers
     *
     * @return string
     */
    public function events(array $aHandlers): string
    {
        return array_reduce($aHandlers, fn(EventAttr|null $xAttr, array $aHandler)
            => $this->setEventHandler($aHandler, $xAttr), null)?->__toString() ?? '';
    }

    /**
     * Get the HTML or Javascript ready code for a package
     *
     * @param string $sClass
     * @param string $sType
     *
     * @return string
     */
    public function package(string $sClass, string $sType = 'html'): string
    {
        $sCode = match($sType) {
            'html' => jaxon()->package($sClass)?->getHtml() ?? '',
            'ready' => jaxon()->package($sClass)?->getReadyScript() ?? '',
            default => ''
        };
        $sCode = trim($sCode);

        return $sType !== 'ready' || $sCode === '' ? $sCode :
            // Call the ready code with the jaxon.dom.ready function.
            "jaxon.dom.ready(() => $sCode)";
    }
}