536 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			536 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
 | 
						|
namespace FML\Script\Features;
 | 
						|
 | 
						|
use FML\Controls\Control;
 | 
						|
use FML\Controls\Label;
 | 
						|
use FML\Script\Builder;
 | 
						|
use FML\Script\Script;
 | 
						|
use FML\Script\ScriptInclude;
 | 
						|
use FML\Script\ScriptLabel;
 | 
						|
 | 
						|
/**
 | 
						|
 * Script Feature realizing a mechanism for browsing through Pages
 | 
						|
 *
 | 
						|
 * @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 Paging extends ScriptFeature
 | 
						|
{
 | 
						|
 | 
						|
    /*
 | 
						|
     * Constants
 | 
						|
     */
 | 
						|
    const VAR_CURRENT_PAGE             = "FML_Paging_CurrentPage";
 | 
						|
    const FUNCTION_UPDATE_CURRENT_PAGE = "FML_UpdateCurrentPage";
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var Label $label Page number Label
 | 
						|
     */
 | 
						|
    protected $label = null;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var PagingPage[] $pages Pages
 | 
						|
     */
 | 
						|
    protected $pages = array();
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var PagingButton[] $buttons Paging Buttons
 | 
						|
     */
 | 
						|
    protected $buttons = array();
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var int $startPageNumber Start Page number
 | 
						|
     */
 | 
						|
    protected $startPageNumber = null;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var int $customMaxPageNumber Custom maximum page number
 | 
						|
     */
 | 
						|
    protected $customMaxPageNumber = null;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var string $previousChunkAction Previous chunk action name
 | 
						|
     */
 | 
						|
    protected $previousChunkAction = null;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var string $nextChunkAction Next chunk action name
 | 
						|
     */
 | 
						|
    protected $nextChunkAction = null;
 | 
						|
 | 
						|
    /**
 | 
						|
     * @var bool $chunkActionAppendsPageNumber Chunk action appended with Page number
 | 
						|
     */
 | 
						|
    protected $chunkActionAppendsPageNumber = null;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Construct a new Paging
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @param Label          $label   (optional) Page number Label
 | 
						|
     * @param PagingPage[]   $pages   (optional) Pages
 | 
						|
     * @param PagingButton[] $buttons (optional) Pageing Buttons
 | 
						|
     */
 | 
						|
    public function __construct(Label $label = null, array $pages = null, array $buttons = null)
 | 
						|
    {
 | 
						|
        if ($label) {
 | 
						|
            $this->setLabel($label);
 | 
						|
        }
 | 
						|
        if ($pages) {
 | 
						|
            $this->setPages($pages);
 | 
						|
        }
 | 
						|
        if ($buttons) {
 | 
						|
            $this->setButtons($buttons);
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the Label showing the Page number
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @return Label
 | 
						|
     */
 | 
						|
    public function getLabel()
 | 
						|
    {
 | 
						|
        return $this->label;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set the Label showing the Page number
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @param Label $label Page number Label
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function setLabel(Label $label)
 | 
						|
    {
 | 
						|
        $label->checkId();
 | 
						|
        $this->label = $label;
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the Pages
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @return PagingPage[]
 | 
						|
     */
 | 
						|
    public function getPages()
 | 
						|
    {
 | 
						|
        return $this->pages;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Add a new Page Control
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @param Control $pageControl Page Control
 | 
						|
     * @param string  $pageNumber  (optional) Page number
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function addPageControl(Control $pageControl, $pageNumber = null)
 | 
						|
    {
 | 
						|
        if ($pageNumber === null) {
 | 
						|
            $pageNumber = count($this->pages) + 1;
 | 
						|
        }
 | 
						|
        $page = new PagingPage($pageControl, $pageNumber);
 | 
						|
        return $this->addPage($page);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Add a new Page
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @param PagingPage $page Page
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function addPage(PagingPage $page)
 | 
						|
    {
 | 
						|
        if (!in_array($page, $this->pages, true)) {
 | 
						|
            array_push($this->pages, $page);
 | 
						|
        }
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Add new Pages
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @param PagingPage[] $pages Pages
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function setPages(array $pages)
 | 
						|
    {
 | 
						|
        $this->pages = array();
 | 
						|
        foreach ($pages as $page) {
 | 
						|
            $this->addPage($page);
 | 
						|
        }
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the Buttons
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @return PagingButton[]
 | 
						|
     */
 | 
						|
    public function getButtons()
 | 
						|
    {
 | 
						|
        return $this->buttons;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Add a new Button Control to browse through the Pages
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @param Control $buttonControl Button used for browsing
 | 
						|
     * @param int     $browseAction  (optional) Number of browsed Pages per click
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function addButtonControl(Control $buttonControl, $browseAction = null)
 | 
						|
    {
 | 
						|
        if ($browseAction === null) {
 | 
						|
            $buttonCount = count($this->buttons);
 | 
						|
            if ($buttonCount % 2 === 0) {
 | 
						|
                $browseAction = $buttonCount / 2 + 1;
 | 
						|
            } else {
 | 
						|
                $browseAction = $buttonCount / -2 - 1;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        $button = new PagingButton($buttonControl, $browseAction);
 | 
						|
        return $this->addButton($button);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Add a new Button to browse through Pages
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @param PagingButton $button Paging Button
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function addButton(PagingButton $button)
 | 
						|
    {
 | 
						|
        if (!in_array($button, $this->buttons, true)) {
 | 
						|
            array_push($this->buttons, $button);
 | 
						|
        }
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set the Paging Buttons
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @param PagingButton[] $buttons Paging Buttons
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function setButtons(array $buttons)
 | 
						|
    {
 | 
						|
        $this->buttons = array();
 | 
						|
        foreach ($buttons as $button) {
 | 
						|
            $this->addButton($button);
 | 
						|
        }
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the start Page number
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @return int
 | 
						|
     */
 | 
						|
    public function getStartPageNumber()
 | 
						|
    {
 | 
						|
        return $this->startPageNumber;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set the start Page number
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @param int $startPageNumber Page number to start with
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function setStartPageNumber($startPageNumber)
 | 
						|
    {
 | 
						|
        $this->startPageNumber = (int)$startPageNumber;
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get a custom maximum Page number for using chunks
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @return int
 | 
						|
     */
 | 
						|
    public function getCustomMaxPageNumber()
 | 
						|
    {
 | 
						|
        return $this->customMaxPageNumber;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set a custom maximum Page number for using chunks
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @param int $maxPageNumber Custom maximum Page number
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function setCustomMaxPageNumber($maxPageNumber)
 | 
						|
    {
 | 
						|
        $this->customMaxPageNumber = (int)$maxPageNumber;
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the action triggered when the previous chunk is needed
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    public function getPreviousChunkAction()
 | 
						|
    {
 | 
						|
        return $this->previousChunkAction;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set the action triggered when the previous chunk is needed
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @param string $previousChunkAction Triggered action
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function setPreviousChunkAction($previousChunkAction)
 | 
						|
    {
 | 
						|
        $this->previousChunkAction = (string)$previousChunkAction;
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the action triggered when the next chunk is needed
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    public function getNextChunkAction()
 | 
						|
    {
 | 
						|
        return $this->nextChunkAction;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set the action triggered when the next chunk is needed
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @param string $nextChunkAction Triggered action
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function setNextChunkAction($nextChunkAction)
 | 
						|
    {
 | 
						|
        $this->nextChunkAction = (string)$nextChunkAction;
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set the actions triggered when another chunk is needed
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @param string $chunkAction Triggered action
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function setChunkActions($chunkAction)
 | 
						|
    {
 | 
						|
        return $this->setNextChunkAction($chunkAction)
 | 
						|
                    ->setPreviousChunkAction($chunkAction);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get if the chunk action should append the needed Page number
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @return bool
 | 
						|
     */
 | 
						|
    public function getChunkActionAppendsPageNumber()
 | 
						|
    {
 | 
						|
        return $this->chunkActionAppendsPageNumber;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Set if the chunk action should append the needed Page number
 | 
						|
     *
 | 
						|
     * @api
 | 
						|
     * @param bool $appendPageNumber Append the needed Page number
 | 
						|
     * @return static
 | 
						|
     */
 | 
						|
    public function setChunkActionAppendsPageNumber($appendPageNumber)
 | 
						|
    {
 | 
						|
        $this->chunkActionAppendsPageNumber = (bool)$appendPageNumber;
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @see ScriptFeature::prepare()
 | 
						|
     */
 | 
						|
    public function prepare(Script $script)
 | 
						|
    {
 | 
						|
        if (empty($this->pages)) {
 | 
						|
            return $this;
 | 
						|
        }
 | 
						|
        $script->setScriptInclude(ScriptInclude::TEXTLIB);
 | 
						|
 | 
						|
        $currentPageVariable = self::VAR_CURRENT_PAGE;
 | 
						|
        $updatePageFunction  = self::FUNCTION_UPDATE_CURRENT_PAGE;
 | 
						|
 | 
						|
        $minPageNumber   = 1;
 | 
						|
        $startPageNumber = (is_int($this->startPageNumber) ? $this->startPageNumber : $minPageNumber);
 | 
						|
        $maxPage         = $this->getMaxPage();
 | 
						|
        $maxPageNumber   = $this->customMaxPageNumber;
 | 
						|
        if (!is_int($maxPageNumber)) {
 | 
						|
            $maxPageNumber = $maxPage->getPageNumber();
 | 
						|
        }
 | 
						|
 | 
						|
        $pagingId    = $maxPage->getControl()
 | 
						|
                               ->getId(true, true);
 | 
						|
        $pagingId    = Builder::escapeText($maxPage->getControl()
 | 
						|
                                                   ->getId());
 | 
						|
        $pageLabelId = Builder::EMPTY_STRING;
 | 
						|
        if ($this->label) {
 | 
						|
            $pageLabelId = Builder::escapeText($this->label->getId());
 | 
						|
        }
 | 
						|
 | 
						|
        $pagesArrayText       = $this->getPagesArrayText();
 | 
						|
        $pageButtonsArrayText = $this->getPageButtonsArrayText();
 | 
						|
 | 
						|
        $previousChunkAction          = Builder::escapeText($this->previousChunkAction);
 | 
						|
        $nextChunkAction              = Builder::escapeText($this->nextChunkAction);
 | 
						|
        $chunkActionAppendsPageNumber = Builder::getBoolean($this->chunkActionAppendsPageNumber);
 | 
						|
 | 
						|
        // Init
 | 
						|
        $initScriptText = "
 | 
						|
declare {$currentPageVariable} for This = Integer[Text];
 | 
						|
{$currentPageVariable}[{$pagingId}] = {$startPageNumber};
 | 
						|
{$updatePageFunction}({$pagingId}, {$pageLabelId}, 0, {$minPageNumber}, {$maxPageNumber}, {$pagesArrayText}, {$previousChunkAction}, {$nextChunkAction}, {$chunkActionAppendsPageNumber});";
 | 
						|
        $script->appendGenericScriptLabel(ScriptLabel::ONINIT, $initScriptText, true);
 | 
						|
 | 
						|
        // MouseClick
 | 
						|
        $clickScriptText = "
 | 
						|
declare PageButtons = {$pageButtonsArrayText};
 | 
						|
if (PageButtons.existskey(Event.Control.ControlId)) {
 | 
						|
	declare BrowseAction = PageButtons[Event.Control.ControlId];
 | 
						|
	{$updatePageFunction}({$pagingId}, {$pageLabelId}, BrowseAction, {$minPageNumber}, {$maxPageNumber}, {$pagesArrayText}, {$previousChunkAction}, {$nextChunkAction}, {$chunkActionAppendsPageNumber});
 | 
						|
}";
 | 
						|
        $script->appendGenericScriptLabel(ScriptLabel::MOUSECLICK, $clickScriptText, true);
 | 
						|
 | 
						|
        // Update function
 | 
						|
        $functionText = "
 | 
						|
Void {$updatePageFunction}(Text _PagingId, Text _PageLabelId, Integer _BrowseAction, Integer _MinPageNumber, Integer _MaxPageNumber, Text[Integer] _Pages, Text _PreviousChunkAction, Text _NextChunkAction, Boolean _ChunkActionAppendPageNumber) {
 | 
						|
	declare {$currentPageVariable} for This = Integer[Text];
 | 
						|
	if (!{$currentPageVariable}.existskey(_PagingId)) return;
 | 
						|
	declare NewPageNumber = {$currentPageVariable}[_PagingId] + _BrowseAction;
 | 
						|
	if (NewPageNumber < _MinPageNumber) {
 | 
						|
		NewPageNumber = _MinPageNumber;
 | 
						|
	} else if (NewPageNumber > _MaxPageNumber) {
 | 
						|
		NewPageNumber = _MaxPageNumber;
 | 
						|
	}
 | 
						|
	{$currentPageVariable}[_PagingId] = NewPageNumber;
 | 
						|
	if (_Pages.existskey(NewPageNumber)) {
 | 
						|
        foreach (PageNumber => PageId in _Pages) {
 | 
						|
            declare PageControl <=> Page.GetFirstChild(PageId);
 | 
						|
            PageControl.Visible = (PageNumber == NewPageNumber);
 | 
						|
        }
 | 
						|
        if (_PageLabelId != \"\") {
 | 
						|
            declare PageLabel <=> (Page.GetFirstChild(_PageLabelId) as CMlLabel);
 | 
						|
            PageLabel.Value = NewPageNumber^\"/\"^_MaxPageNumber;
 | 
						|
        }
 | 
						|
	} else {
 | 
						|
		declare Text ChunkAction;
 | 
						|
		if (_BrowseAction < 0) {
 | 
						|
			ChunkAction = _PreviousChunkAction;
 | 
						|
		} else {
 | 
						|
			ChunkAction = _NextChunkAction;
 | 
						|
		}
 | 
						|
		if (_ChunkActionAppendPageNumber) {
 | 
						|
			ChunkAction ^= NewPageNumber;
 | 
						|
		}
 | 
						|
		TriggerPageAction(ChunkAction);
 | 
						|
	}
 | 
						|
}";
 | 
						|
        $script->addScriptFunction($updatePageFunction, $functionText);
 | 
						|
        return $this;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the minimum Page
 | 
						|
     *
 | 
						|
     * @return PagingPage
 | 
						|
     */
 | 
						|
    protected function getMinPage()
 | 
						|
    {
 | 
						|
        $minPageNumber = null;
 | 
						|
        $minPage       = null;
 | 
						|
        foreach ($this->pages as $page) {
 | 
						|
            $pageNumber = $page->getPageNumber();
 | 
						|
            if ($minPageNumber === null || $pageNumber < $minPageNumber) {
 | 
						|
                $minPageNumber = $pageNumber;
 | 
						|
                $minPage       = $page;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return $minPage;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Get the maximum Page
 | 
						|
     *
 | 
						|
     * @return PagingPage
 | 
						|
     */
 | 
						|
    protected function getMaxPage()
 | 
						|
    {
 | 
						|
        $maxPageNumber = null;
 | 
						|
        $maxPage       = null;
 | 
						|
        foreach ($this->pages as $page) {
 | 
						|
            $pageNumber = $page->getPageNumber();
 | 
						|
            if ($maxPageNumber === null || $pageNumber > $maxPageNumber) {
 | 
						|
                $maxPageNumber = $pageNumber;
 | 
						|
                $maxPage       = $page;
 | 
						|
            }
 | 
						|
        }
 | 
						|
        return $maxPage;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Build the array text for the Pages
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    protected function getPagesArrayText()
 | 
						|
    {
 | 
						|
        if (empty($this->pages)) {
 | 
						|
            return Builder::getArray(array(0 => ''), true);
 | 
						|
        }
 | 
						|
        $pages = array();
 | 
						|
        foreach ($this->pages as $page) {
 | 
						|
            $pages[$page->getPageNumber()] = $page->getControl()
 | 
						|
                                                  ->getId();
 | 
						|
        }
 | 
						|
        return Builder::getArray($pages, true);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Build the array text for the Page Buttons
 | 
						|
     *
 | 
						|
     * @return string
 | 
						|
     */
 | 
						|
    protected function getPageButtonsArrayText()
 | 
						|
    {
 | 
						|
        if (empty($this->buttons)) {
 | 
						|
            return Builder::getArray(array('' => 0), true);
 | 
						|
        }
 | 
						|
        $pageButtons = array();
 | 
						|
        foreach ($this->buttons as $pageButton) {
 | 
						|
            $pageButtons[$pageButton->getControl()
 | 
						|
                                    ->getId()] = $pageButton->getPagingCount();
 | 
						|
        }
 | 
						|
        return Builder::getArray($pageButtons, true);
 | 
						|
    }
 | 
						|
 | 
						|
}
 |