* commit 5cec54d508fd4a34de509b3ac28d6277b6abc090 (HEAD -> master, all/master, all/development, all/NewFeatures) | log size 644 | Author: Clemens Schwaighofer <clemens.schwaighofer@egplusww.com> | Date: 2024-09-20 13:33:19 +0900 | | Add "Success" to message logging levels, fixes for PHP 8.4, other preg_match fixes | | The Logger/MessageLevel gets "success" as level 110 to something a bit | heigher than "ok" which is the general "OK" for anything ending without | an error. The "success" is currently only used in file uploads with the | java script ajax file uploader | | Fix any "type $var = null" with correctly "?type $var = null" for PHP 8.4 (phphan) | | Fix preg match no return catches for DB IO compare version and for language | look up. | | 4dev/tests/Logging/CoreLibsLoggingErrorMessagesTest.php | 5 +++++ | www/admin/class_test.html.php | 1 + | www/admin/class_test.php | 2 +- | www/admin/layout/javascript/edit.jq.js | 2 +- | www/lib/CoreLibs/Admin/Backend.php | 6 +++--- | www/lib/CoreLibs/Basic.php | 2 +- | www/lib/CoreLibs/Convert/Extends/SetVarTypeMain.php | 6 +++--- | www/lib/CoreLibs/Convert/SetVarTypeNull.php | 6 +++--- | www/lib/CoreLibs/DB/IO.php | 24 ++++++++++++++++++------ | www/lib/CoreLibs/Language/GetLocale.php | 4 ++-- | www/lib/CoreLibs/Logging/Logger/MessageLevel.php | 2 ++ | www/lib/CoreLibs/Output/Form/Elements.php | 12 ++++++------ | www/lib/CoreLibs/Template/HtmlBuilder/Element.php | 4 ++-- | 13 files changed, 48 insertions(+), 28 deletions(-) | * commit 8e60c992f109993b40d9e5ec9354ffb7d7db9f79 | log size 123 | Author: Clemens Schwaighofer <clemens.schwaighofer@egplusww.com> | Date: 2024-09-03 12:06:01 +0900 | | Fixes phan/phpstan | | phpstan.neon | 6 +++--- | www/lib/CoreLibs/Get/System.php | 2 +- | www/lib/CoreLibs/Template/HtmlBuilder/Block.php | 4 ---- | 3 files changed, 4 insertions(+), 8 deletions(-) | * commit 1b5437b675f6ceda4318f19522d47a08f28f95a8 | log size 147 | Author: Clemens Schwaighofer <clemens.schwaighofer@egplusww.com> | Date: 2024-09-03 11:58:36 +0900 | | Add testing for new added bom utf8 replace | | 4dev/tests/Convert/CoreLibsConvertStringsTest.php | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ | 4dev/tests/Convert/data/UTF8.csv | 1 + | 4dev/tests/Convert/data/UTF8BOM.csv | 1 + | 4dev/tests/Get/CoreLibsGetSystemTest.php | 23 +++++++++++++++++++++++ | www/admin/class_test.system.php | 4 +++- | 5 files changed, 76 insertions(+), 1 deletion(-) | * commit ef80cba5610b8acae8fc11d3f0a441c1f5a03735 | log size 659 | Author: Clemens Schwaighofer <clemens.schwaighofer@egplusww.com> | Date: 2024-09-03 09:49:01 +0900 | | Add new functions: get IPs, strip UTF8 BOM from text, text updates | | Add the following new static methods | | Convert\Strings::stripUTF8BomBytes: removes the UTF8 BOM bytes from the beginning of a line | Used for CSV files created in Excel for the first header entry (line 0/row 0) | | Get\Systen::getIpAddresses: gets all IP addresses for the the current access user | and returns an array | | Moved the frontend folder detection from the first load config to the config.path.php | | Cleaned up the translations JS scripts | | 4dev/bin/create_mo.sh | 9 +++++---- | 4dev/bin/mo_to_js.sh | 63 +++++++++++++++++++++++++++++++++++---------------------------- | www/configs/config.path.php | 16 +++++++++++++++- | www/configs/config.php | 15 +-------------- | www/lib/CoreLibs/Convert/Strings.php | 12 ++++++++++++ | www/lib/CoreLibs/DB/IO.php | 2 +- | www/lib/CoreLibs/Get/System.php | 23 +++++++++++++++++++++++ | www/lib/CoreLibs/Template/HtmlBuilder/Block.php | 37 ++++++++++++++++++++++++++----------- | 8 files changed, 118 insertions(+), 59 deletions(-) | * commit 2d71e760e8fb7b4b0a5552a2f62bedffad928f4f | log size 120 | Author: Clemens Schwaighofer <clemens.schwaighofer@egplusww.com> | Date: 2024-08-21 11:45:17 +0900 | | Composer update | | www/composer.lock | 12 ++++++------ | www/lib/CoreLibs/Template/SmartyExtend.php | 3 ++- | www/vendor/composer/installed.json | 14 +++++++------- | www/vendor/composer/installed.php | 6 +++--- | www/vendor/gullevek/dotenv/Readme.md | 23 +++++++++++++++++++++++ | www/vendor/gullevek/dotenv/src/DotEnv.php | 13 ++++++++++--- | 6 files changed, 51 insertions(+), 20 deletions(-) | * commit a8d07634ffaf961a37557437aac1f202ae18fa6e | log size 182 | Author: Clemens Schwaighofer <clemens.schwaighofer@egplusww.com> | Date: 2024-08-07 13:41:09 +0900 | | Add soba.egplusww.jp as local development host, jshint esversion update to 11 | | www/admin/layout/javascript/edit.jq.js | 2 +- | www/configs/config.host.php | 28 +++++++++++----------------- | 2 files changed, 12 insertions(+), 18 deletions(-) |
560 lines
13 KiB
PHP
560 lines
13 KiB
PHP
<?php
|
|
|
|
/**
|
|
* AUTOR: Clemens Schwaighofer
|
|
* CREATED: 2023/6/1
|
|
* DESCRIPTION:
|
|
* html builder: element
|
|
* nested and connected objects
|
|
*/
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace CoreLibs\Template\HtmlBuilder;
|
|
|
|
use CoreLibs\Template\HtmlBuilder\General\Settings;
|
|
use CoreLibs\Template\HtmlBuilder\General\Error;
|
|
use CoreLibs\Template\HtmlBuilder\General\HtmlBuilderExcpetion;
|
|
|
|
class Element
|
|
{
|
|
/** @var string */
|
|
private string $tag = '';
|
|
/** @var string */
|
|
private string $id = '';
|
|
/** @var string */
|
|
private string $name = '';
|
|
/** @var string */
|
|
private string $content = '';
|
|
/** @var array<string> */
|
|
private array $css = [];
|
|
/** @var array<string,mixed> */
|
|
private array $options = [];
|
|
/** @var array<Element> list of elements */
|
|
private array $sub = [];
|
|
|
|
/**
|
|
* create new html element
|
|
*
|
|
* @param string $tag html tag (eg div, button, etc)
|
|
* @param string $id html tag id, used also for name if name
|
|
* not set in $options
|
|
* @param string $content content text inside, eg <div>Content</div>
|
|
* if sub elements exist, they are added after content
|
|
* @param array<string> $css array of css names, put style in $options
|
|
* @param array<string,string> $options Additional element options in
|
|
* key = value format
|
|
* eg: onClick => 'something();'
|
|
* id, css are skipped
|
|
* name only set on input/button
|
|
* @throws HtmlBuilderExcpetion
|
|
*/
|
|
public function __construct(
|
|
string $tag,
|
|
string $id = '',
|
|
string $content = '',
|
|
array $css = [],
|
|
array $options = []
|
|
) {
|
|
// exit if not valid tag
|
|
try {
|
|
$this->setTag($tag);
|
|
} catch (HtmlBuilderExcpetion $e) {
|
|
throw new HtmlBuilderExcpetion('Could not create Element', 0, $e);
|
|
}
|
|
$this->setId($id);
|
|
$this->setName($options['name'] ?? '');
|
|
$this->setContent($content);
|
|
$this->addCss(...$css);
|
|
$this->setOptions($options);
|
|
}
|
|
|
|
/**
|
|
* set tag
|
|
*
|
|
* @param string $tag
|
|
* @return void
|
|
* @throws HtmlBuilderExcpetion
|
|
*/
|
|
public function setTag(string $tag): void
|
|
{
|
|
// tag must be letters only
|
|
if (!preg_match("/^[A-Za-z]+$/", $tag)) {
|
|
Error::setError(
|
|
'201',
|
|
'invalid or empty tag',
|
|
['tag' => $tag]
|
|
);
|
|
throw new HtmlBuilderExcpetion('Invalid or empty tag: ' . $tag);
|
|
}
|
|
$this->tag = $tag;
|
|
}
|
|
|
|
/**
|
|
* get the tag name
|
|
*
|
|
* @return string HTML element tag
|
|
*/
|
|
public function getTag(): string
|
|
{
|
|
return $this->tag;
|
|
}
|
|
|
|
/**
|
|
* set the element id
|
|
*
|
|
* @param string $id
|
|
* @return void
|
|
*/
|
|
public function setId(string $id): void
|
|
{
|
|
// invalid id and name check too
|
|
// be strict: [a-zA-Z0-9], -, _
|
|
// cannot start with digit, two hyphens or a hyphen with a digit:
|
|
// 0abc
|
|
// __abc
|
|
// _0abc
|
|
if (
|
|
!empty($id) &&
|
|
!preg_match("/^[A-Za-z][\w-]*$/", $id)
|
|
) {
|
|
Error::setWarning(
|
|
'202',
|
|
'possible invalid id',
|
|
['id' => $id, 'tag' => $this->getTag()]
|
|
);
|
|
// TODO: shoud throw error
|
|
}
|
|
$this->id = $id;
|
|
}
|
|
|
|
/**
|
|
* get the html tag id
|
|
*
|
|
* @return string HTML element id
|
|
*/
|
|
public function getId(): string
|
|
{
|
|
return $this->id;
|
|
}
|
|
|
|
/**
|
|
* Set name for elements
|
|
* only for elements that need it (input/button/form)
|
|
*
|
|
* @param string $name
|
|
* @return void
|
|
*/
|
|
public function setName(string $name): void
|
|
{
|
|
if (
|
|
!empty($name) &&
|
|
!preg_match("/^[A-Za-z][\w-]*$/", $name)
|
|
) {
|
|
Error::setWarning(
|
|
'203',
|
|
'possible invalid name',
|
|
['name' => $name, 'id' => $this->getId(), 'tag' => $this->getTag()]
|
|
);
|
|
// TODO: shoud throw error
|
|
}
|
|
$this->name = $name;
|
|
}
|
|
|
|
/**
|
|
* get the name if set
|
|
*
|
|
* @return string Optional HTML name (eg for input)
|
|
*/
|
|
public function getName(): string
|
|
{
|
|
return $this->name;
|
|
}
|
|
|
|
/**
|
|
* Set new content for element
|
|
*
|
|
* @param string $content
|
|
* @return void
|
|
*/
|
|
public function setContent(string $content): void
|
|
{
|
|
$this->content = $content;
|
|
}
|
|
|
|
/**
|
|
* get the elment text content (not sub elements)
|
|
*
|
|
* @return string HTML content text as is
|
|
*/
|
|
public function getContent(): string
|
|
{
|
|
return $this->content;
|
|
}
|
|
|
|
/**
|
|
* set or update options
|
|
*
|
|
* @param array<string,mixed> $options
|
|
* @return void
|
|
*/
|
|
public function setOptions(array $options): void
|
|
{
|
|
foreach ($options as $key => $value) {
|
|
if (empty($key)) {
|
|
Error::setError(
|
|
'110',
|
|
'Cannot set option with empty key',
|
|
['id' => $this->getId(), 'tag' => $this->getTag()]
|
|
);
|
|
// TODO: shoud throw error
|
|
continue;
|
|
}
|
|
// if data is null
|
|
if ($value === null) {
|
|
if (isset($this->options[$key])) {
|
|
unset($this->options[$key]);
|
|
} else {
|
|
Error::setError(
|
|
'210',
|
|
'Cannot set option with null value',
|
|
['id' => $this->getId(), 'tag' => $this->getTag()]
|
|
);
|
|
}
|
|
// TODO: shoud throw error
|
|
continue;
|
|
}
|
|
$this->options[$key] = $value;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* get the options array
|
|
* also holds "name" option
|
|
* anything like: style, javascript, value or any other html tag option
|
|
* right side can be empty but not null
|
|
*
|
|
* @return array<string,string> get options as list html option name and value
|
|
*/
|
|
public function getOptions(): array
|
|
{
|
|
return $this->options;
|
|
}
|
|
|
|
// Sub Elements
|
|
|
|
/**
|
|
* get the sub elements (array of Elements)
|
|
*
|
|
* @return array<Element> Array of Elements (that can have sub elements)
|
|
*/
|
|
public function getSub(): array
|
|
{
|
|
return $this->sub;
|
|
}
|
|
|
|
/**
|
|
* add one or many sub elements (add at the end)
|
|
*
|
|
* @param Element $sub One or many elements to add
|
|
* @return void
|
|
* @throws HtmlBuilderExcpetion
|
|
*/
|
|
public function addSub(Element ...$sub): void
|
|
{
|
|
foreach ($sub as $_sub) {
|
|
// if one of the elements is the same as this class, ignore it
|
|
// with this we avoid self reference loop
|
|
if ($_sub == $this) {
|
|
Error::setError(
|
|
'100',
|
|
'Cannot assign Element to itself, this would create an infinite loop',
|
|
['id' => $this->getId(), 'tag' => $this->getTag()]
|
|
);
|
|
throw new HtmlBuilderExcpetion('Cannot assign Element to itself, this would create an infinite loop');
|
|
}
|
|
array_push($this->sub, $_sub);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove an element from the sub array
|
|
* By pos in array or id set on first level
|
|
*
|
|
* @param int|string $id String id name or int pos number in array
|
|
* @return void
|
|
*/
|
|
public function removeSub(int|string $id): void
|
|
{
|
|
// find element with id and remove it
|
|
// or when number find pos in sub and remove it
|
|
if (is_int($id)) {
|
|
if (!isset($this->sub[$id])) {
|
|
return;
|
|
}
|
|
unset($this->sub[$id]);
|
|
return;
|
|
}
|
|
// only on first level
|
|
foreach ($this->sub as $pos => $el) {
|
|
if (
|
|
$el->getId() === $id
|
|
) {
|
|
unset($this->sub[$pos]);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* remove all sub elements
|
|
*
|
|
* @return void
|
|
*/
|
|
public function resetSub(): void
|
|
{
|
|
$this->sub = [];
|
|
}
|
|
|
|
// CSS Elements
|
|
|
|
/**
|
|
* get the current set css elements
|
|
*
|
|
* @return array<string> list of css element entries
|
|
*/
|
|
public function getCss(): array
|
|
{
|
|
return $this->css;
|
|
}
|
|
|
|
/**
|
|
* add one or many new css elements
|
|
* Note that we can chain: add/remove/reset
|
|
*
|
|
* @param string ...$css one or more css strings to add
|
|
* @return Element Current element for chaining
|
|
*/
|
|
public function addCss(string ...$css): Element
|
|
{
|
|
// should do check for empty/invalid css
|
|
$_set_css = [];
|
|
foreach ($css as $_css) {
|
|
if (empty($_css)) {
|
|
Error::setError(
|
|
'204',
|
|
'cannot have empty css string',
|
|
);
|
|
// TODO: shoud throw error
|
|
continue;
|
|
}
|
|
// -?[_A-Za-z][_A-Za-z0-9-]*
|
|
if (!preg_match("/^-?[_A-Za-z][_A-Za-z0-9-]*$/", $_css)) {
|
|
Error::setWarning(
|
|
'205',
|
|
'possible invalid css string',
|
|
['css' => $_css, 'id' => $this->id, 'tag' => $this->tag]
|
|
);
|
|
// TODO: shoud throw error
|
|
}
|
|
$_set_css[] = $_css;
|
|
}
|
|
$this->css = array_unique(array_merge($this->css, $_set_css));
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* remove one or more css elements
|
|
* Note that we can chain: add/remove/reset
|
|
*
|
|
* @param string ...$css one or more css strings to remove
|
|
* @return Element Current element for chaining
|
|
*/
|
|
public function removeCss(string ...$css): Element
|
|
{
|
|
$this->css = array_diff($this->css, $css);
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* unset all css elements
|
|
* Note that we can chain: add/remove/reset
|
|
*
|
|
* @return Element
|
|
*/
|
|
public function resetCss(): Element
|
|
{
|
|
$this->css = [];
|
|
return $this;
|
|
}
|
|
|
|
// build output from tree
|
|
|
|
/**
|
|
* build html string from the current element tree (self)
|
|
* or from the Element tree given as parameter
|
|
* if $add_nl is set then new lines are added before each sub element added
|
|
* no indet is done (tab or other)
|
|
*
|
|
* @param Element|null $tree Different Element tree to build
|
|
* if not set (null), self is used
|
|
* @param bool $add_nl [default=false] Optional output string line breaks
|
|
* @return string HTML as string
|
|
*/
|
|
public function buildHtml(?Element $tree = null, bool $add_nl = false): string
|
|
{
|
|
// print "D01: " . microtime(true) . "<br>";
|
|
if ($tree === null) {
|
|
$tree = $this;
|
|
}
|
|
$line = '<' . $tree->getTag();
|
|
|
|
if ($tree->getId()) {
|
|
$line .= ' id="' . $tree->getId() . '"';
|
|
if (in_array($tree->getTag(), Settings::NAME_ELEMENTS)) {
|
|
$line .= ' name="'
|
|
. (!empty($tree->getName()) ? $tree->getName() : $tree->getId())
|
|
. '"';
|
|
}
|
|
}
|
|
if (count($tree->getCss())) {
|
|
$line .= ' class="' . join(' ', $tree->getCss()) . '"';
|
|
}
|
|
foreach ($tree->getOptions() as $key => $item) {
|
|
// skip
|
|
if (in_array($key, Settings::SKIP_OPTIONS)) {
|
|
continue;
|
|
}
|
|
$line .= ' ' . $key . '="' . $item . '"';
|
|
}
|
|
$line .= '>';
|
|
if (strlen($tree->getContent()) > 0) {
|
|
$line .= $tree->getContent();
|
|
}
|
|
// sub nodes
|
|
foreach ($tree->getSub() as $sub) {
|
|
if ($add_nl === true) {
|
|
$line .= "\n";
|
|
}
|
|
$line .= $tree->buildHtml($sub, $add_nl);
|
|
if ($add_nl === true) {
|
|
$line .= "\n";
|
|
}
|
|
}
|
|
|
|
// close line if needed
|
|
if (!in_array($tree->getTag(), Settings::NO_CLOSE)) {
|
|
$line .= '</' . $tree->getTag() . '>';
|
|
}
|
|
|
|
return $line;
|
|
}
|
|
|
|
// this is static
|
|
|
|
/**
|
|
* Builds a single string from an array of elements
|
|
* a new line can be added before each new element if $add_nl is set to true
|
|
*
|
|
* @param array<Element> $list array of Elements, uses buildHtml internal
|
|
* @param bool $add_nl [default=false] Optional output string line breaks
|
|
* @return string HTML as string
|
|
*/
|
|
public static function buildHtmlFromList(array $list, bool $add_nl = false): string
|
|
{
|
|
$output = '';
|
|
foreach ($list as $el) {
|
|
if (!empty($output) && $add_nl === true) {
|
|
$output .= "\n";
|
|
}
|
|
$output .= $el->buildHtml();
|
|
}
|
|
return $output;
|
|
}
|
|
|
|
// so we can call builder statically
|
|
|
|
/**
|
|
* Search element tree for id and add
|
|
* if id is empty add at element given in parameter $base
|
|
*
|
|
* @param Element $base Element to attach to
|
|
* @param Element $attach Element to attach (single)
|
|
* @param string $id Optional id, if empty then attached at the end
|
|
* If set will loop through ALL sub elements until
|
|
* matching id found. if not found, not added
|
|
* @return Element Element with attached sub element
|
|
*/
|
|
public static function addElementWithId(
|
|
Element $base,
|
|
Element $attach,
|
|
string $id = ''
|
|
): Element {
|
|
// no id or matching id
|
|
if (
|
|
empty($id) ||
|
|
$base->getId() == $id
|
|
) {
|
|
$base->addSub($attach);
|
|
return $base;
|
|
}
|
|
// find id in 'id' in all 'sub'
|
|
foreach ($base->getSub() as $el) {
|
|
self::addElementWithId($el, $attach, $id);
|
|
}
|
|
|
|
return $base;
|
|
}
|
|
|
|
/**
|
|
* add one or more elemens to $base
|
|
*
|
|
* @param Element $base Element to attach to
|
|
* @param Element ...$attach Element or Elements to attach
|
|
* @return Element Element with attached sub elements
|
|
*/
|
|
public static function addElement(
|
|
Element $base,
|
|
Element ...$attach
|
|
): Element {
|
|
// we must make sure we do not self attach
|
|
$base->addSub(...$attach);
|
|
return $base;
|
|
}
|
|
|
|
/**
|
|
* Static call version for building
|
|
* not recommended to be used, rather use "Element->buildHtml()"
|
|
* wrapper for buildHtml
|
|
*
|
|
* @param ?Element $tree Element tree to build
|
|
* if not set returns empty string
|
|
* @param bool $add_nl [default=false] Optional output string line break
|
|
* @return string build html as string
|
|
* @deprecated Do not use, use Element->buildHtml() instead
|
|
*/
|
|
public static function printHtmlFromObject(?Element $tree = null, bool $add_nl = false): string
|
|
{
|
|
// nothing ->bad
|
|
if ($tree === null) {
|
|
return '';
|
|
}
|
|
return $tree->buildHtml(add_nl: $add_nl);
|
|
}
|
|
|
|
/**
|
|
* Undocumented function
|
|
* wrapper for buildHtmlFromList
|
|
*
|
|
* @param array<Element> $list array of Elements to build string from
|
|
* @param bool $add_nl [default=false] Optional output string line break
|
|
* @return string build html as string
|
|
*/
|
|
public static function printHtmlFromArray(array $list, bool $add_nl = false): string
|
|
{
|
|
return self::buildHtmlFromList($list, $add_nl);
|
|
}
|
|
}
|
|
|
|
// __END__
|