steeffeen/FancyManiaLinks

View on GitHub
FML/Script/Features/Menu.php

Summary

Maintainability
A
0 mins
Test Coverage
F
48%
<?php

namespace FML\Script\Features;

use FML\Controls\Control;
use FML\Script\Builder;
use FML\Script\Script;
use FML\Script\ScriptLabel;

/**
 * Script Feature realising a Menu showing specific Controls for the different items
 *
 * @author    steeffeen
 * @copyright FancyManiaLinks Copyright © 2017 Steffen Schröder
 * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3
 */
class Menu extends ScriptFeature
{

    /*
     * Constants
     */
    const FUNCTION_UPDATE_MENU = "FML_UpdateMenu";

    /**
     * @var MenuElement[] $elements Menu Elements
     */
    protected $elements = array();

    /**
     * @var MenuElement $startElement Start Element
     */
    protected $startElement = null;

    /**
     * Construct a new Menu
     *
     * @api
     * @param Control $item           (optional) Item Control in the Menu bar
     * @param Control $control        (optional) Toggled Menu Control
     * @param bool    $isStartElement (optional) Whether the Menu should start with the given Element
     */
    public function __construct(Control $item = null, Control $control = null, $isStartElement = true)
    {
        if ($item && $control) {
            $this->addItem($item, $control, $isStartElement);
        }
    }

    /**
     * Get the Menu Elements
     *
     * @api
     * @return MenuElement[]
     */
    public function getElements()
    {
        return $this->elements;
    }

    /**
     * Add a Menu item
     *
     * @api
     * @param Control $item           Item Control in the Menu bar
     * @param Control $control        Toggled Menu Control
     * @param bool    $isStartElement (optional) Whether the Menu should start with this Element
     * @return static
     */
    public function addItem(Control $item, Control $control, $isStartElement = false)
    {
        $menuElement = new MenuElement($item, $control);
        $this->addElement($menuElement, $isStartElement);
        return $this;
    }

    /**
     * Add a Menu Element
     *
     * @api
     * @param MenuElement $menuElement    Menu Element
     * @param bool        $isStartElement (optional) Whether the Menu should start with this Element
     * @return static
     */
    public function addElement(MenuElement $menuElement, $isStartElement = false)
    {
        if (!in_array($menuElement, $this->elements, true)) {
            array_push($this->elements, $menuElement);
            if ($isStartElement) {
                // new start element
                $this->setStartElement($menuElement);
            } else {
                // additional element - set invisible
                $menuElement->getControl()
                            ->setVisible(false);
            }
        }
        return $this;
    }

    /**
     * Get the Element to start with
     *
     * @api
     * @return MenuElement
     */
    public function getStartElement()
    {
        return $this->startElement;
    }

    /**
     * Set the Element to start with
     *
     * @api
     * @param MenuElement $startElement Start Element
     * @return static
     */
    public function setStartElement(MenuElement $startElement = null)
    {
        $this->startElement = $startElement;
        if ($startElement && !in_array($startElement, $this->elements, true)) {
            array_push($this->elements, $startElement);
        }
        return $this;
    }

    /**
     * @see ScriptFeature::prepare()
     */
    public function prepare(Script $script)
    {
        $updateFunctionName = self::FUNCTION_UPDATE_MENU;
        $elementsArrayText  = $this->getElementsArrayText();

        // OnInit
        if ($this->startElement) {
            $startControlId = Builder::escapeText($this->startElement->getControl()
                                                                     ->getId());
            $initScriptText = "
{$updateFunctionName}({$elementsArrayText}, {$startControlId});";
            $script->appendGenericScriptLabel(ScriptLabel::ONINIT, $initScriptText, true);
        }

        // MouseClick
        $scriptText = "
declare MenuElements = {$elementsArrayText};
if (MenuElements.existskey(Event.Control.ControlId)) {
    declare ShownControlId = MenuElements[Event.Control.ControlId];
    {$updateFunctionName}(MenuElements, ShownControlId);
}";
        $script->appendGenericScriptLabel(ScriptLabel::MOUSECLICK, $scriptText, true);

        // Update menu function
        $updateFunctionText = "
Void {$updateFunctionName}(Text[Text] _Elements, Text _ShownControlId) {
    foreach (ItemId => ControlId in _Elements) {
        declare Control <=> (Page.GetFirstChild(ControlId));
        Control.Visible = (ControlId == _ShownControlId);
    }
}";
        $script->addScriptFunction($updateFunctionName, $updateFunctionText);

        return $this;
    }

    /**
     * Build the array text for the Elements
     *
     * @return string
     */
    protected function getElementsArrayText()
    {
        $elements = array();
        foreach ($this->elements as $element) {
            $elementId            = $element->getItem()
                                            ->getId();
            $elements[$elementId] = $element->getControl()
                                            ->getId();
        }
        return Builder::getArray($elements, true);
    }

}