Smarty Update to v5.4.3
This commit is contained in:
24
ReadMe.md
24
ReadMe.md
@@ -33,17 +33,19 @@ Alternative setup composer local zip file repot:
|
||||
1) Located in `Smarty/Smarty-Composer/vendor/smarty/smarty/src/`
|
||||
2) Alternative is to checkout master branch from git
|
||||
1) Located in `Smarty/Smarty-git/src/`
|
||||
3) copy over the following into `src/BlockHandler/`:
|
||||
1) T.php
|
||||
4) copy over the following into `src/FunctionHandler`:
|
||||
1) Popup.php
|
||||
2) PopupInit.php
|
||||
5) Upate the global `src/Extensions/DefaultExtension.php`:
|
||||
1) `getFunctionHandler`: popup_init, popup
|
||||
2) `getBlockHandler`: t
|
||||
6) check either `src/FunctionHander/HtmlCheckboxes.php` and `src/FunctionHander/HtmlOptions.php` have changed
|
||||
1) Update and leep the label/pos changes
|
||||
7) Create new release version as official relase number
|
||||
3) Copy the `src/` folder as is over the `Smarty/Smarty-Extended/src` folder
|
||||
4) From the `update/` folder copy
|
||||
1) copy over the following into `src/BlockHandler/`:
|
||||
1) T.php
|
||||
2) copy over the following into `src/FunctionHandler`:
|
||||
1) Popup.php
|
||||
2) PopupInit.php
|
||||
3) Upate the global `src/Extensions/DefaultExtension.php`:
|
||||
1) `getFunctionHandler`: popup_init, popup
|
||||
2) `getBlockHandler`: t
|
||||
4) check either `src/FunctionHander/HtmlCheckboxes.php` and `src/FunctionHander/HtmlOptions.php` have changed
|
||||
1) Update and leep the label/pos changes
|
||||
5) Create new release version as official relase number
|
||||
|
||||
## Updated files (different from master)
|
||||
|
||||
|
||||
@@ -14,6 +14,6 @@ class BlockPluginWrapper extends Base {
|
||||
}
|
||||
|
||||
public function handle($params, $content, Template $template, &$repeat) {
|
||||
return call_user_func_array($this->callback, [$params, $content, &$template, &$repeat]);
|
||||
return \call_user_func_array($this->callback, [$params, $content, &$template, &$repeat]);
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ abstract class Base
|
||||
*/
|
||||
abstract public function process(
|
||||
Template $_template,
|
||||
Cached $cached = null,
|
||||
?Cached $cached = null,
|
||||
$update = false
|
||||
);
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@ abstract class Custom extends Base
|
||||
*/
|
||||
public function process(
|
||||
Template $_smarty_tpl,
|
||||
\Smarty\Template\Cached $cached = null,
|
||||
?\Smarty\Template\Cached $cached = null,
|
||||
$update = false
|
||||
) {
|
||||
if (!$cached) {
|
||||
|
||||
@@ -99,7 +99,7 @@ class File extends Base
|
||||
*/
|
||||
public function process(
|
||||
Template $_smarty_tpl,
|
||||
Cached $cached = null,
|
||||
?Cached $cached = null,
|
||||
$update = false
|
||||
) {
|
||||
$_smarty_tpl->getCached()->setValid(false);
|
||||
|
||||
@@ -103,7 +103,7 @@ abstract class KeyValueStore extends Base
|
||||
*/
|
||||
public function process(
|
||||
Template $_smarty_tpl,
|
||||
Cached $cached = null,
|
||||
?Cached $cached = null,
|
||||
$update = false
|
||||
) {
|
||||
if (!$cached) {
|
||||
|
||||
@@ -41,7 +41,7 @@ class CodeFrame
|
||||
$content = '',
|
||||
$functions = '',
|
||||
$cache = false,
|
||||
\Smarty\Compiler\Template $compiler = null
|
||||
?\Smarty\Compiler\Template $compiler = null
|
||||
) {
|
||||
// build property code
|
||||
$properties[ 'version' ] = \Smarty\Smarty::SMARTY_VERSION;
|
||||
|
||||
@@ -374,7 +374,7 @@ class Template extends BaseCompiler {
|
||||
* @throws CompilerException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function compileTemplateSource(\Smarty\Template $template, \Smarty\Compiler\Template $parent_compiler = null) {
|
||||
public function compileTemplateSource(\Smarty\Template $template, ?\Smarty\Compiler\Template $parent_compiler = null) {
|
||||
try {
|
||||
// save template object in compiler class
|
||||
$this->template = $template;
|
||||
@@ -505,7 +505,7 @@ class Template extends BaseCompiler {
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function compileVariable($variable) {
|
||||
public function triggerTagNoCache($variable): void {
|
||||
if (!strpos($variable, '(')) {
|
||||
// not a variable variable
|
||||
$var = trim($variable, '\'');
|
||||
@@ -516,7 +516,6 @@ class Template extends BaseCompiler {
|
||||
false
|
||||
)->isNocache();
|
||||
}
|
||||
return '$_smarty_tpl->getValue(' . $variable . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -665,7 +664,7 @@ class Template extends BaseCompiler {
|
||||
$script = null;
|
||||
$cacheable = true;
|
||||
|
||||
$result = call_user_func_array(
|
||||
$result = \call_user_func_array(
|
||||
$defaultPluginHandlerFunc,
|
||||
[
|
||||
$tag,
|
||||
@@ -1281,9 +1280,10 @@ class Template extends BaseCompiler {
|
||||
}
|
||||
// call post compile callbacks
|
||||
foreach ($this->postCompileCallbacks as $cb) {
|
||||
$parameter = $cb;
|
||||
$parameter[0] = $this;
|
||||
call_user_func_array($cb[0], $parameter);
|
||||
$callbackFunction = $cb[0];
|
||||
$parameters = $cb;
|
||||
$parameters[0] = $this;
|
||||
$callbackFunction(...$parameters);
|
||||
}
|
||||
// return compiled code
|
||||
return $this->prefixCompiledCode . $this->parser->retvalue . $this->postfixCompiledCode;
|
||||
|
||||
@@ -16,14 +16,14 @@ class CompilerException extends Exception {
|
||||
* @param int $code The Exception code.
|
||||
* @param string|null $filename The filename where the exception is thrown.
|
||||
* @param int|null $line The line number where the exception is thrown.
|
||||
* @param Throwable|null $previous The previous exception used for the exception chaining.
|
||||
* @param \Throwable|null $previous The previous exception used for the exception chaining.
|
||||
*/
|
||||
public function __construct(
|
||||
string $message = "",
|
||||
int $code = 0,
|
||||
?string $filename = null,
|
||||
?int $line = null,
|
||||
Throwable $previous = null
|
||||
?\Throwable $previous = null
|
||||
) {
|
||||
parent::__construct($message, $code, $previous);
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ class CallbackWrapper {
|
||||
|
||||
public function handle(...$params) {
|
||||
try {
|
||||
return call_user_func_array($this->callback, $params);
|
||||
return ($this->callback)(...$params);
|
||||
} catch (\ArgumentCountError $e) {
|
||||
throw new Exception("Invalid number of arguments to modifier " . $this->modifierName);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ class HtmlBase extends Base {
|
||||
* @param $separator
|
||||
* @param $labels
|
||||
* @param $label_ids
|
||||
* @param $pos
|
||||
* @param bool $escape
|
||||
*
|
||||
* @return string
|
||||
@@ -31,7 +30,6 @@ class HtmlBase extends Base {
|
||||
$separator,
|
||||
$labels,
|
||||
$label_ids,
|
||||
$pos,
|
||||
$escape = true
|
||||
) {
|
||||
|
||||
@@ -85,7 +83,7 @@ class HtmlBase extends Base {
|
||||
}
|
||||
$_output .= '<input type="' . $inputType . '" name="' . $name;
|
||||
if ($ismultiselect) {
|
||||
$_output .= '[' . $pos . ']';
|
||||
$_output .= '[]';
|
||||
}
|
||||
$_output .= '" value="' . $value . '"';
|
||||
if ($labels && $label_ids) {
|
||||
@@ -106,4 +104,4 @@ class HtmlBase extends Base {
|
||||
return $_output;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,7 @@ use \Smarty\ParseTree\Code;
|
||||
use \Smarty\ParseTree\Dq;
|
||||
use \Smarty\ParseTree\DqContent;
|
||||
use \Smarty\ParseTree\Tag;
|
||||
|
||||
use \Smarty\CompilerException;
|
||||
|
||||
/**
|
||||
* Smarty Template Parser Class
|
||||
@@ -306,7 +306,8 @@ smartytag(A) ::= SIMPELOUTPUT(B). {
|
||||
$attributes[] = 'nocache';
|
||||
$var = $match[1];
|
||||
}
|
||||
A = $this->compiler->compilePrintExpression($this->compiler->compileVariable('\''.$var.'\''), $attributes);
|
||||
$this->compiler->triggerTagNoCache($var);
|
||||
A = $this->compiler->compilePrintExpression('$_smarty_tpl->getValue(\''.$var.'\')', $attributes);
|
||||
}
|
||||
|
||||
// simple tag like {name}
|
||||
@@ -375,7 +376,7 @@ outattr(A) ::= output(B) attributes(C). {
|
||||
A = array(B,C);
|
||||
}
|
||||
|
||||
output(A) ::= variable(B). {
|
||||
output(A) ::= variablevalue(B). {
|
||||
A = B;
|
||||
}
|
||||
output(A) ::= value(B). {
|
||||
@@ -689,7 +690,8 @@ nullcoalescing(res) ::= expr(v) QMARK QMARK expr(e2). {
|
||||
// ternary
|
||||
//
|
||||
ternary(res) ::= expr(v) QMARK DOLLARID(e1) COLON expr(e2). {
|
||||
res = v.' ? '. $this->compiler->compileVariable('\''.substr(e1,1).'\'') . ' : '.e2;
|
||||
$this->compiler->triggerTagNoCache(substr(e1,1));
|
||||
res = v.' ? $_smarty_tpl->getValue(\''.substr(e1,1).'\') : '.e2;
|
||||
}
|
||||
|
||||
ternary(res) ::= expr(v) QMARK value(e1) COLON expr(e2). {
|
||||
@@ -706,7 +708,7 @@ ternary(res) ::= expr(v) QMARK COLON expr(e2). {
|
||||
}
|
||||
|
||||
// value
|
||||
value(res) ::= variable(v). {
|
||||
value(res) ::= variablevalue(v). {
|
||||
res = v;
|
||||
}
|
||||
|
||||
@@ -724,7 +726,7 @@ value(res) ::= TYPECAST(t) value(v). {
|
||||
res = t.v;
|
||||
}
|
||||
|
||||
value(res) ::= variable(v) INCDEC(o). {
|
||||
value(res) ::= variablevalue(v) INCDEC(o). {
|
||||
res = v.o;
|
||||
}
|
||||
|
||||
@@ -771,10 +773,10 @@ value(res) ::= OPENP expr(e) CLOSEP. {
|
||||
res = '('. e .')';
|
||||
}
|
||||
|
||||
value(res) ::= variable(v1) INSTANCEOF(i) ns1(v2). {
|
||||
value(res) ::= variablevalue(v1) INSTANCEOF(i) ns1(v2). {
|
||||
res = v1.i.v2;
|
||||
}
|
||||
value(res) ::= variable(v1) INSTANCEOF(i) variable(v2). {
|
||||
value(res) ::= variablevalue(v1) INSTANCEOF(i) variablevalue(v2). {
|
||||
res = v1.i.v2;
|
||||
}
|
||||
|
||||
@@ -797,7 +799,8 @@ value(res) ::= varindexed(vi) DOUBLECOLON static_class_access(r). {
|
||||
if (vi['var'] === '\'smarty\'') {
|
||||
$this->compiler->appendPrefixCode("<?php {$prefixVar} = ". (new \Smarty\Compile\SpecialVariableCompiler())->compile(array(),$this->compiler,vi['smarty_internal_index']).';?>');
|
||||
} else {
|
||||
$this->compiler->appendPrefixCode("<?php {$prefixVar} = ". $this->compiler->compileVariable(vi['var']).vi['smarty_internal_index'].';?>');
|
||||
$this->compiler->triggerTagNoCache(vi['var']);
|
||||
$this->compiler->appendPrefixCode("<?php {$prefixVar} = \$_smarty_tpl->getValue(" . vi['var'] . ')'.vi['smarty_internal_index'].';?>');
|
||||
}
|
||||
res = $prefixVar .'::'.r[0].r[1];
|
||||
}
|
||||
@@ -847,54 +850,88 @@ ns1(res) ::= NAMESPACE(i). {
|
||||
}
|
||||
|
||||
|
||||
// variable lists
|
||||
|
||||
// multiple variables
|
||||
variablelist(res) ::= variablelist(l) COMMA variable(v). {
|
||||
res = array_merge(l,array(v));
|
||||
}
|
||||
|
||||
variablelist(res) ::= variablelist(l) COMMA expr(e). {
|
||||
res = array_merge(l,array(e));
|
||||
}
|
||||
|
||||
// single variable
|
||||
variablelist(res) ::= variable(v). {
|
||||
res = array(v);
|
||||
}
|
||||
|
||||
// single expression
|
||||
variablelist(res) ::= expr(e). {
|
||||
res = array(e);
|
||||
}
|
||||
|
||||
// no variable
|
||||
variablelist(res) ::= . {
|
||||
res = array();
|
||||
}
|
||||
|
||||
//
|
||||
// variables
|
||||
//
|
||||
// Smarty variable (optional array)
|
||||
variable(res) ::= DOLLARID(i). {
|
||||
res = $this->compiler->compileVariable('\''.substr(i,1).'\'');
|
||||
$this->compiler->triggerTagNoCache(substr(i,1));
|
||||
res = array('$_smarty_tpl->hasVariable(\''.substr(i,1).'\')','$_smarty_tpl->getValue(\''.substr(i,1).'\')');
|
||||
}
|
||||
variable(res) ::= varindexed(vi). {
|
||||
if (vi['var'] === '\'smarty\'') {
|
||||
$smarty_var = (new \Smarty\Compile\SpecialVariableCompiler())->compile(array(),$this->compiler,vi['smarty_internal_index']);
|
||||
res = $smarty_var;
|
||||
res = array('true', $smarty_var);
|
||||
} else {
|
||||
// used for array reset,next,prev,end,current
|
||||
$this->last_variable = vi['var'];
|
||||
$this->last_index = vi['smarty_internal_index'];
|
||||
res = $this->compiler->compileVariable(vi['var']).vi['smarty_internal_index'];
|
||||
$this->compiler->triggerTagNoCache(vi['var']);
|
||||
res = array('true', '$_smarty_tpl->getValue(' . vi['var'] . ')'.vi['smarty_internal_index']);
|
||||
}
|
||||
}
|
||||
|
||||
// variable with property
|
||||
variable(res) ::= varvar(v) AT ID(p). {
|
||||
res = '$_smarty_tpl->getVariable('. v .')->'.p;
|
||||
res = array('true', '$_smarty_tpl->getVariable('. v .')->'.p);
|
||||
}
|
||||
|
||||
// object
|
||||
variable(res) ::= object(o). {
|
||||
res = o;
|
||||
res = array('true', o);
|
||||
}
|
||||
|
||||
// config variable
|
||||
variable(res) ::= HATCH ID(i) HATCH. {
|
||||
configvariable(res) ::= HATCH ID(i) HATCH. {
|
||||
res = $this->compiler->compileConfigVariable('\'' . i . '\'');
|
||||
}
|
||||
|
||||
variable(res) ::= HATCH ID(i) HATCH arrayindex(a). {
|
||||
configvariable(res) ::= HATCH ID(i) HATCH arrayindex(a). {
|
||||
res = '(is_array($tmp = ' . $this->compiler->compileConfigVariable('\'' . i . '\'') . ') ? $tmp'.a.' :null)';
|
||||
}
|
||||
|
||||
variable(res) ::= HATCH variable(v) HATCH. {
|
||||
configvariable(res) ::= HATCH variablevalue(v) HATCH. {
|
||||
res = $this->compiler->compileConfigVariable(v);
|
||||
}
|
||||
|
||||
variable(res) ::= HATCH variable(v) HATCH arrayindex(a). {
|
||||
configvariable(res) ::= HATCH variablevalue(v) HATCH arrayindex(a). {
|
||||
res = '(is_array($tmp = ' . $this->compiler->compileConfigVariable(v) . ') ? $tmp'.a.' : null)';
|
||||
}
|
||||
|
||||
variablevalue(res) ::= variable(v). {
|
||||
res = v[1];
|
||||
}
|
||||
|
||||
variablevalue(res) ::= configvariable(v). {
|
||||
res = v;
|
||||
}
|
||||
|
||||
varindexed(res) ::= DOLLARID(i) arrayindex(a). {
|
||||
res = array('var'=>'\''.substr(i,1).'\'', 'smarty_internal_index'=>a);
|
||||
}
|
||||
@@ -918,14 +955,17 @@ arrayindex ::= . {
|
||||
// single index definition
|
||||
// Smarty2 style index
|
||||
indexdef(res) ::= DOT DOLLARID(i). {
|
||||
res = '['.$this->compiler->compileVariable('\''.substr(i,1).'\'').']';
|
||||
$this->compiler->triggerTagNoCache(substr(i,1));
|
||||
res = '[$_smarty_tpl->getValue(\''.substr(i,1).'\')]';
|
||||
}
|
||||
indexdef(res) ::= DOT varvar(v). {
|
||||
res = '['.$this->compiler->compileVariable(v).']';
|
||||
$this->compiler->triggerTagNoCache(v);
|
||||
res = '[$_smarty_tpl->getValue(' . v . ')]';
|
||||
}
|
||||
|
||||
indexdef(res) ::= DOT varvar(v) AT ID(p). {
|
||||
res = '['.$this->compiler->compileVariable(v).'->'.p.']';
|
||||
$this->compiler->triggerTagNoCache(v);
|
||||
res = '[$_smarty_tpl->getValue(' . v . ')->'.p.']';
|
||||
}
|
||||
|
||||
indexdef(res) ::= DOT ID(i). {
|
||||
@@ -956,9 +996,10 @@ indexdef(res) ::= OPENB INTEGER(n) CLOSEB. {
|
||||
res = '['.n.']';
|
||||
}
|
||||
indexdef(res) ::= OPENB DOLLARID(i) CLOSEB. {
|
||||
res = '['.$this->compiler->compileVariable('\''.substr(i,1).'\'').']';
|
||||
$this->compiler->triggerTagNoCache(substr(i,1));
|
||||
res = '[$_smarty_tpl->getValue(\''.substr(i,1).'\')]';
|
||||
}
|
||||
indexdef(res) ::= OPENB variable(v) CLOSEB. {
|
||||
indexdef(res) ::= OPENB variablevalue(v) CLOSEB. {
|
||||
res = '['.v.']';
|
||||
}
|
||||
indexdef(res) ::= OPENB value(v) CLOSEB. {
|
||||
@@ -1000,7 +1041,8 @@ varvarele(res) ::= ID(s). {
|
||||
}
|
||||
varvarele(res) ::= SIMPELOUTPUT(i). {
|
||||
$var = trim(substr(i, $this->compiler->getLdelLength(), -$this->compiler->getRdelLength()), ' $');
|
||||
res = $this->compiler->compileVariable('\''.$var.'\'');
|
||||
$this->compiler->triggerTagNoCache($var);
|
||||
res = '$_smarty_tpl->getValue(\''.$var.'\')';
|
||||
}
|
||||
|
||||
// variable sections of element
|
||||
@@ -1015,7 +1057,8 @@ object(res) ::= varindexed(vi) objectchain(oc). {
|
||||
if (vi['var'] === '\'smarty\'') {
|
||||
res = (new \Smarty\Compile\SpecialVariableCompiler())->compile(array(),$this->compiler,vi['smarty_internal_index']).oc;
|
||||
} else {
|
||||
res = $this->compiler->compileVariable(vi['var']).vi['smarty_internal_index'].oc;
|
||||
$this->compiler->triggerTagNoCache(vi['var']);
|
||||
res = '$_smarty_tpl->getValue(' . vi['var'] . ')'.vi['smarty_internal_index'].oc;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1041,7 +1084,8 @@ objectelement(res)::= PTR varvar(v) arrayindex(a). {
|
||||
if ($this->security) {
|
||||
$this->compiler->trigger_template_error (self::ERR2);
|
||||
}
|
||||
res = '->{'.$this->compiler->compileVariable(v).a.'}';
|
||||
$this->compiler->triggerTagNoCache(v);
|
||||
res = '->{$_smarty_tpl->getValue(' . v . ')'.a.'}';
|
||||
}
|
||||
|
||||
objectelement(res)::= PTR LDEL expr(e) RDEL arrayindex(a). {
|
||||
@@ -1067,8 +1111,41 @@ objectelement(res)::= PTR method(f). {
|
||||
//
|
||||
// function
|
||||
//
|
||||
function(res) ::= ns1(f) OPENP params(p) CLOSEP. {
|
||||
res = $this->compiler->compileModifierInExpression(f, p);
|
||||
function(res) ::= ns1(f) OPENP variablelist(v) CLOSEP. {
|
||||
|
||||
if (f == 'isset') {
|
||||
res = '(true';
|
||||
if (count(v) == 0) {
|
||||
throw new CompilerException("Invalid number of arguments for isset. isset expects at least one parameter.");
|
||||
}
|
||||
foreach (v as $value) {
|
||||
if (is_array($value)) {
|
||||
res .= ' && (' . $value[0] . ' && null !== (' . $value[1] . ' ?? null))';
|
||||
} else {
|
||||
res .= ' && (' . $value . ' !== null)';
|
||||
}
|
||||
}
|
||||
res .= ')';
|
||||
} elseif (f == 'empty') {
|
||||
if (count(v) != 1) {
|
||||
throw new CompilerException("Invalid number of arguments for empty. empty expects at exactly one parameter.");
|
||||
}
|
||||
if (is_array(v[0])) {
|
||||
res .= '( !' . v[0][0] . ' || empty(' . v[0][1] . '))';
|
||||
} else {
|
||||
res = 'false == ' . v[0];
|
||||
}
|
||||
} else {
|
||||
$p = array();
|
||||
foreach (v as $value) {
|
||||
if (is_array($value)) {
|
||||
$p[] = $value[1];
|
||||
} else {
|
||||
$p[] = $value;
|
||||
}
|
||||
}
|
||||
res = $this->compiler->compileModifierInExpression(f, $p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1087,7 +1164,8 @@ method(res) ::= DOLLARID(f) OPENP params(p) CLOSEP. {
|
||||
$this->compiler->trigger_template_error (self::ERR2);
|
||||
}
|
||||
$prefixVar = $this->compiler->getNewPrefixVariable();
|
||||
$this->compiler->appendPrefixCode("<?php {$prefixVar} = ".$this->compiler->compileVariable('\''.substr(f,1).'\'').';?>');
|
||||
$this->compiler->triggerTagNoCache(substr(f,1));
|
||||
$this->compiler->appendPrefixCode("<?php {$prefixVar} = \$_smarty_tpl->getValue('".substr(f,1).'\')'.';?>');
|
||||
res = $prefixVar .'('. implode(',',p) .')';
|
||||
}
|
||||
|
||||
@@ -1282,7 +1360,7 @@ doublequoted(res) ::= doublequotedcontent(o). {
|
||||
res = new Dq($this, o);
|
||||
}
|
||||
|
||||
doublequotedcontent(res) ::= BACKTICK variable(v) BACKTICK. {
|
||||
doublequotedcontent(res) ::= BACKTICK variablevalue(v) BACKTICK. {
|
||||
res = new Code('(string)'.v);
|
||||
}
|
||||
|
||||
@@ -1294,7 +1372,7 @@ doublequotedcontent(res) ::= DOLLARID(i). {
|
||||
res = new Code('(string)$_smarty_tpl->getValue(\''. substr(i,1) .'\')');
|
||||
}
|
||||
|
||||
doublequotedcontent(res) ::= LDEL variable(v) RDEL. {
|
||||
doublequotedcontent(res) ::= LDEL variablevalue(v) RDEL. {
|
||||
res = new Code('(string)'.v);
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ abstract class BasePlugin
|
||||
* @param Source $source source object
|
||||
* @param Template|null $_template template object
|
||||
*/
|
||||
abstract public function populate(Source $source, \Smarty\Template $_template = null);
|
||||
abstract public function populate(Source $source, ?\Smarty\Template $_template = null);
|
||||
|
||||
/**
|
||||
* populate Source Object with timestamp and exists from Resource
|
||||
|
||||
@@ -50,7 +50,7 @@ abstract class CustomPlugin extends BasePlugin {
|
||||
* @param Source $source source object
|
||||
* @param Template|null $_template template object
|
||||
*/
|
||||
public function populate(Source $source, Template $_template = null) {
|
||||
public function populate(Source $source, ?Template $_template = null) {
|
||||
$source->uid = sha1($source->type . ':' . $source->name);
|
||||
$mtime = $this->fetchTimestamp($source->name);
|
||||
if ($mtime !== null) {
|
||||
|
||||
@@ -23,7 +23,7 @@ class ExtendsPlugin extends BasePlugin
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function populate(Source $source, Template $_template = null)
|
||||
public function populate(Source $source, ?Template $_template = null)
|
||||
{
|
||||
$uid = '';
|
||||
$sources = array();
|
||||
@@ -93,7 +93,11 @@ class ExtendsPlugin extends BasePlugin
|
||||
*/
|
||||
public function getBasename(Source $source)
|
||||
{
|
||||
return str_replace(':', '.', basename($source->getResourceName()));
|
||||
$search = array(':');
|
||||
if (\Smarty\Smarty::$_IS_WINDOWS) {
|
||||
$search = array(':', '|');
|
||||
}
|
||||
return str_replace($search, '.', basename($source->getResourceName()));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -32,7 +32,7 @@ class FilePlugin extends BasePlugin {
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function populate(Source $source, Template $_template = null) {
|
||||
public function populate(Source $source, ?Template $_template = null) {
|
||||
|
||||
$source->uid = sha1(
|
||||
$source->name . ($source->isConfig ? $source->getSmarty()->_joined_config_dir :
|
||||
|
||||
@@ -33,7 +33,7 @@ class StreamPlugin extends RecompiledPlugin {
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function populate(Source $source, Template $_template = null) {
|
||||
public function populate(Source $source, ?Template $_template = null) {
|
||||
$source->uid = false;
|
||||
$source->content = $this->getContent($source);
|
||||
$source->timestamp = $source->exists = !!$source->content;
|
||||
|
||||
@@ -31,7 +31,7 @@ class StringPlugin extends BasePlugin {
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function populate(Source $source, Template $_template = null) {
|
||||
public function populate(Source $source, ?Template $_template = null) {
|
||||
$source->uid = sha1($source->name);
|
||||
$source->timestamp = $source->exists = true;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class DefaultPluginHandlerRuntime {
|
||||
$script = null;
|
||||
$cacheable = null;
|
||||
|
||||
return (call_user_func_array(
|
||||
return (\call_user_func_array(
|
||||
$this->defaultPluginHandler,
|
||||
[
|
||||
$tag,
|
||||
@@ -54,7 +54,7 @@ class DefaultPluginHandlerRuntime {
|
||||
$script = null;
|
||||
$cacheable = null;
|
||||
|
||||
if (call_user_func_array(
|
||||
if (\call_user_func_array(
|
||||
$this->defaultPluginHandler,
|
||||
[
|
||||
$tag,
|
||||
|
||||
@@ -162,7 +162,7 @@ class InheritanceRuntime {
|
||||
private function processBlock(
|
||||
Template $tpl,
|
||||
\Smarty\Runtime\Block $block,
|
||||
\Smarty\Runtime\Block $parent = null
|
||||
?\Smarty\Runtime\Block $parent = null
|
||||
) {
|
||||
if ($block->hide && !isset($block->child)) {
|
||||
return;
|
||||
|
||||
@@ -54,7 +54,7 @@ class Smarty extends \Smarty\TemplateBase {
|
||||
/**
|
||||
* smarty version
|
||||
*/
|
||||
const SMARTY_VERSION = '5.4.0';
|
||||
const SMARTY_VERSION = '5.4.3';
|
||||
|
||||
/**
|
||||
* define caching modes
|
||||
|
||||
@@ -115,7 +115,7 @@ class Template extends TemplateBase {
|
||||
public function __construct(
|
||||
$template_resource,
|
||||
Smarty $smarty,
|
||||
\Smarty\Data $_parent = null,
|
||||
?\Smarty\Data $_parent = null,
|
||||
$_cache_id = null,
|
||||
$_compile_id = null,
|
||||
$_caching = null,
|
||||
@@ -248,7 +248,7 @@ class Template extends TemplateBase {
|
||||
$caching,
|
||||
$cache_lifetime,
|
||||
array $extra_vars = [],
|
||||
int $scope = null,
|
||||
?int $scope = null,
|
||||
?string $currentDir = null
|
||||
) {
|
||||
|
||||
@@ -462,7 +462,7 @@ class Template extends TemplateBase {
|
||||
* @return string
|
||||
* @throws Exception
|
||||
*/
|
||||
public function createCodeFrame($content = '', $functions = '', $cache = false, \Smarty\Compiler\Template $compiler = null) {
|
||||
public function createCodeFrame($content = '', $functions = '', $cache = false, ?\Smarty\Compiler\Template $compiler = null) {
|
||||
return $this->getCodeFrameCompiler()->create($content, $functions, $cache, $compiler);
|
||||
}
|
||||
|
||||
|
||||
@@ -134,9 +134,9 @@ class Source {
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function load(
|
||||
Template $_template = null,
|
||||
Smarty $smarty = null,
|
||||
$template_resource = null
|
||||
?Template $_template = null,
|
||||
?Smarty $smarty = null,
|
||||
$template_resource = null
|
||||
) {
|
||||
if ($_template) {
|
||||
$smarty = $_template->getSmarty();
|
||||
@@ -203,7 +203,7 @@ class Source {
|
||||
*/
|
||||
public function _getDefaultTemplate($default_handler) {
|
||||
$_content = $_timestamp = null;
|
||||
$_return = call_user_func_array(
|
||||
$_return = \call_user_func_array(
|
||||
$default_handler,
|
||||
[$this->type, $this->name, &$_content, &$_timestamp, $this->smarty]
|
||||
);
|
||||
|
||||
@@ -179,7 +179,7 @@ abstract class TemplateBase extends Data {
|
||||
* @api Smarty::createData()
|
||||
*
|
||||
*/
|
||||
public function createData(Data $parent = null, $name = null) {
|
||||
public function createData(?Data $parent = null, $name = null) {
|
||||
/* @var Smarty $smarty */
|
||||
$smarty = $this->getSmarty();
|
||||
$dataObj = new Data($parent, $smarty, $name);
|
||||
|
||||
15
update/ReadMe.md
Normal file
15
update/ReadMe.md
Normal file
@@ -0,0 +1,15 @@
|
||||
# Files in this folder must be copied or merged over
|
||||
|
||||
The following files can be copied as is
|
||||
|
||||
- `src/BlockHandler/T.php`
|
||||
- `src/FunctionHandler/Popup.php`
|
||||
- `src/FunctionHandler/PopupInit.php`
|
||||
|
||||
The following files need to be checkd for changes.
|
||||
|
||||
If no changes they can be copied, else merged
|
||||
|
||||
- `src/FunctionHandler/HtmlCheckboxes.php`
|
||||
- `src/FunctionHandler/HtmlOptions.php`
|
||||
- `src/Extensions/DefaultExtensions.php`
|
||||
238
update/src/BlockHandler/T.php
Normal file
238
update/src/BlockHandler/T.php
Normal file
@@ -0,0 +1,238 @@
|
||||
<?php
|
||||
|
||||
namespace Smarty\BlockHandler;
|
||||
|
||||
// use Smarty\Smarty;
|
||||
use Smarty\Template;
|
||||
|
||||
/**
|
||||
* Smart {t}{/t} translation block plugin
|
||||
* Type: block function
|
||||
* Name: t
|
||||
* Purpose: translate text with gettext l10n class
|
||||
* Params:
|
||||
*
|
||||
* - escape - default html. else: javascript/js, url, no/off/false/'0'/0
|
||||
* - plural - pluaral option for gettext
|
||||
* - count - count option for gettext
|
||||
* - domain - domain name option for gettext
|
||||
* - context - context name option for gettext
|
||||
* - 1, 2, n - position for replace %n
|
||||
*
|
||||
* Must have the following functions loaded and defined before hand
|
||||
* d: domain
|
||||
* p: context
|
||||
* n: plural
|
||||
* - _dnpgettext - domain, plural, context gettext call
|
||||
* - _dngettext - domain, plural gettext call
|
||||
* - _npgettext - plural, contexct gettext call
|
||||
* - _ngettext - plural gettext call
|
||||
* - _dpgettext - domain, context gettext call
|
||||
* - _dgettext - domain gettext call
|
||||
* - _pgettext - context gettext calls
|
||||
* - _gettext - normal call
|
||||
*
|
||||
* @param array $params parameters
|
||||
* @param string $content contents of the block
|
||||
* @param Template $template template object
|
||||
* @param boolean &$repeat repeat flag
|
||||
*
|
||||
* @return string content re-formatted
|
||||
* @author Clemens Schwaighofer <gullevek at gullevek dot org>
|
||||
* @throws \Smarty\Exception
|
||||
*/
|
||||
class T implements BlockHandlerInterface
|
||||
{
|
||||
/**
|
||||
* Replaces arguments in a string with their values.
|
||||
* Arguments are represented by % followed by their number.
|
||||
*
|
||||
* @param string $str Source string
|
||||
* @param mixed mixed Arguments, can be passed in an array or through single variables.
|
||||
* @return string Modified string
|
||||
*/
|
||||
private function smartyGettextStrArg($str/*, $varargs... */)
|
||||
{
|
||||
$tr = [];
|
||||
$p = 0;
|
||||
|
||||
$nargs = func_num_args();
|
||||
for ($i = 1; $i < $nargs; $i++) {
|
||||
$arg = func_get_arg($i);
|
||||
|
||||
if (is_array($arg)) {
|
||||
foreach ($arg as $aarg) {
|
||||
$tr['%' . ++$p] = $aarg;
|
||||
}
|
||||
} else {
|
||||
$tr['%' . ++$p] = $arg;
|
||||
}
|
||||
}
|
||||
|
||||
return strtr($str, $tr);
|
||||
}
|
||||
|
||||
/**
|
||||
* raise a notice for missing callable, indicates L10n functions where not loaded
|
||||
*
|
||||
* @param string $function
|
||||
* @return void
|
||||
*/
|
||||
private function reportL10nNotInitialized(string $function): void
|
||||
{
|
||||
trigger_error("Missing " . $function . ", L10n::loadFunctions() called?", E_NOTICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* main handler
|
||||
*
|
||||
* @param array $params
|
||||
* @param string $content
|
||||
* @param Template $template
|
||||
* @param boolean $repeat
|
||||
* @return void
|
||||
*/
|
||||
public function handle($params, $content, Template $template, &$repeat)
|
||||
{
|
||||
if (is_null($content)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$escape = 'html';
|
||||
$plural = null;
|
||||
$count = null;
|
||||
$domain = null;
|
||||
$context = null;
|
||||
|
||||
foreach ($params as $_key => $_value) {
|
||||
switch ($_key) {
|
||||
// set escape mode, default html escape
|
||||
case 'escape':
|
||||
$escape = (string)$_value;
|
||||
break;
|
||||
// set plural parameters 'plural' and 'count'.
|
||||
case 'plural':
|
||||
$plural = $_value;
|
||||
break;
|
||||
// set count, only for plural, else ignored
|
||||
case 'count':
|
||||
$count = $_value;
|
||||
break;
|
||||
// get domain param
|
||||
case 'domain':
|
||||
$domain = (string)$_value;
|
||||
break;
|
||||
// get context param
|
||||
case 'context':
|
||||
$context = (string)$_value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// use plural if required parameters are set
|
||||
if (isset($count) && isset($plural)) {
|
||||
// plural calls
|
||||
if (isset($domain) && isset($context)) {
|
||||
if (is_callable('_dnpgettext')) {
|
||||
$content = _dnpgettext($domain, $context, $content, $plural, $count);
|
||||
} else {
|
||||
$this->reportL10nNotInitialized('_dnpgettext');
|
||||
}
|
||||
} elseif (isset($domain)) {
|
||||
if (is_callable('_dngettext')) {
|
||||
$content = _dngettext($domain, $content, $plural, $count);
|
||||
} else {
|
||||
$this->reportL10nNotInitialized('_dngettext');
|
||||
}
|
||||
} elseif (isset($context)) {
|
||||
if (is_callable('_npgettext')) {
|
||||
$content = _npgettext($context, $content, $plural, $count);
|
||||
} else {
|
||||
$this->reportL10nNotInitialized('_npgettext');
|
||||
}
|
||||
} else {
|
||||
if (is_callable('_ngettext')) {
|
||||
$content = _ngettext($content, $plural, $count);
|
||||
} else {
|
||||
$this->reportL10nNotInitialized('_ngettext');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// use normal
|
||||
if (isset($domain) && isset($context)) {
|
||||
if (is_callable('_dpgettext')) {
|
||||
$content = _dpgettext($domain, $context, $content);
|
||||
} else {
|
||||
$this->reportL10nNotInitialized('_dpgettext');
|
||||
}
|
||||
} elseif (isset($domain)) {
|
||||
if (is_callable('_dgettext')) {
|
||||
$content = _dgettext($domain, $content);
|
||||
} else {
|
||||
$this->reportL10nNotInitialized('_dgettext');
|
||||
}
|
||||
} elseif (isset($context)) {
|
||||
if (is_callable('_pgettext')) {
|
||||
$content = _pgettext($context, $content);
|
||||
} else {
|
||||
$this->reportL10nNotInitialized('_pgettext');
|
||||
}
|
||||
} else {
|
||||
if (is_callable('_gettext')) {
|
||||
$content = _gettext($content);
|
||||
} else {
|
||||
$this->reportL10nNotInitialized('_gettext');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// run strarg if there are parameters
|
||||
if (count($params)) {
|
||||
$content = $this->smartyGettextStrArg($content, $params);
|
||||
}
|
||||
|
||||
switch ($escape) {
|
||||
case 'html':
|
||||
// default
|
||||
$content = nl2br(htmlspecialchars($content));
|
||||
break;
|
||||
case 'javascript':
|
||||
case 'js':
|
||||
// javascript escape
|
||||
$content = strtr(
|
||||
$content,
|
||||
[
|
||||
'\\' => '\\\\',
|
||||
"'" => "\\'",
|
||||
'"' => '\\"',
|
||||
"\r" => '\\r',
|
||||
"\n" => '\\n',
|
||||
'</' => '<\/'
|
||||
]
|
||||
);
|
||||
break;
|
||||
case 'url':
|
||||
// url escape
|
||||
$content = urlencode($content);
|
||||
break;
|
||||
// below is a list for explicit OFF
|
||||
case 'no':
|
||||
case 'off':
|
||||
case 'false':
|
||||
case '0':
|
||||
case 0:
|
||||
// explicit OFF
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
public function isCacheable(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// __END__
|
||||
760
update/src/Extensions/DefaultExtension.php
Normal file
760
update/src/Extensions/DefaultExtension.php
Normal file
@@ -0,0 +1,760 @@
|
||||
<?php
|
||||
|
||||
namespace Smarty\Extension;
|
||||
|
||||
use Smarty\Exception;
|
||||
|
||||
class DefaultExtension extends Base {
|
||||
|
||||
private $modifiers = [];
|
||||
|
||||
private $functionHandlers = [];
|
||||
|
||||
private $blockHandlers = [];
|
||||
|
||||
public function getModifierCompiler(string $modifier): ?\Smarty\Compile\Modifier\ModifierCompilerInterface {
|
||||
|
||||
if (isset($this->modifiers[$modifier])) {
|
||||
return $this->modifiers[$modifier];
|
||||
}
|
||||
|
||||
switch ($modifier) {
|
||||
case 'cat': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\CatModifierCompiler(); break;
|
||||
case 'count_characters': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\CountCharactersModifierCompiler(); break;
|
||||
case 'count_paragraphs': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\CountParagraphsModifierCompiler(); break;
|
||||
case 'count_sentences': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\CountSentencesModifierCompiler(); break;
|
||||
case 'count_words': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\CountWordsModifierCompiler(); break;
|
||||
case 'default': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\DefaultModifierCompiler(); break;
|
||||
case 'empty': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\EmptyModifierCompiler(); break;
|
||||
case 'escape': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\EscapeModifierCompiler(); break;
|
||||
case 'from_charset': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\FromCharsetModifierCompiler(); break;
|
||||
case 'indent': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\IndentModifierCompiler(); break;
|
||||
case 'is_array': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\IsArrayModifierCompiler(); break;
|
||||
case 'isset': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\IssetModifierCompiler(); break;
|
||||
case 'json_encode': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\JsonEncodeModifierCompiler(); break;
|
||||
case 'lower': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\LowerModifierCompiler(); break;
|
||||
case 'nl2br': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\Nl2brModifierCompiler(); break;
|
||||
case 'noprint': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\NoPrintModifierCompiler(); break;
|
||||
case 'raw': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\RawModifierCompiler(); break;
|
||||
case 'round': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\RoundModifierCompiler(); break;
|
||||
case 'str_repeat': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\StrRepeatModifierCompiler(); break;
|
||||
case 'string_format': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\StringFormatModifierCompiler(); break;
|
||||
case 'strip': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\StripModifierCompiler(); break;
|
||||
case 'strip_tags': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\StripTagsModifierCompiler(); break;
|
||||
case 'strlen': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\StrlenModifierCompiler(); break;
|
||||
case 'substr': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\SubstrModifierCompiler(); break;
|
||||
case 'to_charset': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\ToCharsetModifierCompiler(); break;
|
||||
case 'unescape': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\UnescapeModifierCompiler(); break;
|
||||
case 'upper': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\UpperModifierCompiler(); break;
|
||||
case 'wordwrap': $this->modifiers[$modifier] = new \Smarty\Compile\Modifier\WordWrapModifierCompiler(); break;
|
||||
}
|
||||
|
||||
return $this->modifiers[$modifier] ?? null;
|
||||
}
|
||||
|
||||
public function getModifierCallback(string $modifierName) {
|
||||
switch ($modifierName) {
|
||||
case 'capitalize': return [$this, 'smarty_modifier_capitalize'];
|
||||
case 'count': return [$this, 'smarty_modifier_count'];
|
||||
case 'date_format': return [$this, 'smarty_modifier_date_format'];
|
||||
case 'debug_print_var': return [$this, 'smarty_modifier_debug_print_var'];
|
||||
case 'escape': return [$this, 'smarty_modifier_escape'];
|
||||
case 'explode': return [$this, 'smarty_modifier_explode'];
|
||||
case 'implode': return [$this, 'smarty_modifier_implode'];
|
||||
case 'in_array': return [$this, 'smarty_modifier_in_array'];
|
||||
case 'join': return [$this, 'smarty_modifier_join'];
|
||||
case 'mb_wordwrap': return [$this, 'smarty_modifier_mb_wordwrap'];
|
||||
case 'number_format': return [$this, 'smarty_modifier_number_format'];
|
||||
case 'regex_replace': return [$this, 'smarty_modifier_regex_replace'];
|
||||
case 'replace': return [$this, 'smarty_modifier_replace'];
|
||||
case 'spacify': return [$this, 'smarty_modifier_spacify'];
|
||||
case 'split': return [$this, 'smarty_modifier_split'];
|
||||
case 'truncate': return [$this, 'smarty_modifier_truncate'];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getFunctionHandler(string $functionName): ?\Smarty\FunctionHandler\FunctionHandlerInterface {
|
||||
|
||||
if (isset($this->functionHandlers[$functionName])) {
|
||||
return $this->functionHandlers[$functionName];
|
||||
}
|
||||
|
||||
switch ($functionName) {
|
||||
case 'count': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Count(); break;
|
||||
case 'counter': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Counter(); break;
|
||||
case 'cycle': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Cycle(); break;
|
||||
case 'fetch': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Fetch(); break;
|
||||
case 'html_checkboxes': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\HtmlCheckboxes(); break;
|
||||
case 'html_image': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\HtmlImage(); break;
|
||||
case 'html_options': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\HtmlOptions(); break;
|
||||
case 'html_radios': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\HtmlRadios(); break;
|
||||
case 'html_select_date': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\HtmlSelectDate(); break;
|
||||
case 'html_select_time': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\HtmlSelectTime(); break;
|
||||
case 'html_table': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\HtmlTable(); break;
|
||||
case 'mailto': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Mailto(); break;
|
||||
case 'math': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Math(); break;
|
||||
case 'popup_init': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\PopupInit(); break;
|
||||
case 'popup': $this->functionHandlers[$functionName] = new \Smarty\FunctionHandler\Popup(); break;
|
||||
}
|
||||
|
||||
return $this->functionHandlers[$functionName] ?? null;
|
||||
}
|
||||
|
||||
public function getBlockHandler(string $blockTagName): ?\Smarty\BlockHandler\BlockHandlerInterface {
|
||||
|
||||
switch ($blockTagName) {
|
||||
case 'textformat': $this->blockHandlers[$blockTagName] = new \Smarty\BlockHandler\TextFormat(); break;
|
||||
case 't': $this->blockHandlers[$blockTagName] = new \Smarty\BlockHandler\T(); break;
|
||||
}
|
||||
|
||||
return $this->blockHandlers[$blockTagName] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Smarty spacify modifier plugin
|
||||
* Type: modifier
|
||||
* Name: spacify
|
||||
* Purpose: add spaces between characters in a string
|
||||
*
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
*
|
||||
* @param string $string input string
|
||||
* @param string $spacify_char string to insert between characters.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function smarty_modifier_spacify($string, $spacify_char = ' ')
|
||||
{
|
||||
// well… what about charsets besides latin and UTF-8?
|
||||
return implode($spacify_char, preg_split('//' . \Smarty\Smarty::$_UTF8_MODIFIER, $string, -1, PREG_SPLIT_NO_EMPTY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Smarty capitalize modifier plugin
|
||||
* Type: modifier
|
||||
* Name: capitalize
|
||||
* Purpose: capitalize words in the string
|
||||
* {@internal {$string|capitalize:true:true} is the fastest option for MBString enabled systems }}
|
||||
*
|
||||
* @param string $string string to capitalize
|
||||
* @param boolean $uc_digits also capitalize "x123" to "X123"
|
||||
* @param boolean $lc_rest capitalize first letters, lowercase all following letters "aAa" to "Aaa"
|
||||
*
|
||||
* @return string capitalized string
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @author Rodney Rehm
|
||||
*/
|
||||
public function smarty_modifier_capitalize($string, $uc_digits = false, $lc_rest = false)
|
||||
{
|
||||
$string = (string) $string;
|
||||
|
||||
if ($lc_rest) {
|
||||
// uppercase (including hyphenated words)
|
||||
$upper_string = mb_convert_case($string, MB_CASE_TITLE, \Smarty\Smarty::$_CHARSET);
|
||||
} else {
|
||||
// uppercase word breaks
|
||||
$upper_string = preg_replace_callback(
|
||||
"!(^|[^\p{L}'])([\p{Ll}])!S" . \Smarty\Smarty::$_UTF8_MODIFIER,
|
||||
function ($matches) {
|
||||
return stripslashes($matches[1]) .
|
||||
mb_convert_case(stripslashes($matches[2]), MB_CASE_UPPER, \Smarty\Smarty::$_CHARSET);
|
||||
},
|
||||
$string
|
||||
);
|
||||
}
|
||||
// check uc_digits case
|
||||
if (!$uc_digits) {
|
||||
if (preg_match_all(
|
||||
"!\b([\p{L}]*[\p{N}]+[\p{L}]*)\b!" . \Smarty\Smarty::$_UTF8_MODIFIER,
|
||||
$string,
|
||||
$matches,
|
||||
PREG_OFFSET_CAPTURE
|
||||
)
|
||||
) {
|
||||
foreach ($matches[ 1 ] as $match) {
|
||||
$upper_string =
|
||||
substr_replace(
|
||||
$upper_string,
|
||||
mb_strtolower($match[ 0 ], \Smarty\Smarty::$_CHARSET),
|
||||
$match[ 1 ],
|
||||
strlen($match[ 0 ])
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
$upper_string =
|
||||
preg_replace_callback(
|
||||
"!((^|\s)['\"])(\w)!" . \Smarty\Smarty::$_UTF8_MODIFIER,
|
||||
function ($matches) {
|
||||
return stripslashes(
|
||||
$matches[ 1 ]) . mb_convert_case(stripslashes($matches[ 3 ]),
|
||||
MB_CASE_UPPER,
|
||||
\Smarty\Smarty::$_CHARSET
|
||||
);
|
||||
},
|
||||
$upper_string
|
||||
);
|
||||
return $upper_string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Smarty count modifier plugin
|
||||
* Type: modifier
|
||||
* Name: count
|
||||
* Purpose: counts all elements in an array or in a Countable object
|
||||
* Input:
|
||||
* - Countable|array: array or object to count
|
||||
* - mode: int defaults to 0 for normal count mode, if set to 1 counts recursive
|
||||
*
|
||||
* @param mixed $arrayOrObject input array/object
|
||||
* @param int $mode count mode
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function smarty_modifier_count($arrayOrObject, $mode = 0) {
|
||||
/*
|
||||
* @see https://www.php.net/count
|
||||
* > Prior to PHP 8.0.0, if the parameter was neither an array nor an object that implements the Countable interface,
|
||||
* > 1 would be returned, unless value was null, in which case 0 would be returned.
|
||||
*/
|
||||
|
||||
if ($arrayOrObject instanceof \Countable || is_array($arrayOrObject)) {
|
||||
return count($arrayOrObject, (int) $mode);
|
||||
} elseif ($arrayOrObject === null) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Smarty date_format modifier plugin
|
||||
* Type: modifier
|
||||
* Name: date_format
|
||||
* Purpose: format datestamps via strftime
|
||||
* Input:
|
||||
* - string: input date string
|
||||
* - format: strftime format for output
|
||||
* - default_date: default date if $string is empty
|
||||
*
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
*
|
||||
* @param string $string input date string
|
||||
* @param string $format strftime format for output
|
||||
* @param string $default_date default date if $string is empty
|
||||
* @param string $formatter either 'strftime' or 'auto'
|
||||
*
|
||||
* @return string |void
|
||||
* @uses smarty_make_timestamp()
|
||||
*/
|
||||
public function smarty_modifier_date_format($string, $format = null, $default_date = '', $formatter = 'auto')
|
||||
{
|
||||
if ($format === null) {
|
||||
$format = \Smarty\Smarty::$_DATE_FORMAT;
|
||||
}
|
||||
|
||||
if (!empty($string) && $string !== '0000-00-00' && $string !== '0000-00-00 00:00:00') {
|
||||
$timestamp = smarty_make_timestamp($string);
|
||||
} elseif (!empty($default_date)) {
|
||||
$timestamp = smarty_make_timestamp($default_date);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
if ($formatter === 'strftime' || ($formatter === 'auto' && strpos($format, '%') !== false)) {
|
||||
if (\Smarty\Smarty::$_IS_WINDOWS) {
|
||||
$_win_from = array(
|
||||
'%D',
|
||||
'%h',
|
||||
'%n',
|
||||
'%r',
|
||||
'%R',
|
||||
'%t',
|
||||
'%T'
|
||||
);
|
||||
$_win_to = array(
|
||||
'%m/%d/%y',
|
||||
'%b',
|
||||
"\n",
|
||||
'%I:%M:%S %p',
|
||||
'%H:%M',
|
||||
"\t",
|
||||
'%H:%M:%S'
|
||||
);
|
||||
if (strpos($format, '%e') !== false) {
|
||||
$_win_from[] = '%e';
|
||||
$_win_to[] = sprintf('%\' 2d', date('j', $timestamp));
|
||||
}
|
||||
if (strpos($format, '%l') !== false) {
|
||||
$_win_from[] = '%l';
|
||||
$_win_to[] = sprintf('%\' 2d', date('h', $timestamp));
|
||||
}
|
||||
$format = str_replace($_win_from, $_win_to, $format);
|
||||
}
|
||||
// @ to suppress deprecation errors when running in PHP8.1 or higher.
|
||||
return @strftime($format, $timestamp);
|
||||
} else {
|
||||
return date($format, $timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Smarty debug_print_var modifier plugin
|
||||
* Type: modifier
|
||||
* Name: debug_print_var
|
||||
* Purpose: formats variable contents for display in the console
|
||||
*
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
*
|
||||
* @param array|object $var variable to be formatted
|
||||
* @param int $max maximum recursion depth if $var is an array or object
|
||||
* @param int $length maximum string length if $var is a string
|
||||
* @param int $depth actual recursion depth
|
||||
* @param array $objects processed objects in actual depth to prevent recursive object processing
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function smarty_modifier_debug_print_var($var, $max = 10, $length = 40, $depth = 0, $objects = array())
|
||||
{
|
||||
$_replace = array("\n" => '\n', "\r" => '\r', "\t" => '\t');
|
||||
switch (gettype($var)) {
|
||||
case 'array':
|
||||
$results = '<b>Array (' . count($var) . ')</b>';
|
||||
if ($depth === $max) {
|
||||
break;
|
||||
}
|
||||
foreach ($var as $curr_key => $curr_val) {
|
||||
$results .= '<br>' . str_repeat(' ', $depth * 2) . '<b>' . strtr($curr_key, $_replace) .
|
||||
'</b> => ' .
|
||||
$this->smarty_modifier_debug_print_var($curr_val, $max, $length, ++$depth, $objects);
|
||||
$depth--;
|
||||
}
|
||||
break;
|
||||
case 'object':
|
||||
$object_vars = get_object_vars($var);
|
||||
$results = '<b>' . get_class($var) . ' Object (' . count($object_vars) . ')</b>';
|
||||
if (in_array($var, $objects)) {
|
||||
$results .= ' called recursive';
|
||||
break;
|
||||
}
|
||||
if ($depth === $max) {
|
||||
break;
|
||||
}
|
||||
$objects[] = $var;
|
||||
foreach ($object_vars as $curr_key => $curr_val) {
|
||||
$results .= '<br>' . str_repeat(' ', $depth * 2) . '<b> ->' . strtr($curr_key, $_replace) .
|
||||
'</b> = ' . $this->smarty_modifier_debug_print_var($curr_val, $max, $length, ++$depth, $objects);
|
||||
$depth--;
|
||||
}
|
||||
break;
|
||||
case 'boolean':
|
||||
case 'NULL':
|
||||
case 'resource':
|
||||
if (true === $var) {
|
||||
$results = 'true';
|
||||
} elseif (false === $var) {
|
||||
$results = 'false';
|
||||
} elseif (null === $var) {
|
||||
$results = 'null';
|
||||
} else {
|
||||
$results = htmlspecialchars((string)$var);
|
||||
}
|
||||
$results = '<i>' . $results . '</i>';
|
||||
break;
|
||||
case 'integer':
|
||||
case 'float':
|
||||
$results = htmlspecialchars((string)$var);
|
||||
break;
|
||||
case 'string':
|
||||
$results = strtr($var, $_replace);
|
||||
if (mb_strlen($var, \Smarty\Smarty::$_CHARSET) > $length) {
|
||||
$results = mb_substr($var, 0, $length - 3, \Smarty\Smarty::$_CHARSET) . '...';
|
||||
}
|
||||
$results = htmlspecialchars('"' . $results . '"', ENT_QUOTES, \Smarty\Smarty::$_CHARSET);
|
||||
break;
|
||||
case 'unknown type':
|
||||
default:
|
||||
$results = strtr((string)$var, $_replace);
|
||||
if (mb_strlen($results, \Smarty\Smarty::$_CHARSET) > $length) {
|
||||
$results = mb_substr($results, 0, $length - 3, \Smarty\Smarty::$_CHARSET) . '...';
|
||||
}
|
||||
$results = htmlspecialchars($results, ENT_QUOTES, \Smarty\Smarty::$_CHARSET);
|
||||
}
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Smarty escape modifier plugin
|
||||
* Type: modifier
|
||||
* Name: escape
|
||||
* Purpose: escape string for output
|
||||
*
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
*
|
||||
* @param string $string input string
|
||||
* @param string $esc_type escape type
|
||||
* @param string $char_set character set, used for htmlspecialchars() or htmlentities()
|
||||
* @param boolean $double_encode encode already encoded entitites again, used for htmlspecialchars() or htmlentities()
|
||||
*
|
||||
* @return string escaped input string
|
||||
*/
|
||||
public function smarty_modifier_escape($string, $esc_type = 'html', $char_set = null, $double_encode = true)
|
||||
{
|
||||
if (!$char_set) {
|
||||
$char_set = \Smarty\Smarty::$_CHARSET;
|
||||
}
|
||||
|
||||
$string = (string)$string;
|
||||
|
||||
switch ($esc_type) {
|
||||
case 'html':
|
||||
return htmlspecialchars($string, ENT_QUOTES, $char_set, $double_encode);
|
||||
// no break
|
||||
case 'htmlall':
|
||||
$string = mb_convert_encoding($string, 'UTF-8', $char_set);
|
||||
return htmlentities($string, ENT_QUOTES, 'UTF-8', $double_encode);
|
||||
// no break
|
||||
case 'url':
|
||||
return rawurlencode($string);
|
||||
case 'urlpathinfo':
|
||||
return str_replace('%2F', '/', rawurlencode($string));
|
||||
case 'quotes':
|
||||
// escape unescaped single quotes
|
||||
return preg_replace("%(?<!\\\\)'%", "\\'", $string);
|
||||
case 'hex':
|
||||
// escape every byte into hex
|
||||
// Note that the UTF-8 encoded character ä will be represented as %c3%a4
|
||||
$return = '';
|
||||
$_length = strlen($string);
|
||||
for ($x = 0; $x < $_length; $x++) {
|
||||
$return .= '%' . bin2hex($string[ $x ]);
|
||||
}
|
||||
return $return;
|
||||
case 'hexentity':
|
||||
$return = '';
|
||||
foreach ($this->mb_to_unicode($string, \Smarty\Smarty::$_CHARSET) as $unicode) {
|
||||
$return .= '&#x' . strtoupper(dechex($unicode)) . ';';
|
||||
}
|
||||
return $return;
|
||||
case 'decentity':
|
||||
$return = '';
|
||||
foreach ($this->mb_to_unicode($string, \Smarty\Smarty::$_CHARSET) as $unicode) {
|
||||
$return .= '&#' . $unicode . ';';
|
||||
}
|
||||
return $return;
|
||||
case 'javascript':
|
||||
// escape quotes and backslashes, newlines, etc.
|
||||
return strtr(
|
||||
$string,
|
||||
array(
|
||||
'\\' => '\\\\',
|
||||
"'" => "\\'",
|
||||
'"' => '\\"',
|
||||
"\r" => '\\r',
|
||||
"\n" => '\\n',
|
||||
'</' => '<\/',
|
||||
// see https://html.spec.whatwg.org/multipage/scripting.html#restrictions-for-contents-of-script-elements
|
||||
'<!--' => '<\!--',
|
||||
'<s' => '<\s',
|
||||
'<S' => '<\S',
|
||||
"`" => "\\\\`",
|
||||
"\${" => "\\\\\\$\\{"
|
||||
)
|
||||
);
|
||||
case 'mail':
|
||||
return smarty_mb_str_replace(
|
||||
array(
|
||||
'@',
|
||||
'.'
|
||||
),
|
||||
array(
|
||||
' [AT] ',
|
||||
' [DOT] '
|
||||
),
|
||||
$string
|
||||
);
|
||||
case 'nonstd':
|
||||
// escape non-standard chars, such as ms document quotes
|
||||
$return = '';
|
||||
foreach ($this->mb_to_unicode($string, \Smarty\Smarty::$_CHARSET) as $unicode) {
|
||||
if ($unicode >= 126) {
|
||||
$return .= '&#' . $unicode . ';';
|
||||
} else {
|
||||
$return .= chr($unicode);
|
||||
}
|
||||
}
|
||||
return $return;
|
||||
default:
|
||||
trigger_error("escape: unsupported type: $esc_type - returning unmodified string", E_USER_NOTICE);
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* convert characters to their decimal unicode equivalents
|
||||
*
|
||||
* @link http://www.ibm.com/developerworks/library/os-php-unicode/index.html#listing3 for inspiration
|
||||
*
|
||||
* @param string $string characters to calculate unicode of
|
||||
* @param string $encoding encoding of $string
|
||||
*
|
||||
* @return array sequence of unicodes
|
||||
* @author Rodney Rehm
|
||||
*/
|
||||
private function mb_to_unicode($string, $encoding = null) {
|
||||
if ($encoding) {
|
||||
$expanded = mb_convert_encoding($string, 'UTF-32BE', $encoding);
|
||||
} else {
|
||||
$expanded = mb_convert_encoding($string, 'UTF-32BE');
|
||||
}
|
||||
return unpack('N*', $expanded);
|
||||
}
|
||||
|
||||
/**
|
||||
* Smarty explode modifier plugin
|
||||
* Type: modifier
|
||||
* Name: explode
|
||||
* Purpose: split a string by a string
|
||||
*
|
||||
* @param string $separator
|
||||
* @param string $string
|
||||
* @param int|null $limit
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function smarty_modifier_explode($separator, $string, ?int $limit = null)
|
||||
{
|
||||
trigger_error("Using explode is deprecated. " .
|
||||
"Use split, using the array first, separator second.", E_USER_DEPRECATED);
|
||||
// provide $string default to prevent deprecation errors in PHP >=8.1
|
||||
return explode($separator, $string ?? '', $limit ?? PHP_INT_MAX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Smarty split modifier plugin
|
||||
* Type: modifier
|
||||
* Name: split
|
||||
* Purpose: split a string by a string
|
||||
*
|
||||
* @param string $string
|
||||
* @param string $separator
|
||||
* @param int|null $limit
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function smarty_modifier_split($string, $separator, ?int $limit = null)
|
||||
{
|
||||
// provide $string default to prevent deprecation errors in PHP >=8.1
|
||||
return explode($separator, $string ?? '', $limit ?? PHP_INT_MAX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Smarty implode modifier plugin
|
||||
* Type: modifier
|
||||
* Name: implode
|
||||
* Purpose: join an array of values into a single string
|
||||
*
|
||||
* @param array $values
|
||||
* @param string $separator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function smarty_modifier_implode($values, $separator = '')
|
||||
{
|
||||
|
||||
trigger_error("Using implode is deprecated. " .
|
||||
"Use join using the array first, separator second.", E_USER_DEPRECATED);
|
||||
|
||||
if (is_array($separator)) {
|
||||
return implode((string) ($values ?? ''), (array) $separator);
|
||||
}
|
||||
return implode((string) ($separator ?? ''), (array) $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Smarty in_array modifier plugin
|
||||
* Type: modifier
|
||||
* Name: in_array
|
||||
* Purpose: test if value is contained in an array
|
||||
*
|
||||
* @param mixed $needle
|
||||
* @param array $array
|
||||
* @param bool $strict
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function smarty_modifier_in_array($needle, $array, $strict = false)
|
||||
{
|
||||
return in_array($needle, (array) $array, (bool) $strict);
|
||||
}
|
||||
|
||||
/**
|
||||
* Smarty join modifier plugin
|
||||
* Type: modifier
|
||||
* Name: join
|
||||
* Purpose: join an array of values into a single string
|
||||
*
|
||||
* @param array $values
|
||||
* @param string $separator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function smarty_modifier_join($values, $separator = '')
|
||||
{
|
||||
if (is_array($separator)) {
|
||||
trigger_error("Using join with the separator first is deprecated. " .
|
||||
"Call join using the array first, separator second.", E_USER_DEPRECATED);
|
||||
return implode((string) ($values ?? ''), (array) $separator);
|
||||
}
|
||||
return implode((string) ($separator ?? ''), (array) $values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Smarty wordwrap modifier plugin
|
||||
* Type: modifier
|
||||
* Name: mb_wordwrap
|
||||
* Purpose: Wrap a string to a given number of characters
|
||||
*
|
||||
* @link https://php.net/manual/en/function.wordwrap.php for similarity
|
||||
*
|
||||
* @param string $str the string to wrap
|
||||
* @param int $width the width of the output
|
||||
* @param string $break the character used to break the line
|
||||
* @param boolean $cut ignored parameter, just for the sake of
|
||||
*
|
||||
* @return string wrapped string
|
||||
* @author Rodney Rehm
|
||||
*/
|
||||
public function smarty_modifier_mb_wordwrap($str, $width = 75, $break = "\n", $cut = false)
|
||||
{
|
||||
return smarty_mb_wordwrap($str, $width, $break, $cut);
|
||||
}
|
||||
|
||||
/**
|
||||
* Smarty number_format modifier plugin
|
||||
* Type: modifier
|
||||
* Name: number_format
|
||||
* Purpose: Format a number with grouped thousands
|
||||
*
|
||||
* @param float|null $num
|
||||
* @param int $decimals
|
||||
* @param string|null $decimal_separator
|
||||
* @param string|null $thousands_separator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function smarty_modifier_number_format(?float $num, int $decimals = 0, ?string $decimal_separator = ".", ?string $thousands_separator = ",")
|
||||
{
|
||||
// provide $num default to prevent deprecation errors in PHP >=8.1
|
||||
return number_format($num ?? 0.0, $decimals, $decimal_separator, $thousands_separator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Smarty regex_replace modifier plugin
|
||||
* Type: modifier
|
||||
* Name: regex_replace
|
||||
* Purpose: regular expression search/replace
|
||||
*
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
*
|
||||
* @param string $string input string
|
||||
* @param string|array $search regular expression(s) to search for
|
||||
* @param string|array $replace string(s) that should be replaced
|
||||
* @param int $limit the maximum number of replacements
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function smarty_modifier_regex_replace($string, $search, $replace, $limit = -1)
|
||||
{
|
||||
if (is_array($search)) {
|
||||
foreach ($search as $idx => $s) {
|
||||
$search[ $idx ] = $this->regex_replace_check($s);
|
||||
}
|
||||
} else {
|
||||
$search = $this->regex_replace_check($search);
|
||||
}
|
||||
return preg_replace($search, $replace, $string, $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $search string(s) that should be replaced
|
||||
*
|
||||
* @return string
|
||||
* @ignore
|
||||
*/
|
||||
private function regex_replace_check($search)
|
||||
{
|
||||
// null-byte injection detection
|
||||
// anything behind the first null-byte is ignored
|
||||
if (($pos = strpos($search, "\0")) !== false) {
|
||||
$search = substr($search, 0, $pos);
|
||||
}
|
||||
// remove eval-modifier from $search
|
||||
if (preg_match('!([a-zA-Z\s]+)$!s', $search, $match) && (strpos($match[ 1 ], 'e') !== false)) {
|
||||
$search = substr($search, 0, -strlen($match[ 1 ])) . preg_replace('![e\s]+!', '', $match[ 1 ]);
|
||||
}
|
||||
return $search;
|
||||
}
|
||||
|
||||
/**
|
||||
* Smarty replace modifier plugin
|
||||
* Type: modifier
|
||||
* Name: replace
|
||||
* Purpose: simple search/replace
|
||||
*
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @author Uwe Tews
|
||||
*
|
||||
* @param string $string input string
|
||||
* @param string $search text to search for
|
||||
* @param string $replace replacement text
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function smarty_modifier_replace($string, $search, $replace)
|
||||
{
|
||||
return smarty_mb_str_replace($search, $replace, $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Smarty truncate modifier plugin
|
||||
* Type: modifier
|
||||
* Name: truncate
|
||||
* Purpose: Truncate a string to a certain length if necessary,
|
||||
* optionally splitting in the middle of a word, and
|
||||
* appending the $etc string or inserting $etc into the middle.
|
||||
*
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
*
|
||||
* @param string $string input string
|
||||
* @param integer $length length of truncated text
|
||||
* @param string $etc end string
|
||||
* @param boolean $break_words truncate at word boundary
|
||||
* @param boolean $middle truncate in the middle of text
|
||||
*
|
||||
* @return string truncated string
|
||||
*/
|
||||
public function smarty_modifier_truncate($string, $length = 80, $etc = '...', $break_words = false, $middle = false)
|
||||
{
|
||||
if ($length === 0 || $string === null) {
|
||||
return '';
|
||||
}
|
||||
if (mb_strlen($string, \Smarty\Smarty::$_CHARSET) > $length) {
|
||||
$length -= min($length, mb_strlen($etc, \Smarty\Smarty::$_CHARSET));
|
||||
if (!$break_words && !$middle) {
|
||||
$string = preg_replace(
|
||||
'/\s+?(\S+)?$/' . \Smarty\Smarty::$_UTF8_MODIFIER,
|
||||
'',
|
||||
mb_substr($string, 0, $length + 1, \Smarty\Smarty::$_CHARSET)
|
||||
);
|
||||
}
|
||||
if (!$middle) {
|
||||
return mb_substr($string, 0, $length, \Smarty\Smarty::$_CHARSET) . $etc;
|
||||
}
|
||||
return mb_substr($string, 0, intval($length / 2), \Smarty\Smarty::$_CHARSET) . $etc .
|
||||
mb_substr($string, -intval($length / 2), $length, \Smarty\Smarty::$_CHARSET);
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
}
|
||||
198
update/src/FunctionHandler/HtmlCheckboxes.php
Normal file
198
update/src/FunctionHandler/HtmlCheckboxes.php
Normal file
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
namespace Smarty\FunctionHandler;
|
||||
|
||||
use Smarty\Template;
|
||||
|
||||
/**
|
||||
* Smarty {html_checkboxes} function plugin
|
||||
* File: HtmlCheckboxes.php
|
||||
* Type: function
|
||||
* Name: html_checkboxes
|
||||
* Date: 24.Feb.2003
|
||||
* Purpose: Prints out a list of checkbox input types
|
||||
* Examples:
|
||||
*
|
||||
* {html_checkboxes values=$ids output=$names}
|
||||
* {html_checkboxes values=$ids name='box' separator='<br>' output=$names}
|
||||
* {html_checkboxes values=$ids checked=$checked separator='<br>' output=$names}
|
||||
*
|
||||
* Params:
|
||||
*
|
||||
* - name (optional) - string default "checkbox"
|
||||
* - values (required) - array
|
||||
* - options (optional) - associative array
|
||||
* - checked (optional) - array default not set
|
||||
* - separator (optional) - ie <br> or
|
||||
* - output (optional) - the output next to each checkbox
|
||||
* - pos (optional) - position entry into the [] for multi checkboxes
|
||||
* - assign (optional) - assign the output as an array to this variable
|
||||
* - escape (optional) - escape the content (not value), defaults to true
|
||||
*
|
||||
* @author Christopher Kvarme <christopher.kvarme@flashjab.com>
|
||||
* @author credits to Monte Ohrt <monte at ohrt dot com>
|
||||
* @version 1.0
|
||||
*
|
||||
* @param array $params parameters
|
||||
* @param Template $template template object
|
||||
*
|
||||
* @return string
|
||||
* @uses smarty_function_escape_special_chars()
|
||||
* @throws \Smarty\Exception
|
||||
*/
|
||||
class HtmlCheckboxes extends HtmlBase {
|
||||
|
||||
public function handle($params, Template $template) {
|
||||
$name = 'checkbox';
|
||||
$values = null;
|
||||
$options = null;
|
||||
$selected = [];
|
||||
$separator = '';
|
||||
$escape = true;
|
||||
$labels = true;
|
||||
$label_ids = false;
|
||||
$output = null;
|
||||
$pos = null;
|
||||
$extra = '';
|
||||
foreach ($params as $_key => $_val) {
|
||||
switch ($_key) {
|
||||
case 'name':
|
||||
case 'separator':
|
||||
$$_key = (string)$_val;
|
||||
break;
|
||||
case 'escape':
|
||||
case 'labels':
|
||||
case 'label_ids':
|
||||
$$_key = (bool)$_val;
|
||||
break;
|
||||
case 'options':
|
||||
$$_key = (array)$_val;
|
||||
break;
|
||||
case 'values':
|
||||
case 'output':
|
||||
$$_key = array_values((array)$_val);
|
||||
break;
|
||||
case 'checked':
|
||||
case 'selected':
|
||||
if (is_array($_val)) {
|
||||
$selected = [];
|
||||
foreach ($_val as $_sel) {
|
||||
if (is_object($_sel)) {
|
||||
if (method_exists($_sel, '__toString')) {
|
||||
$_sel = smarty_function_escape_special_chars((string)$_sel->__toString());
|
||||
} else {
|
||||
trigger_error(
|
||||
'html_checkboxes: selected attribute contains an object of class \'' .
|
||||
get_class($_sel) . '\' without __toString() method',
|
||||
E_USER_NOTICE
|
||||
);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
$_sel = smarty_function_escape_special_chars((string)$_sel);
|
||||
}
|
||||
$selected[$_sel] = true;
|
||||
}
|
||||
} elseif (is_object($_val)) {
|
||||
if (method_exists($_val, '__toString')) {
|
||||
$selected = smarty_function_escape_special_chars((string)$_val->__toString());
|
||||
} else {
|
||||
trigger_error(
|
||||
'html_checkboxes: selected attribute is an object of class \'' . get_class($_val) .
|
||||
'\' without __toString() method',
|
||||
E_USER_NOTICE
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$selected = smarty_function_escape_special_chars((string)$_val);
|
||||
}
|
||||
break;
|
||||
case 'checkboxes':
|
||||
trigger_error(
|
||||
'html_checkboxes: the use of the "checkboxes" attribute is deprecated, use "options" instead',
|
||||
E_USER_WARNING
|
||||
);
|
||||
$options = (array)$_val;
|
||||
break;
|
||||
case 'pos':
|
||||
$$_key = array_values((array)$_val);
|
||||
break;
|
||||
case 'strict':
|
||||
case 'assign':
|
||||
break;
|
||||
case 'disabled':
|
||||
case 'readonly':
|
||||
if (!empty($params['strict'])) {
|
||||
if (!is_scalar($_val)) {
|
||||
trigger_error(
|
||||
"html_options: {$_key} attribute must be a scalar, only boolean true or string '{$_key}' will actually add the attribute",
|
||||
E_USER_NOTICE
|
||||
);
|
||||
}
|
||||
if ($_val === true || $_val === $_key) {
|
||||
$extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_key) . '"';
|
||||
}
|
||||
break;
|
||||
}
|
||||
// omit break; to fall through!
|
||||
// no break
|
||||
default:
|
||||
if (!is_array($_val)) {
|
||||
$extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_val) . '"';
|
||||
} else {
|
||||
trigger_error("html_checkboxes: extra attribute '{$_key}' cannot be an array", E_USER_NOTICE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isset($options) && !isset($values)) {
|
||||
return '';
|
||||
} /* raise error here? */
|
||||
$_html_result = [];
|
||||
if (isset($options)) {
|
||||
foreach ($options as $_key => $_val) {
|
||||
$_pos = isset($pos[ $_key ]) ? $pos[ $_key ] : '';
|
||||
$_html_result[] =
|
||||
$this->getHtmlForInput(
|
||||
'checkbox',
|
||||
$name,
|
||||
$_key,
|
||||
$_val,
|
||||
true,
|
||||
$selected,
|
||||
$extra,
|
||||
$separator,
|
||||
$labels,
|
||||
$label_ids,
|
||||
$_pos,
|
||||
$escape
|
||||
);
|
||||
}
|
||||
} else {
|
||||
foreach ($values as $_i => $_key) {
|
||||
$_val = isset($output[$_i]) ? $output[$_i] : '';
|
||||
$_pos = isset($pos[ $_i ]) ? $pos[ $_i ] : '';
|
||||
$_html_result[] =
|
||||
$this->getHtmlForInput(
|
||||
'checkbox',
|
||||
$name,
|
||||
$_key,
|
||||
$_val,
|
||||
true,
|
||||
$selected,
|
||||
$extra,
|
||||
$separator,
|
||||
$labels,
|
||||
$label_ids,
|
||||
$_pos,
|
||||
$escape
|
||||
);
|
||||
}
|
||||
}
|
||||
if (!empty($params['assign'])) {
|
||||
$template->assign($params['assign'], $_html_result);
|
||||
} else {
|
||||
return implode("\n", $_html_result);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
236
update/src/FunctionHandler/HtmlOptions.php
Normal file
236
update/src/FunctionHandler/HtmlOptions.php
Normal file
@@ -0,0 +1,236 @@
|
||||
<?php
|
||||
namespace Smarty\FunctionHandler;
|
||||
|
||||
use Smarty\Template;
|
||||
|
||||
/**
|
||||
* Smarty {html_options} function plugin
|
||||
* Type: function
|
||||
* Name: html_options
|
||||
* Purpose: Prints the list of <option> tags generated from
|
||||
* the passed parameters
|
||||
* Params:
|
||||
*
|
||||
* - name (optional) - string default "select"
|
||||
* - values (required) - if no options supplied) - array
|
||||
* - options (required) - if no values supplied) - associative array
|
||||
* - selected (optional) - string default not set
|
||||
* - output (required) - if not options supplied) - array
|
||||
* - id (optional) - string default not set
|
||||
* - label (optional) - label strinng to set
|
||||
* - class (optional) - string default not set
|
||||
*
|
||||
* @author Monte Ohrt <monte at ohrt dot com>
|
||||
* @author Ralf Strehle (minor optimization) <ralf dot strehle at yahoo dot de>
|
||||
*
|
||||
* @param array $params parameters
|
||||
*
|
||||
* @param \Smarty\Template $template
|
||||
*
|
||||
* @return string
|
||||
* @uses smarty_function_escape_special_chars()
|
||||
* @throws \Smarty\Exception
|
||||
*/
|
||||
class HtmlOptions extends Base {
|
||||
|
||||
public function handle($params, Template $template) {
|
||||
$name = null;
|
||||
$values = null;
|
||||
$options = null;
|
||||
$selected = null;
|
||||
$output = null;
|
||||
$id = null;
|
||||
$class = null;
|
||||
$label = true;
|
||||
$extra = '';
|
||||
foreach ($params as $_key => $_val) {
|
||||
switch ($_key) {
|
||||
case 'name':
|
||||
case 'class':
|
||||
case 'id':
|
||||
$$_key = (string)$_val;
|
||||
break;
|
||||
case 'options':
|
||||
$options = (array)$_val;
|
||||
break;
|
||||
case 'values':
|
||||
case 'output':
|
||||
$$_key = array_values((array)$_val);
|
||||
break;
|
||||
case 'selected':
|
||||
if (is_array($_val)) {
|
||||
$selected = [];
|
||||
foreach ($_val as $_sel) {
|
||||
if (is_object($_sel)) {
|
||||
if (method_exists($_sel, '__toString')) {
|
||||
$_sel = smarty_function_escape_special_chars((string)$_sel->__toString());
|
||||
} else {
|
||||
trigger_error(
|
||||
'html_options: selected attribute contains an object of class \'' .
|
||||
get_class($_sel) . '\' without __toString() method',
|
||||
E_USER_NOTICE
|
||||
);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
$_sel = smarty_function_escape_special_chars((string)$_sel);
|
||||
}
|
||||
$selected[$_sel] = true;
|
||||
}
|
||||
} elseif (is_object($_val)) {
|
||||
if (method_exists($_val, '__toString')) {
|
||||
$selected = smarty_function_escape_special_chars((string)$_val->__toString());
|
||||
} else {
|
||||
trigger_error(
|
||||
'html_options: selected attribute is an object of class \'' . get_class($_val) .
|
||||
'\' without __toString() method',
|
||||
E_USER_NOTICE
|
||||
);
|
||||
}
|
||||
} else {
|
||||
$selected = smarty_function_escape_special_chars((string)$_val);
|
||||
}
|
||||
break;
|
||||
case 'label':
|
||||
if ($_val == 'true' || $_val == 'false') {
|
||||
$$_key = (string)$_val;
|
||||
}
|
||||
break;
|
||||
case 'strict':
|
||||
break;
|
||||
case 'disabled':
|
||||
case 'readonly':
|
||||
if (!empty($params['strict'])) {
|
||||
if (!is_scalar($_val)) {
|
||||
trigger_error(
|
||||
"html_options: {$_key} attribute must be a scalar, only boolean true or string '{$_key}' will actually add the attribute",
|
||||
E_USER_NOTICE
|
||||
);
|
||||
}
|
||||
if ($_val === true || $_val === $_key) {
|
||||
$extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_key) . '"';
|
||||
}
|
||||
break;
|
||||
}
|
||||
// omit break; to fall through!
|
||||
// no break
|
||||
default:
|
||||
if (!is_array($_val)) {
|
||||
$extra .= ' ' . $_key . '="' . smarty_function_escape_special_chars($_val) . '"';
|
||||
} else {
|
||||
trigger_error("html_options: extra attribute '{$_key}' cannot be an array", E_USER_NOTICE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isset($options) && !isset($values)) {
|
||||
/* raise error here? */
|
||||
return '';
|
||||
}
|
||||
$_html_result = '';
|
||||
$_idx = 0;
|
||||
if (isset($options)) {
|
||||
foreach ($options as $_key => $_val) {
|
||||
$_html_result .= $this->output($_key, $_val, $selected, $id, $class, $label, $_idx);
|
||||
}
|
||||
} else {
|
||||
foreach ($values as $_i => $_key) {
|
||||
$_val = $output[$_i] ?? '';
|
||||
$_html_result .= $this->output($_key, $_val, $selected, $id, $class, $label, $_idx);
|
||||
}
|
||||
}
|
||||
if (!empty($name)) {
|
||||
$_html_class = !empty($class) ? ' class="' . $class . '"' : '';
|
||||
$_html_id = !empty($id) ? ' id="' . $id . '"' : '';
|
||||
$_html_result =
|
||||
'<select name="' . $name . '"' . $_html_class . $_html_id . $extra . '>' . "\n" . $_html_result .
|
||||
'</select>' . "\n";
|
||||
}
|
||||
return $_html_result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @param $selected
|
||||
* @param $id
|
||||
* @param $class
|
||||
* @param $label
|
||||
* @param $idx
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function output($key, $value, $selected, $id, $class, $label, &$idx)
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
$_key = smarty_function_escape_special_chars($key);
|
||||
$_html_result = '<option'
|
||||
. ($label == 'true' ?
|
||||
' label="' . smarty_function_escape_special_chars($value) . '"' : ''
|
||||
)
|
||||
. ' value="' . $_key . '"';
|
||||
if (is_array($selected)) {
|
||||
if (isset($selected[ $_key ])) {
|
||||
$_html_result .= ' selected="selected"';
|
||||
}
|
||||
} elseif ($_key === $selected) {
|
||||
$_html_result .= ' selected="selected"';
|
||||
}
|
||||
$_html_class = !empty($class) ? ' class="' . $class . ' option"' : '';
|
||||
$_html_id = !empty($id) ? ' id="' . $id . '-' . $idx . '"' : '';
|
||||
if (is_object($value)) {
|
||||
if (method_exists($value, '__toString')) {
|
||||
$value = smarty_function_escape_special_chars((string)$value->__toString());
|
||||
} else {
|
||||
trigger_error(
|
||||
'html_options: value is an object of class \'' . get_class($value) .
|
||||
'\' without __toString() method',
|
||||
E_USER_NOTICE
|
||||
);
|
||||
return '';
|
||||
}
|
||||
} else {
|
||||
$value = smarty_function_escape_special_chars((string)$value);
|
||||
}
|
||||
$_html_result .= $_html_class . $_html_id . '>' . $value . '</option>' . "\n";
|
||||
$idx++;
|
||||
} else {
|
||||
$_idx = 0;
|
||||
$_html_result =
|
||||
$this->getHtmlForOptGroup(
|
||||
$key,
|
||||
$value,
|
||||
$selected,
|
||||
!empty($id) ? ($id . '-' . $idx) : null,
|
||||
$class,
|
||||
$label,
|
||||
$_idx
|
||||
);
|
||||
$idx++;
|
||||
}
|
||||
return $_html_result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $key
|
||||
* @param $values
|
||||
* @param $selected
|
||||
* @param $id
|
||||
* @param $class
|
||||
* @param $idx
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function getHtmlForOptGroup($key, $values, $selected, $id, $class, $label, &$idx)
|
||||
{
|
||||
$optgroup_html = '<optgroup label="' . smarty_function_escape_special_chars($key) . '">' . "\n";
|
||||
foreach ($values as $key => $value) {
|
||||
$optgroup_html .= $this->output($key, $value, $selected, $id, $class, $label, $idx);
|
||||
}
|
||||
$optgroup_html .= "</optgroup>\n";
|
||||
return $optgroup_html;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
123
update/src/FunctionHandler/Popup.php
Normal file
123
update/src/FunctionHandler/Popup.php
Normal file
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
namespace Smarty\FunctionHandler;
|
||||
|
||||
use Smarty\Template;
|
||||
|
||||
class Popup extends Base
|
||||
{
|
||||
/**
|
||||
* Smarty {popup_init} function plugin
|
||||
*
|
||||
* Type: function<br>
|
||||
* Name: popup_init<br>
|
||||
* Purpose: initialize overlib
|
||||
* @author Clemens Schwaighofer <gullevek at gullevek dot org>
|
||||
* @param array
|
||||
* @param Smarty
|
||||
* @return string
|
||||
*/
|
||||
public function handle($params, Template $template)
|
||||
{
|
||||
$append = '';
|
||||
foreach ($params as $_key => $_value) {
|
||||
switch ($_key) {
|
||||
case 'text':
|
||||
case 'trigger':
|
||||
case 'function':
|
||||
case 'inarray':
|
||||
$$_key = (string)$_value;
|
||||
if ($_key == 'function' || $_key == 'inarray') {
|
||||
$append .= ',' . strtoupper($_key) . ",'$_value'";
|
||||
}
|
||||
break;
|
||||
|
||||
case 'caption':
|
||||
case 'closetext':
|
||||
case 'status':
|
||||
$append .= ',' . strtoupper($_key) . ",'" . str_replace("'", "\'", $_value) . "'";
|
||||
break;
|
||||
|
||||
case 'fgcolor':
|
||||
case 'bgcolor':
|
||||
case 'textcolor':
|
||||
case 'capcolor':
|
||||
case 'closecolor':
|
||||
case 'textfont':
|
||||
case 'captionfont':
|
||||
case 'closefont':
|
||||
case 'fgbackground':
|
||||
case 'bgbackground':
|
||||
case 'caparray':
|
||||
case 'capicon':
|
||||
case 'background':
|
||||
case 'frame':
|
||||
$append .= ',' . strtoupper($_key) . ",'$_value'";
|
||||
break;
|
||||
|
||||
case 'textsize':
|
||||
case 'captionsize':
|
||||
case 'closesize':
|
||||
case 'width':
|
||||
case 'height':
|
||||
case 'border':
|
||||
case 'offsetx':
|
||||
case 'offsety':
|
||||
case 'snapx':
|
||||
case 'snapy':
|
||||
case 'fixx':
|
||||
case 'fixy':
|
||||
case 'padx':
|
||||
case 'pady':
|
||||
case 'timeout':
|
||||
case 'delay':
|
||||
$append .= ',' . strtoupper($_key) . ",$_value";
|
||||
break;
|
||||
|
||||
case 'sticky':
|
||||
case 'left':
|
||||
case 'right':
|
||||
case 'center':
|
||||
case 'above':
|
||||
case 'below':
|
||||
case 'noclose':
|
||||
case 'autostatus':
|
||||
case 'autostatuscap':
|
||||
case 'fullhtml':
|
||||
case 'hauto':
|
||||
case 'vauto':
|
||||
case 'mouseoff':
|
||||
case 'followmouse':
|
||||
case 'closeclick':
|
||||
if ($_value) {
|
||||
$append .= ',' . strtoupper($_key);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
trigger_error("[popup] unknown parameter $_key", E_USER_WARNING);
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($text) && !isset($inarray) && empty($function)) {
|
||||
trigger_error("overlib: attribute 'text' or 'inarray' or 'function' required");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (empty($trigger)) {
|
||||
$trigger = "onmouseover";
|
||||
}
|
||||
|
||||
$retval = $trigger
|
||||
. '="return overlib(\'' . preg_replace(array("!'!", "![\r\n]!"), array("\'", '\r'), $text) . '\'';
|
||||
$retval .= $append . ');"';
|
||||
if ($trigger == 'onmouseover') {
|
||||
$retval .= ' onmouseout="nd();"';
|
||||
}
|
||||
|
||||
|
||||
return $retval;
|
||||
}
|
||||
}
|
||||
|
||||
// __END__
|
||||
36
update/src/FunctionHandler/PopupInit.php
Normal file
36
update/src/FunctionHandler/PopupInit.php
Normal file
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace Smarty\FunctionHandler;
|
||||
|
||||
use Smarty\Template;
|
||||
|
||||
class PopupInit extends Base
|
||||
{
|
||||
/**
|
||||
* Smarty {popup_init} function plugin
|
||||
*
|
||||
* Type: function<br>
|
||||
* Name: popup_init<br>
|
||||
* Purpose: initialize overlib
|
||||
* @author Clemens Schwaighofer <gullevek at gullevek dot org>
|
||||
* @param array
|
||||
* @param Smarty
|
||||
* @return string
|
||||
*/
|
||||
public function handle($params, Template $template)
|
||||
{
|
||||
if (empty($params['src'])) {
|
||||
trigger_error("popup_init: missing src parameter");
|
||||
return false;
|
||||
}
|
||||
return str_replace(
|
||||
["{SCRIPT_SOURCE}"],
|
||||
[$params['src']],
|
||||
<<<HTML
|
||||
<script type="text/javascript" language="JavaScript" src="{SCRIPT_SOURCE}"></script>
|
||||
HTML
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// __END__
|
||||
Reference in New Issue
Block a user