Skip to content
Snippets Groups Projects
Select Git revision
  • e6a11cb96f7a0259554580369f41b2caf259c650
  • main default protected
  • step-3263
  • feature/plugins-cli
  • feature/vite
  • step-2484-peerreview
  • biest/issue-5051
  • tests/simplify-jsonapi-tests
  • fix/typo-in-1a70031
  • feature/broadcasting
  • database-seeders-and-factories
  • feature/peer-review-2
  • feature-feedback-jsonapi
  • feature/peerreview
  • feature/balloon-plus
  • feature/stock-images-unsplash
  • tic-2588
  • 5.0
  • 5.2
  • biest/unlock-blocks
  • biest-1514
21 results

ManagerApp.vue

Blame
  • Forked from Stud.IP / Stud.IP
    Source project has a limited visibility.
    Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    Icon.class.php 12.36 KiB
    <?php
    /**
     * Icon class is used to create icon objects which can be rendered as
     * svg. Output will be html. Optionally, the icon can be rendered
     * as a css background.
     *
     * @author    Jan-Hendrik Willms <tleilax+studip@gmail.com>
     * @copyright Stud.IP Core Group
     * @license   GPL2 or any later version
     * @since     3.2
     */
    class Icon
    {
        const SVG = 1;
        const CSS_BACKGROUND = 4;
        const INPUT = 256;
    
        const DEFAULT_SIZE = 16;
        const DEFAULT_COLOR = 'blue';
        const DEFAULT_ROLE = 'clickable';
    
        const ROLE_INFO          = 'info';
        const ROLE_CLICKABLE     = 'clickable';
        const ROLE_ACCEPT        = 'accept';
        const ROLE_STATUS_GREEN  = 'status-green';
        const ROLE_INACTIVE      = 'inactive';
        const ROLE_NAVIGATION    = 'navigation';
        const ROLE_NEW           = 'new';
        const ROLE_ATTENTION     = 'attention';
        const ROLE_STATUS_RED    = 'status-red';
        const ROLE_INFO_ALT      = 'info_alt';
        const ROLE_SORT          = 'sort';
        const ROLE_STATUS_YELLOW = 'status-yellow';
    
    
        protected $shape;
        protected $role;
        protected $attributes = [];
    
    
        /**
         * This is the magical Role to Color mapping.
         */
        private static $roles_to_colors = [
            self::ROLE_INFO          => 'black',
            self::ROLE_CLICKABLE     => 'blue',
            self::ROLE_ACCEPT        => 'green',
            self::ROLE_STATUS_GREEN  => 'green',
            self::ROLE_INACTIVE      => 'grey',
            self::ROLE_NAVIGATION    => 'blue',
            self::ROLE_NEW           => 'red',
            self::ROLE_ATTENTION     => 'red',
            self::ROLE_STATUS_RED    => 'red',
            self::ROLE_INFO_ALT      => 'white',
            self::ROLE_SORT          => 'blue',
            self::ROLE_STATUS_YELLOW => 'yellow'
        ];
    
        // return the color associated to a role
        private static function roleToColor($role)
        {
            if (!isset(self::$roles_to_colors[$role])) {
                throw new \InvalidArgumentException('Unknown role: "' . $role . '"');
            }
            return self::$roles_to_colors[$role];
        }
    
        // return the roles! associated to a color
        private static function colorToRoles($color)
        {
            static $colors_to_roles;
    
            if (!$colors_to_roles) {
                foreach (self::$roles_to_colors as $r => $c) {
                    $colors_to_roles[$c][] = $r;
                }
            }
    
            if (!isset($colors_to_roles[$color])) {
                throw new \InvalidArgumentException('Unknown color: "' . $color . '"');
            }
    
            return $colors_to_roles[$color];
        }
    
        /**
         * Create a new Icon object.
         *
         * This is just a factory method. You could easily just call the
         * constructor instead.
         *
         * @param String $shape      Shape of the icon, may contain a mixed definition
         *                           like 'seminar'
         * @param String $role       Role of the icon, defaults to Icon::DEFAULT_ROLE
         * @param Array $attributes  Additional attributes like 'title';
         *                           only use semantic ones describing
         *                           this icon regardless of its later
         *                           rendering in a view
         * @return Icon object
         */
        public static function create($shape, $role = Icon::DEFAULT_ROLE, $attributes = [])
        {
            // $role may be omitted
            if (is_array($role)) {
                $attributes = $role;
                $role = Icon::DEFAULT_ROLE;
            }
    
            return new self($shape, $role, $attributes);
        }
    
        /**
         * Constructor of the object.
         *
         * @param String $shape      Shape of the icon, may contain a mixed definition
         *                           like 'seminar'
         * @param String $role       Role of the icon, defaults to Icon::DEFAULT_ROLE
         * @param Array $attributes  Additional attributes like 'title';
         *                           only use semantic ones describing
         *                           this icon regardless of its later
         *                           rendering in a view
         */
        public function __construct($shape, $role = Icon::DEFAULT_ROLE, array $attributes = [])
        {
    
            // only defined roles
            if (!isset(self::$roles_to_colors[$role])) {
                throw new \InvalidArgumentException('Creating an Icon without proper role: "' . $role . '"');
            }
    
            // only semantic attributes
            if ($non_semantic = array_filter(array_keys($attributes), function ($attr) {
                return !in_array($attr, ['title']);
            })) {
                // DEPRECATED
                // TODO starting with the v3.6 the following line should
                // be enabled to prevent non-semantic attributes in this position
                # throw new \InvalidArgumentException('Creating an Icon with non-semantic attributes:' . json_encode($non_semantic));
            }
    
            $this->shape      = $shape;
            $this->role       = $role;
            $this->attributes = $attributes;
        }
    
        /**
         * Returns the `shape` -- the string describing the shape of this instance.
         * @return String  the shape of this Icon
         */
        public function getShape()
        {
            return $this->shapeToPath($this->shape);
        }
    
        /**
         * Returns the `role` -- the string describing the role of this instance.
         * @return String  the role of this Icon
         */
        public function getRole()
        {
            return $this->role;
        }
    
        /**
         * Returns the semantic `attributes` of this instance, e.g. the title of this Icon
         * @return Array  the semantic attribiutes of the Icon
         */
        public function getAttributes()
        {
            return $this->attributes;
        }
    
        /**
         * Returns whether this icon intends to signal attention.
         *
         * @todo This is currently just a heuristic based on the associated icon
         *       role. Although this is sufficient for the current requirements,
         *       it could probably in a better, more suitable way.
         *
         * @return bool
         * @since Stud.IP 5.0
         */
        public function signalsAttention()
        {
            return $this->roleToColor($this->role) === 'red';
        }
    
        /**
         * Function to be called whenever the object is converted to
         * string. Internally the same as calling Icon::asImg
         *
         * @return String representation
         */
        public function __toString()
        {
            return $this->asImg();
        }
    
        /**
         * Renders the icon inside an img html tag.
         *
         * @param int   $size             Optional; Defines the dimension in px of the rendered icon; FALSE prevents any
         *                                width or height attributes
         * @param Array $view_attributes  Optional; Additional attributes to pass
         *                                into the rendered output
         * @return String containing the html representation for the icon.
         */
        public function asImg($size = null, $view_attributes = [])
        {
            if (is_array($size)) {
                list($view_attributes, $size) = [$size, null];
            }
            return sprintf(
                '<img %s>',
                arrayToHtmlAttributes(
                    $this->prepareHTMLAttributes($size, $view_attributes)
                )
            );
        }
    
        /**
         * Renders the icon inside an input html tag.
         *
         * @param int   $size             Optional; Defines the dimension in px of the rendered icon; FALSE prevents any
         *                                width or height attributes
         * @param Array $view_attributes  Optional; Additional attributes to pass
         *                                into the rendered output
         * @return String containing the html representation for the icon.
         */
        public function asInput($size = null, $view_attributes = [])
        {
            if (is_array($size)) {
                list($view_attributes, $size) = [$size, null];
            }
            return sprintf(
                '<input type="image" %s>',
                arrayToHtmlAttributes(
                    $this->prepareHTMLAttributes($size, $view_attributes)
                )
            );
        }
    
        /**
         * Renders the icon as a set of css background rules.
         *
         * @param int $size  Optional; Defines the size in px of the rendered icon
         * @return String containing the html representation for css backgrounds
         */
        public function asCSS($size = null)
        {
            if (self::isStatic($this->shape)) {
                return sprintf(
                    'background-image:url(%1$s);background-size:%2$upx %2$upx;',
                    $this->shapeToPath($this->shape),
                    $this->get_size($size)
                );
            }
    
            return sprintf(
                'background-image:url(%1$s);background-size:%2$upx %2$upx;',
                $this->get_asset_svg(),
                $this->get_size($size)
            );
        }
    
        /**
         * Returns a path to the SVG matching the icon.
         *
         * @return String containing the html representation for css backgrounds
         */
        public function asImagePath()
        {
            return $this->prepareHTMLAttributes(false, [])['src'];
        }
    
        /**
         * Returns a new Icon with a changed shape
         * @param mixed  $shape  New value of `shape`
         * @return Icon  A new Icon with a new `shape`
         */
        public function copyWithShape($shape)
        {
            $clone = clone $this;
            $clone->shape = $shape;
            return $clone;
        }
    
        /**
         * Returns a new Icon with a changed role
         * @param mixed  $role  New value of `role`
         * @return Icon  A new Icon with a new `role`
         */
        public function copyWithRole($role)
        {
            $clone = clone $this;
            $clone->role = $role;
            return $clone;
        }
    
        /**
         * Returns a new Icon with new attributes
         * @param mixed  $attributes  New value of `attributes`
         * @return Icon  A new Icon with a new `attributes`
         */
        public function copyWithAttributes($attributes)
        {
            $clone = clone $this;
            $clone->attributes = $attributes;
            return $clone;
        }
    
        /**
         * Prepares the html attributes for use assembling HTML attributes
         * from given shape, role, size, semantic and view attributes
         *
         * @param int   $size       Size of the icon
         * @param array $attributes Additional attributes
         * @return Array containing the merged attributes
         */
        private function prepareHTMLAttributes($size, $attributes)
        {
            $dimensions = [];
            if ($size !== false) {
                $size = $this->get_size($size);
                $dimensions = ['width'  => $size, 'height' => $size];
            }
    
            $result = array_merge($this->attributes, $attributes, $dimensions, [
                'src' => self::isStatic($this->shape) ? $this->shape : $this->get_asset_svg(),
            ]);
    
            if (!isset($result['alt']) && !isset($result['title'])) {
                //Add an empty alt attribute to prevent screen readers from
                //reading the URL of the icon:
                $result['alt'] = '';
            }
    
            $classNames = 'icon-role-' . $this->role;
    
            if (!self::isStatic($this->shape)) {
                $classNames .= ' icon-shape-' . $this->shape;
            }
    
            $result['class'] = isset($result['class']) ? $result['class'] . ' ' . $classNames : $classNames;
    
            return $result;
        }
    
        /**
         * Get the correct asset for an SVG icon.
         *
         * @return String containing the url of the corresponding asset
         */
        protected function get_asset_svg()
        {
            return Assets::url('images/icons/' . self::roleToColor($this->role) . '/' . $this->shapeToPath($this->shape) . '.svg');
        }
    
        /**
         * Get the size of the icon. If a size was passed as a parameter and
         * inside the attributes array during icon construction, the size from
         * the attributes will be used.
         *
         * @param int $size  size of the icon
         * @return int Size of the icon in pixels
         */
        protected function get_size($size)
        {
            $size = $size ?: Icon::DEFAULT_SIZE;
            if (isset($this->attributes['size'])) {
                $parts =  explode('@', $this->attributes['size'], 2);
                $size = $parts[0];
                $temp = $parts[1] ?? null;
                unset($this->attributes['size']);
            }
            return (int)$size;
        }
    
        // an icon is static if it starts with 'http'
        private static function isStatic($shape)
        {
            return mb_strpos($shape, 'http') === 0;
        }
    
        // transforms a shape w/ possible additions (`shape`) to a path `(addition/)?shape`
        private function shapeToPath()
        {
            return self::isStatic($this->shape)
                ? $this->shape :
                join('/', array_reverse(explode('+', preg_replace('/\.svg$/', '', $this->shape))));
        }
    }