Files
EasySoft-ZenTaoPMS/lib/zin/core/dom.class.php
T
2023-07-25 17:42:27 +08:00

396 lines
11 KiB
PHP

<?php
declare(strict_types=1);
/**
* The dom widget class file of zin of ZenTaoPMS.
*
* @copyright Copyright 2023 青岛易软天创网络科技有限公司(QingDao Nature Easy Soft Network Technology Co,LTD, www.cnezsoft.com)
* @author Hao Sun <sunhao@easycorp.ltd>
* @package zin
* @version $Id
* @link https://www.zentao.net
*/
namespace zin;
use stdClass;
require_once dirname(__DIR__) . DS . 'utils' . DS . 'deep.func.php';
require_once __DIR__ . DS . 'selector.func.php';
class dom
{
/**
* @var wg
*/
public $wg;
public $children = array();
public $selectors = null;
public $renderInner = false;
public $renderType;
public $dataGetters = null;
public $dataCommands;
public $buildList = null;
public $buildListInner = false;
/**
* Construct the dom object.
*
* @param wg $wg
* @param array $children
* @param array|string|object $selectors
* @access public
*/
public function __construct($wg, $children, $selectors = null, $renderType = null, $dataCommands = null)
{
$this->wg = $wg;
$this->renderType = $renderType;
$this->add($children);
$this->addSelectors($selectors);
$this->addDataCommands($dataCommands);
}
public function __debugInfo()
{
return array(
'gid' => $this->wg->gid,
'type' => $this->wg->type(),
'count' => count($this->children),
'renderInner' => $this->renderInner,
'renderType' => $this->renderType,
'dataCommands' => $this->dataCommands,
'selectors' => stringifyWgSelectors($this->selectors)
);
}
public function add($children)
{
if(empty($children)) return;
if(!is_array($children)) $children = [$children];
foreach($children as $child)
{
if(is_array($child)) $this->add($child);
else $this->children[] = $child;
}
}
public function addDataCommands($commands)
{
if(empty($commands)) return;
if(is_string($commands))
{
$commandList = explode(',', $commands);
$commands = array();
foreach($commandList as $command)
{
$parts = explode(':', $command, 2);
$commands[$parts[0]] = count($parts) > 1 ? $parts[1] : $parts[0];
}
}
if($this->dataCommands === null) $this->dataCommands = array();
$index = 0;
foreach($commands as $key => $command)
{
$this->dataCommands[$index == $key ? $command : $key] = $command;
$index++;
}
}
public function addSelectors($selectors)
{
if(empty($selectors)) return;
if($this->selectors === null) $this->selectors = array();
$selectors = parseWgSelectors($selectors);
foreach($selectors as $selector)
{
if(isset($selector->command) && !empty($selector->command)) $this->addDataCommands([$selector->tag => $selector->command]);
else $this->selectors[] = $selector;
}
}
public function isMatch($selector)
{
return $this->wg->isMatch($selector);
}
/**
* Build the children dom list.
* @access public
* @return array
*/
public function build()
{
if($this->buildList !== null && $this->buildListInner === $this->renderInner) return $this->buildList;
if(empty($this->selectors) && !empty($this->dataCommands))
{
$this->buildList = array();
return $this->buildList;
}
$list = array();
$children = $this->renderInner ? $this->wg->children() : $this->children;
if(empty($children)) return $list;
foreach($children as $child) $list[] = ($child instanceof wg) ? $child->buildDom() : $child;
if(!empty($this->selectors)) $list = static::filter($list, $this->selectors);
$this->buildList = $list;
$this->buildListInner = $this->renderInner;
return $list;
}
public function render()
{
if($this->renderType === 'json') return $this->renderJson();
if($this->renderType === 'list') return $this->renderList();
return $this->renderHtml();
}
/**
* Render dom to json object.
*
* @access public
* @return object
*/
public function renderJson(): object
{
$list = $this->build();
$output = new stdClass();
foreach($list as $name => $item)
{
$output->$name = static::renderItemToJson($item);
}
if(!empty($this->dataCommands))
{
$data = array();
foreach($this->dataCommands as $name => $command)
{
$data[$name] = data($command);
}
$output->data = $data;
}
return $output;
}
/**
* Render dom to html string.
*
* @access public
* @return string
*/
public function renderHtml(): string
{
$list = $this->build();
if(empty($list)) return '';
$output = array();
foreach($list as $item)
{
$result = static::renderItemToHtml($item);
if(!is_string($result)) $result = json_encode($result);
$output[] = $result;
}
return implode('', $output);
}
/**
* Render dom to list by given selector.
*
* @access public
* @return array
*/
public function renderList(): array
{
$list = $this->build();
$output = array();
foreach($list as $name => $item)
{
if(is_array($item) && count($item) === 1) $item = $item[0];
$renderType = $item instanceof dom ? $item->renderType : 'html';
if(empty($renderType)) $renderType = 'html';
$output[] = array('name' => $name, 'data' => static::renderDomItem($item, $renderType), 'type' => $renderType);
}
if(!empty($this->dataCommands))
{
foreach($this->dataCommands as $name => $command)
{
$output[] = array('name' => $name, 'data' => data($command), 'type' => 'command');
}
}
return $output;
}
public static function renderDomItem($item, $defaultType = 'html')
{
if($item instanceof dom)
{
$renderType = $item->renderType;
if(empty($renderType)) $renderType = $defaultType;
if($renderType === 'json') return dom::renderItemToJson($item);
return dom::renderItemToHtml($item->build());
}
$renderType = $defaultType;
if($renderType === 'json') return static::renderItemToJson($item);
return static::renderItemToHtml($item);
}
public static function renderItemToJson($item)
{
if($item === null || is_bool($item)) return null;
if(is_array($item))
{
$output = array();
foreach($item as $subItem) $output[] = static::renderItemToJson($subItem);
return $output;
}
if($item instanceof dom)
{
$json = $item->wg->toJsonData();
if(!empty($item->dataGetters))
{
$output = array();
$props = explode(',', $item->dataGetters);
foreach($props as $prop)
{
$prop = trim($prop);
if(empty($prop)) continue;
$parts = explode(':', $prop, 2);
$name = $parts[0];
$namePath = count($parts) > 1 ? $parts[1] : $parts[0];
$output[$name] = \zin\utils\deepGet($json, $namePath);
}
return $output;
}
return $json;
}
if($item instanceof wg) return dom::renderDomItem($item, 'json');
if(is_string($item)) return $item;
if(is_object($item))
{
if(isDirective($item, 'html')) return $item->data;
if(isDirective($item, 'text')) return htmlspecialchars($item->data);
if(isset($item->html)) return $item->html;
if(isset($item->text)) return htmlspecialchars($item->text);
if(method_exists($item, 'render')) return $item->render();
}
return strval($item);
}
public static function renderItemToHtml($item)
{
if($item === null || is_bool($item)) return '';
if(is_array($item))
{
$output = array();
foreach($item as $subItem) $output[] = static::renderItemToHtml($subItem);
return implode('', $output);
}
if($item instanceof dom) return dom::renderItemToHtml($item->build());
if($item instanceof wg) return $item->render();
if(is_string($item)) return $item;
if(is_object($item))
{
if(isDirective($item, 'html')) return $item->data;
if(isDirective($item, 'text')) return htmlspecialchars($item->data);
if(isset($item->html)) return $item->html;
if(isset($item->text)) return htmlspecialchars($item->text);
if(method_exists($item, 'render')) return $item->render();
}
return strval($item);
}
/**
* Filter the dom list with selector.
*
* @param array $list
* @param object $selector
* @param array $filteredList
* @access public
* @return array
*/
public static function filterList(&$list, $selector, &$filteredList)
{
if(empty($list) || empty($selector)) return [];
$results = array();
foreach($list as $item)
{
if(!($item instanceof dom) || in_array($item->wg->gid, $filteredList)) continue;
if($item->wg->isMatch($selector))
{
$item->selector = $selector;
$item->renderInner = isset($selector->inner) ? $selector->inner : false;
$item->renderType = isset($selector->type) ? $selector->type : null;
$item->dataGetters = isset($selector->data) ? $selector->data : null;
$filteredList[] = $item->wg->gid;
$results[] = $item;
}
else
{
$children = $item->build();
if(!empty($children))
{
$subResults = static::filterList($children, $selector, $filteredList);
foreach($subResults as $subItem) $results[] = $subItem;
}
}
if($selector->first && !empty($results)) break;
}
return $results;
}
/**
* Filter the dom list with selectors.
*
* @param array $domList
* @param array $selectors
* @access public
* @return array
*/
public static function filter(&$domList, $selectors)
{
if(empty($selectors)) return $domList;
$list = array();
$filteredList = array();
foreach($selectors as $selector)
{
$results = static::filterList($domList, $selector, $filteredList);
$list[$selector->name] = $results;
}
return $list;
}
}