360 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			360 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
namespace FML\Script;
 | 
						|
 | 
						|
use FML\Script\Features\ScriptFeature;
 | 
						|
 | 
						|
/**
 | 
						|
 * Class representing the ManiaLink Script
 | 
						|
 *
 | 
						|
 * @author    steeffeen <mail@steeffeen.com>
 | 
						|
 * @copyright FancyManiaLinks Copyright © 2017 Steffen Schröder
 | 
						|
 * @license   http://www.gnu.org/licenses/ GNU General Public License, Version 3
 | 
						|
 */
 | 
						|
class Script
 | 
						|
{
 | 
						|
 | 
						|
    /*
 | 
						|
     * Constants
 | 
						|
     */
 | 
						|
    const TICKINTERVAL    = 250;
 | 
						|
    const VAR_ScriptStart = 'FML_ScriptStart';
 | 
						|
    const VAR_LoopCounter = 'FML_LoopCounter';
 | 
						|
    const VAR_LastTick    = 'FML_LastTick';
 | 
						|
 | 
						|
    /*
 | 
						|
     * Protected properties
 | 
						|
     */
 | 
						|
    protected $tagName = 'script';
 | 
						|
    protected $features = array();
 | 
						|
    protected $includes = array();
 | 
						|
    protected $constants = array();
 | 
						|
    protected $functions = array();
 | 
						|
    protected $customLabels = array();
 | 
						|
    protected $genericLabels = array();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set a Script Include
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @param string|ScriptInclude $file      Include file or ScriptInclude
 | 
						|
     * @param string               $namespace Include namespace
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function setScriptInclude($file, $namespace = null)
 | 
						|
    {
 | 
						|
        if ($file instanceof ScriptInclude) {
 | 
						|
            $scriptInclude = $file;
 | 
						|
        } else {
 | 
						|
            $scriptInclude = new ScriptInclude($file, $namespace);
 | 
						|
        }
 | 
						|
        $this->includes[$scriptInclude->getNamespace()] = $scriptInclude;
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Add a Script Constant
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @param string|ScriptConstant $name  Constant name or ScriptConstant
 | 
						|
     * @param string                $value Constant value
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function addScriptConstant($name, $value = null)
 | 
						|
    {
 | 
						|
        if ($name instanceof ScriptConstant) {
 | 
						|
            $scriptConstant = $name;
 | 
						|
        } else {
 | 
						|
            $scriptConstant = new ScriptConstant($name, $value);
 | 
						|
        }
 | 
						|
        if (!in_array($scriptConstant, $this->constants)) {
 | 
						|
            array_push($this->constants, $scriptConstant);
 | 
						|
        }
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Add a Script Function
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @param string|ScriptFunction $name Function name or ScriptFunction
 | 
						|
     * @param string                $text Function text
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function addScriptFunction($name, $text = null)
 | 
						|
    {
 | 
						|
        if ($name instanceof ScriptFunction) {
 | 
						|
            $scriptFunction = $name;
 | 
						|
        } else {
 | 
						|
            $scriptFunction = new ScriptFunction($name, $text);
 | 
						|
        }
 | 
						|
        if (!in_array($scriptFunction, $this->functions)) {
 | 
						|
            array_push($this->functions, $scriptFunction);
 | 
						|
        }
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Add a custom Script text
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @param string|ScriptLabel $name Label name or ScriptLabel
 | 
						|
     * @param string             $text Script text
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function addCustomScriptLabel($name, $text = null)
 | 
						|
    {
 | 
						|
        if ($name instanceof ScriptLabel) {
 | 
						|
            $scriptLabel = $name;
 | 
						|
        } else {
 | 
						|
            $scriptLabel = new ScriptLabel($name, $text);
 | 
						|
        }
 | 
						|
        if (!in_array($scriptLabel, $this->customLabels)) {
 | 
						|
            array_push($this->customLabels, $scriptLabel);
 | 
						|
        }
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Append a generic Script text for the next rendering
 | 
						|
     *
 | 
						|
     * @TODO: get rid of generic script labels approach
 | 
						|
     * @param string|ScriptLabel $name     Label name or ScriptLabel
 | 
						|
     * @param string             $text     Script text
 | 
						|
     * @param bool               $isolated (optional) Whether to isolate the Label Script
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function appendGenericScriptLabel($name, $text = null, $isolated = false)
 | 
						|
    {
 | 
						|
        if ($name instanceof ScriptLabel) {
 | 
						|
            $scriptLabel = $name;
 | 
						|
        } else {
 | 
						|
            $scriptLabel = new ScriptLabel($name, $text, $isolated);
 | 
						|
        }
 | 
						|
        if (!in_array($scriptLabel, $this->genericLabels)) {
 | 
						|
            array_push($this->genericLabels, $scriptLabel);
 | 
						|
        }
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Remove all generic Script texts
 | 
						|
     *
 | 
						|
     * @TODO: get rid of generic script labels approach
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function resetGenericScriptLabels()
 | 
						|
    {
 | 
						|
        $this->genericLabels = array();
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Add a Script Feature
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @param ScriptFeature $feature Script Feature
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function addFeature(ScriptFeature $feature)
 | 
						|
    {
 | 
						|
        if (!in_array($feature, $this->features, true)) {
 | 
						|
            array_push($this->features, $feature);
 | 
						|
        }
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Load the given Script Feature
 | 
						|
     *
 | 
						|
     * @param ScriptFeature $scriptFeature Script Feature to load
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function loadFeature(ScriptFeature $scriptFeature)
 | 
						|
    {
 | 
						|
        $scriptFeature->prepare($this);
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Load the given Script Features
 | 
						|
     *
 | 
						|
     * @param ScriptFeature[] $scriptFeatures Script Features to load
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function loadFeatures(array $scriptFeatures)
 | 
						|
    {
 | 
						|
        foreach ($scriptFeatures as $scriptFeature) {
 | 
						|
            $this->loadFeature($scriptFeature);
 | 
						|
        }
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Check if the Script has content so that it needs to be rendered
 | 
						|
     *
 | 
						|
     * @return bool
 | 
						|
     */
 | 
						|
    public function needsRendering()
 | 
						|
    {
 | 
						|
        if ($this->features || $this->customLabels || $this->genericLabels) {
 | 
						|
            return true;
 | 
						|
        }
 | 
						|
        return false;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Build the complete Script text
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    public function buildScriptText()
 | 
						|
    {
 | 
						|
        $scriptText = PHP_EOL;
 | 
						|
        $scriptText .= $this->getHeaderComment();
 | 
						|
        $scriptText .= $this->getIncludes();
 | 
						|
        $scriptText .= $this->getConstants();
 | 
						|
        $scriptText .= $this->getFunctions();
 | 
						|
        $scriptText .= $this->getLabels();
 | 
						|
        $scriptText .= $this->getMainFunction();
 | 
						|
        return $scriptText;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Render the Script
 | 
						|
     *
 | 
						|
     * @param \DOMDocument $domDocument DOMDocument for which the Script should be created
 | 
						|
     * @return \DOMElement
 | 
						|
     */
 | 
						|
    public function render(\DOMDocument $domDocument)
 | 
						|
    {
 | 
						|
        $this->loadFeatures($this->features);
 | 
						|
        $scriptXml     = $domDocument->createElement($this->tagName);
 | 
						|
        $scriptText    = $this->buildScriptText();
 | 
						|
        $scriptComment = $domDocument->createComment($scriptText);
 | 
						|
        $scriptXml->appendChild($scriptComment);
 | 
						|
        return $scriptXml;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the header comment
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    protected function getHeaderComment()
 | 
						|
    {
 | 
						|
        $headerComment = '/****************************************************
 | 
						|
*		FancyManiaLinks';
 | 
						|
        if (defined('FML_VERSION')) {
 | 
						|
            $headerComment .= ' v' . FML_VERSION;
 | 
						|
        }
 | 
						|
        $headerComment .= ' by steeffeen	 		*
 | 
						|
*	http://github.com/steeffeen/FancyManiaLinks		*
 | 
						|
****************************************************/
 | 
						|
 | 
						|
';
 | 
						|
        return $headerComment;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the Includes text
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    protected function getIncludes()
 | 
						|
    {
 | 
						|
        $includesText = implode(PHP_EOL, $this->includes);
 | 
						|
        return $includesText;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the Constants text
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    protected function getConstants()
 | 
						|
    {
 | 
						|
        $constantsText = implode(PHP_EOL, $this->constants);
 | 
						|
        return $constantsText;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the Functions text
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    protected function getFunctions()
 | 
						|
    {
 | 
						|
        $functionsText = implode(PHP_EOL, $this->functions);
 | 
						|
        return $functionsText;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the Labels text
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    protected function getLabels()
 | 
						|
    {
 | 
						|
        $customLabelsText  = implode(PHP_EOL, $this->customLabels);
 | 
						|
        $genericLabelsText = implode(PHP_EOL, $this->genericLabels);
 | 
						|
        return $customLabelsText . $genericLabelsText;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the main function text
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    protected function getMainFunction()
 | 
						|
    {
 | 
						|
        $mainFunction = '
 | 
						|
Void FML_Dummy() {}
 | 
						|
main() {
 | 
						|
	declare ' . self::VAR_ScriptStart . ' = Now;
 | 
						|
	+++' . ScriptLabel::ONINIT . '+++
 | 
						|
	declare ' . self::VAR_LoopCounter . ' = 0;
 | 
						|
	declare ' . self::VAR_LastTick . ' = 0;
 | 
						|
	while (True) {
 | 
						|
		yield;
 | 
						|
		foreach (Event in PendingEvents) {
 | 
						|
			switch (Event.Type) {
 | 
						|
				case CMlEvent::Type::EntrySubmit: {
 | 
						|
					+++' . ScriptLabel::ENTRYSUBMIT . '+++
 | 
						|
				}
 | 
						|
				case CMlEvent::Type::KeyPress: {
 | 
						|
					+++' . ScriptLabel::KEYPRESS . '+++
 | 
						|
				}
 | 
						|
				case CMlEvent::Type::MouseClick: {
 | 
						|
					+++' . ScriptLabel::MOUSECLICK . '+++
 | 
						|
				}
 | 
						|
				case CMlEvent::Type::MouseOut: {
 | 
						|
					+++' . ScriptLabel::MOUSEOUT . '+++
 | 
						|
				}
 | 
						|
				case CMlEvent::Type::MouseOver: {
 | 
						|
					+++' . ScriptLabel::MOUSEOVER . '+++
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		+++' . ScriptLabel::LOOP . '+++
 | 
						|
		' . self::VAR_LoopCounter . ' += 1;
 | 
						|
		if (' . self::VAR_LastTick . ' + ' . self::TICKINTERVAL . ' > Now) continue;
 | 
						|
		+++' . ScriptLabel::TICK . '+++ 
 | 
						|
		' . self::VAR_LastTick . ' = Now;
 | 
						|
	}
 | 
						|
}';
 | 
						|
        return $mainFunction;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the string representation
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    public function __toString()
 | 
						|
    {
 | 
						|
        return $this->buildScriptText();
 | 
						|
    }
 | 
						|
 | 
						|
}
 |