| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502 | <?php/** * @package    Grav\Framework\ContentBlock * * @copyright  Copyright (c) 2015 - 2022 Trilby Media, LLC. All rights reserved. * @license    MIT License; see LICENSE file for details. */namespace Grav\Framework\ContentBlock;use RuntimeException;use function is_array;use function is_string;/** * HtmlBlock * * @package Grav\Framework\ContentBlock */class HtmlBlock extends ContentBlock implements HtmlBlockInterface{    /** @var int */    protected $version = 1;    /** @var array */    protected $frameworks = [];    /** @var array */    protected $styles = [];    /** @var array */    protected $scripts = [];    /** @var array */    protected $links = [];    /** @var array */    protected $html = [];    /**     * @return array     */    public function getAssets()    {        $assets = $this->getAssetsFast();        $this->sortAssets($assets['styles']);        $this->sortAssets($assets['scripts']);        $this->sortAssets($assets['links']);        $this->sortAssets($assets['html']);        return $assets;    }    /**     * @return array     */    public function getFrameworks()    {        $assets = $this->getAssetsFast();        return array_keys($assets['frameworks']);    }    /**     * @param string $location     * @return array     */    public function getStyles($location = 'head')    {        return $this->getAssetsInLocation('styles', $location);    }    /**     * @param string $location     * @return array     */    public function getScripts($location = 'head')    {        return $this->getAssetsInLocation('scripts', $location);    }    /**     * @param string $location     * @return array     */    public function getLinks($location = 'head')    {        return $this->getAssetsInLocation('links', $location);    }    /**     * @param string $location     * @return array     */    public function getHtml($location = 'bottom')    {        return $this->getAssetsInLocation('html', $location);    }    /**     * @return array     */    public function toArray()    {        $array = parent::toArray();        if ($this->frameworks) {            $array['frameworks'] = $this->frameworks;        }        if ($this->styles) {            $array['styles'] = $this->styles;        }        if ($this->scripts) {            $array['scripts'] = $this->scripts;        }        if ($this->links) {            $array['links'] = $this->links;        }        if ($this->html) {            $array['html'] = $this->html;        }        return $array;    }    /**     * @param array $serialized     * @return void     * @throws RuntimeException     */    public function build(array $serialized)    {        parent::build($serialized);        $this->frameworks = isset($serialized['frameworks']) ? (array) $serialized['frameworks'] : [];        $this->styles = isset($serialized['styles']) ? (array) $serialized['styles'] : [];        $this->scripts = isset($serialized['scripts']) ? (array) $serialized['scripts'] : [];        $this->links = isset($serialized['links']) ? (array) $serialized['links'] : [];        $this->html = isset($serialized['html']) ? (array) $serialized['html'] : [];    }    /**     * @param string $framework     * @return $this     */    public function addFramework($framework)    {        $this->frameworks[$framework] = 1;        return $this;    }    /**     * @param string|array $element     * @param int $priority     * @param string $location     * @return bool     *     * @example $block->addStyle('assets/js/my.js');     * @example $block->addStyle(['href' => 'assets/js/my.js', 'media' => 'screen']);     */    public function addStyle($element, $priority = 0, $location = 'head')    {        if (!is_array($element)) {            $element = ['href' => (string) $element];        }        if (empty($element['href'])) {            return false;        }        if (!isset($this->styles[$location])) {            $this->styles[$location] = [];        }        $id = !empty($element['id']) ? ['id' => (string) $element['id']] : [];        $href = $element['href'];        $type = !empty($element['type']) ? (string) $element['type'] : 'text/css';        $media = !empty($element['media']) ? (string) $element['media'] : null;        unset(            $element['tag'],            $element['id'],            $element['rel'],            $element['content'],            $element['href'],            $element['type'],            $element['media']        );        $this->styles[$location][md5($href) . sha1($href)] = [                ':type' => 'file',                ':priority' => (int) $priority,                'href' => $href,                'type' => $type,                'media' => $media,                'element' => $element            ] + $id;        return true;    }    /**     * @param string|array $element     * @param int $priority     * @param string $location     * @return bool     */    public function addInlineStyle($element, $priority = 0, $location = 'head')    {        if (!is_array($element)) {            $element = ['content' => (string) $element];        }        if (empty($element['content'])) {            return false;        }        if (!isset($this->styles[$location])) {            $this->styles[$location] = [];        }        $content = (string) $element['content'];        $type = !empty($element['type']) ? (string) $element['type'] : 'text/css';        unset($element['content'], $element['type']);        $this->styles[$location][md5($content) . sha1($content)] = [            ':type' => 'inline',            ':priority' => (int) $priority,            'content' => $content,            'type' => $type,            'element' => $element        ];        return true;    }    /**     * @param string|array $element     * @param int $priority     * @param string $location     * @return bool     */    public function addScript($element, $priority = 0, $location = 'head')    {        if (!is_array($element)) {            $element = ['src' => (string) $element];        }        if (empty($element['src'])) {            return false;        }        if (!isset($this->scripts[$location])) {            $this->scripts[$location] = [];        }        $src = $element['src'];        $type = !empty($element['type']) ? (string) $element['type'] : 'text/javascript';        $loading = !empty($element['loading']) ? (string) $element['loading'] : null;        $defer = !empty($element['defer']);        $async = !empty($element['async']);        $handle = !empty($element['handle']) ? (string) $element['handle'] : '';        unset($element['src'], $element['type'], $element['loading'], $element['defer'], $element['async'], $element['handle']);        $this->scripts[$location][md5($src) . sha1($src)] = [            ':type' => 'file',            ':priority' => (int) $priority,            'src' => $src,            'type' => $type,            'loading' => $loading,            'defer' => $defer,            'async' => $async,            'handle' => $handle,            'element' => $element        ];        return true;    }    /**     * @param string|array $element     * @param int $priority     * @param string $location     * @return bool     */    public function addInlineScript($element, $priority = 0, $location = 'head')    {        if (!is_array($element)) {            $element = ['content' => (string) $element];        }        if (empty($element['content'])) {            return false;        }        if (!isset($this->scripts[$location])) {            $this->scripts[$location] = [];        }        $content = (string) $element['content'];        $type = !empty($element['type']) ? (string) $element['type'] : 'text/javascript';        $loading = !empty($element['loading']) ? (string) $element['loading'] : null;        unset($element['content'], $element['type'], $element['loading']);        $this->scripts[$location][md5($content) . sha1($content)] = [            ':type' => 'inline',            ':priority' => (int) $priority,            'content' => $content,            'type' => $type,            'loading' => $loading,            'element' => $element        ];        return true;    }    /**     * @param string|array $element     * @param int $priority     * @param string $location     * @return bool     */    public function addModule($element, $priority = 0, $location = 'head')    {        if (!is_array($element)) {            $element = ['src' => (string) $element];        }        $element['type'] = 'module';        return $this->addScript($element, $priority, $location);    }    /**     * @param string|array $element     * @param int $priority     * @param string $location     * @return bool     */    public function addInlineModule($element, $priority = 0, $location = 'head')    {        if (!is_array($element)) {            $element = ['content' => (string) $element];        }        $element['type'] = 'module';        return $this->addInlineScript($element, $priority, $location);    }    /**     * @param array $element     * @param int $priority     * @param string $location     * @return bool     */    public function addLink($element, $priority = 0, $location = 'head')    {        if (!is_array($element) || empty($element['rel']) || empty($element['href'])) {            return false;        }        if (!isset($this->links[$location])) {            $this->links[$location] = [];        }        $rel = (string) $element['rel'];        $href = (string) $element['href'];        unset($element['rel'], $element['href']);        $this->links[$location][md5($href) . sha1($href)] = [            ':type' => 'file',            ':priority' => (int) $priority,            'href' => $href,            'rel' => $rel,            'element' => $element,        ];        return true;    }    /**     * @param string $html     * @param int $priority     * @param string $location     * @return bool     */    public function addHtml($html, $priority = 0, $location = 'bottom')    {        if (empty($html) || !is_string($html)) {            return false;        }        if (!isset($this->html[$location])) {            $this->html[$location] = [];        }        $this->html[$location][md5($html) . sha1($html)] = [            ':priority' => (int) $priority,            'html' => $html        ];        return true;    }    /**     * @return array     */    protected function getAssetsFast()    {        $assets = [            'frameworks' => $this->frameworks,            'styles' => $this->styles,            'scripts' => $this->scripts,            'links' => $this->links,            'html' => $this->html        ];        foreach ($this->blocks as $block) {            if ($block instanceof self) {                $blockAssets = $block->getAssetsFast();                $assets['frameworks'] += $blockAssets['frameworks'];                foreach ($blockAssets['styles'] as $location => $styles) {                    if (!isset($assets['styles'][$location])) {                        $assets['styles'][$location] = $styles;                    } elseif ($styles) {                        $assets['styles'][$location] += $styles;                    }                }                foreach ($blockAssets['scripts'] as $location => $scripts) {                    if (!isset($assets['scripts'][$location])) {                        $assets['scripts'][$location] = $scripts;                    } elseif ($scripts) {                        $assets['scripts'][$location] += $scripts;                    }                }                foreach ($blockAssets['links'] as $location => $links) {                    if (!isset($assets['links'][$location])) {                        $assets['links'][$location] = $links;                    } elseif ($links) {                        $assets['links'][$location] += $links;                    }                }                foreach ($blockAssets['html'] as $location => $htmls) {                    if (!isset($assets['html'][$location])) {                        $assets['html'][$location] = $htmls;                    } elseif ($htmls) {                        $assets['html'][$location] += $htmls;                    }                }            }        }        return $assets;    }    /**     * @param string $type     * @param string $location     * @return array     */    protected function getAssetsInLocation($type, $location)    {        $assets = $this->getAssetsFast();        if (empty($assets[$type][$location])) {            return [];        }        $styles = $assets[$type][$location];        $this->sortAssetsInLocation($styles);        return $styles;    }    /**     * @param array $items     * @return void     */    protected function sortAssetsInLocation(array &$items)    {        $count = 0;        foreach ($items as &$item) {            $item[':order'] = ++$count;        }        unset($item);        uasort(            $items,            static function ($a, $b) {                return $a[':priority'] <=> $b[':priority'] ?: $a[':order'] <=> $b[':order'];            }        );    }    /**     * @param array $array     * @return void     */    protected function sortAssets(array &$array)    {        foreach ($array as &$items) {            $this->sortAssetsInLocation($items);        }    }}
 |