diff options
| author | Philipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de> | 2024-09-24 10:53:31 +0200 |
|---|---|---|
| committer | Philipp Schüttlöffel <schuettloeffel@zqs.uni-hannover.de> | 2024-09-24 10:53:31 +0200 |
| commit | 4459dd7917f4d1c34f40bb68f0e991e9c3d53e4c (patch) | |
| tree | 5c07151ae61276d334e88f6309c30d439a85c12e /lib/classes/Assets.php | |
| parent | da0022e5c1abbf9825ae76debaabdff7e8623bb4 (diff) | |
| parent | 97a188592c679890a25c37ab78463add76a52ff7 (diff) | |
Merge branch 'main' into issue-3911issue-3911
Diffstat (limited to 'lib/classes/Assets.php')
| -rw-r--r-- | lib/classes/Assets.php | 439 |
1 files changed, 439 insertions, 0 deletions
diff --git a/lib/classes/Assets.php b/lib/classes/Assets.php new file mode 100644 index 0000000..d4d792e --- /dev/null +++ b/lib/classes/Assets.php @@ -0,0 +1,439 @@ +<?php +# Lifter002: TODO +# Lifter005: TODO +# Lifter007: TODO +# Lifter003: TODO +# Lifter010: TODO + +/* + * Assets.php - assets helper + * + * Copyright (C) 2007 - Marcus Lunzenauer <mlunzena@uos.de> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + + +/** + * This class is used to construct URLs for static content like images, + * stylesheets or javascripts. As the URL to the "assets" directory is + * configurable one always has to construct the above mentioned URLs + * dynamically. + * + * Example: + * + * # construct the URL for the image "blank.gif" + * $url = Assets::image_path('blank.gif'); + * + * @package studip + * + * @author mlunzena + * @copyright (c) Authors + */ +class Assets +{ + + const NUMBER_OF_ALIASES = 2; + + /** + * @ignore + */ + private static $assets_url; + private static $assets_path; + private static $dynamic; + private static $counter_cache; + + /** + * This method sets the URL to your assets. + * + * @param string $path the path to the assets + */ + public static function set_assets_path(string $path): void + { + self::$assets_path = $path; + } + + /** + * This method sets the URL to your assets. + * + * @param string the URL to the assets + * + * @return void + */ + public static function set_assets_url($url) + { + self::$assets_url = $url; + self::$counter_cache = NULL; + self::$dynamic = mb_strpos($url, '%d') !== FALSE; + } + + /** + * This class method is an accessor to the URL "prefix" for all things "asset" + * Prepend the return value of this method to the relative path of the wanted + * static content. + * + * Additionally if the ASSETS_URL contains the string '%d', it will be + * replaced with a random number between 0 and 3. If you passed an argument + * this number will not be random but specific to that argument thus being + * referentially transparent. + * + * Example: + * + * # static ASSETS_URL + * $ASSETS_URL = 'http://www.example.com/public/'; + * echo Assets::url() . 'javascripts/prototype.js' . "\n"; + * echo Assets::url('javascripts/prototype.js') . "\n"; + * + * # output + * http://www.example.com/public/javascripts/prototype.js + * http://www.example.com/public/javascripts/prototype.js + * + * + * # dynamic ASSETS_URL + * $ASSETS_URL = 'http://www%d.example.com/public/'; + * echo Assets::url() . 'javascripts/prototype.js' . "\n"; + * echo Assets::url() . 'javascripts/prototype.js' . "\n"; + * echo Assets::url() . 'javascripts/prototype.js' . "\n"; + * echo Assets::url('javascripts/prototype.js') . "\n"; + * echo Assets::url('javascripts/prototype.js') . "\n"; + * echo Assets::url('javascripts/prototype.js') . "\n"; + * + * # output + * http://www0.example.com/public/javascripts/prototype.js + * http://www1.example.com/public/javascripts/prototype.js + * http://www2.example.com/public/javascripts/prototype.js + * http://www1.example.com/public/javascripts/prototype.js + * http://www1.example.com/public/javascripts/prototype.js + * http://www1.example.com/public/javascripts/prototype.js + * + * + * @param string an optional suffix which is used to construct a number if + * ASSETS_URL is dynamic (contains '%d') + * + * @return string the URL "prefix" + */ + public static function url($to = '') + { + if (!self::$dynamic) { + return self::$assets_url . $to; + } + + # dynamic ASSETS_URL + return sprintf(self::$assets_url, + $to == '' + ? self::$counter_cache++ % self::NUMBER_OF_ALIASES + # alternative implementation + # : hexdec(mb_substr(sha1($to),-1)) & 3) + : ord($to[1]) & (self::NUMBER_OF_ALIASES - 1)) + + . $to; + } + + /** + * This class method is an accessor to the path "prefix" for all things "asset" + */ + public static function path($to = ''): string + { + return self::$assets_path . $to; + } + + /** + * Returns an image tag using options as html attributes on the + * tag, but with these special cases: + * + * 'alt' - If no alt text is given, the file name part of the $source is used + * (capitalized and without the extension) + * * 'size' - Supplied as "X@Y", so "30@45" becomes width="30" and height="45" + * + * The source can be supplied as a... + * * full path, like "/my_images/image.gif" + * * file name, like "rss.png", that gets expanded to "/images/rss.png" + * * file name without extension, like "logo", that gets expanded to "/images/logo.png" + * + * Do not use this to render icons. Use the more appropiate class + * Icon for this. + */ + public static function img($source, $opt = []) + { + if (!$source) { + return ''; + } + + $size = $opt['size'] ?? null; + + $opt = self::parse_attributes($opt); + + $opt['src'] = self::image_path($source); + + if (!isset($opt['alt'])) { + $opt['alt'] = ucfirst(current(explode('.', basename($opt['src'])))); + } + + if (isset($size) && !isset($opt['width'])) { + $size = explode('@', $size, 2); + $opt['width'] = $size[0]; + $opt['height'] = $size[1] ?? null; + + unset($opt['size']); + } + + return self::tag('img', $opt); + } + + + /** + * Returns an input tag using options as html attributes on the + * tag, but with these special cases: + * + * * 'size' - Supplied as "X@Y", so "30@45" becomes width="30" and height="45" + * + * The source can be supplied as a... + * * full path, like "/my_images/image.gif" + * * file name, like "rss.png", that gets expanded to "/images/rss.png" + * * file name without extension, like "logo", that gets expanded to "/images/logo.png" + * + * Do not use this to render icons. Use the more appropiate class + * Icon for this. + */ + public static function input($source, $opt = []) + { + + if (!$source) { + return ''; + } + + $parts = explode('/', $source); + + $size = $opt['size']; + + $opt = self::parse_attributes($opt); + + $opt['src'] = self::image_path($source); + $opt['type'] = 'image'; + + if (isset($size) && !isset($opt['width'])) { + [$opt['width'], $opt['height']] = explode('@', $size, 2); + unset($opt['size']); + } + + return self::tag('input', $opt); + } + + /** + * Returns path to an image asset. + * + * Example: + * + * The src can be supplied as a... + * + * full path, + * like "/my_images/image.gif" + * + * file name, + * like "rss.png", that gets expanded to "/images/rss.png" + * + * file name without extension, + * like "logo", that gets expanded to "/images/logo.png" + * + * Note: This function should be private/depracated for the use in other + * scripts, as we would like to always generate the complete <image> oder + * <input> tag. Please use Assets::img or Assets::input instead. + */ + public static function image_path($source, $respect_retina = false) + { + $path = self::compute_public_path($source, 'images', 'png'); + + return $path; + } + + /** + * Returns a script include tag per source given as argument. + * + * Examples: + * + * Assets::script('prototype') => + * <script src="/javascript/prototype.js"></script> + * + * Assets::script('common.javascript', '/elsewhere/cools') => + * <script src="/js/common.javascript"></script> + * <script src="/elsewhere/cools.js"></script> + */ + public static function script($atLeastOneArgument) + { + $html = ''; + foreach (func_get_args() as $source) { + $source = self::javascript_path($source); + $html .= self::content_tag('script', '', + ['src' => $source]); + $html .= "\n"; + } + + return $html; + } + + + /** + * Returns path to a javascript asset. + * + * Example: + * + * Assets::javascript_path('ajax') => /javascripts/ajax.js + */ + public static function javascript_path($source) + { + return self::compute_public_path($source, 'javascripts', 'js'); + } + + + /** + * Returns a css link tag per source given as argument. + * + * Examples: + * + * Assets::stylesheet('style') => + * <link href="/stylesheets/style.css" media="screen" rel="stylesheet"> + * + * Assets::stylesheet('style', array('media' => 'all')) => + * <link href="/stylesheets/style.css" media="all" rel="stylesheet"> + * + * Assets::stylesheet('random.styles', '/css/stylish') => + * <link href="/stylesheets/random.styles" media="screen" rel="stylesheet"> + * <link href="/css/stylish.css" media="screen" rel="stylesheet"> + */ + public static function stylesheet($atLeastOneArgument) + { + $sources = func_get_args(); + $sourceOptions = (func_num_args() > 1 && + is_array($sources[func_num_args() - 1])) + ? array_pop($sources) + : []; + + $html = ''; + foreach ($sources as $source) { + $source = self::stylesheet_path($source); + $opt = array_merge(['rel' => 'stylesheet', + 'media' => 'screen', + 'href' => $source], + $sourceOptions); + $html .= self::tag('link', $opt) . "\n"; + } + + return $html; + } + + + /** + * Returns path to a stylesheet asset. + * + * Example: + * + * stylesheet_path('style') => /stylesheets/style.css + */ + public static function stylesheet_path($source) + { + return self::compute_public_path($source, 'stylesheets', 'css'); + } + + + /** + * This function computes the public path to the given source by using default + * dir and ext if not specified by the source. If source is not an absolute + * URL, the assets url is incorporated. + * + * @ignore + */ + private static function compute_public_path($source, $dir, $ext) + { + + # add extension if not present + if ('' == mb_substr(mb_strrchr($source, "."), 1)) + $source .= ".$ext"; + + # if source is not absolute + if (FALSE === mb_strpos($source, ':')) { + + # add dir if url does not contain a path + if ('/' !== $source[0]) + $source = "$dir/$source"; + + # consider asset host + $source = self::url(ltrim($source, '/')); + } + + return $source; + } + + + /** + * Constructs an html tag. + * + * @ignore + * + * @param string tag name + * @param array tag options + * @param boolean true to leave tag open + * + * @return string + */ + private static function tag($name, $options = [], $open = FALSE) + { + if (!$name) { + return ''; + } + + ksort($options); + return '<' . $name . ' ' . arrayToHtmlAttributes($options) . ($open ? '>' : '>'); + } + + + /** + * Helper function for content tags. + * + * @param string $name tag name + * @param string $content tag content + * @param array $options tag options + * + * @return string + */ + private static function content_tag($name, $content = '', $options = []) + { + if (!$name) { + return ''; + } + return '<' . $name . ' ' . arrayToHtmlAttributes($options) . '>' . + $content . + '</' . $name . '>'; + } + + /** + * Parse a HTML attribute string into an array. + * + * @ignore + */ + private static function parse_attributes($stringOrArray) + { + + if (is_array($stringOrArray)) + return $stringOrArray; + + preg_match_all('/ + \s*(\w+) # key \\1 + \s*=\s* # = + (\'|")? # values may be included in \' or " \\2 + (.*?) # value \\3 + (?(2) \\2) # matching \' or " if needed \\4 + \s*(?: + (?=\w+\s*=) | \s*$ # followed by another key= or the end of the string + ) + /x', $stringOrArray, $matches, PREG_SET_ORDER); + + $attributes = []; + foreach ($matches as $val) + $attributes[$val[1]] = $val[3]; + + return $attributes; + } +} |
