nur-sery/nur_src/v/html5/Html5VanillaPageContainer.php

365 lines
9.6 KiB
PHP
Raw Normal View History

2023-12-03 22:10:18 +04:00
<?php
namespace nur\v\html5;
use nur\A;
use nur\b\ValueException;
use nur\co;
use nur\config;
use nur\func;
use nur\msg;
use nur\str;
use nur\v\base\AbstractPageContainer;
use nur\v\base\MenuManager;
use nur\v\fo;
use nur\v\ly;
use nur\v\model\IComponent;
use nur\v\model\IPage;
use nur\v\model\IPlugin;
use nur\v\navbar;
use nur\v\prefix;
use nur\v\v;
class Html5VanillaPageContainer extends AbstractPageContainer {
protected function initToolkit(): void {
msg::set_messenger_class(Html5Messenger::class);
fo::set_manager_class(Html5FormManager::class);
ly::set_manager_class(Html5LayoutManager::class);
navbar::set_manager_class(Html5NavbarManager::class);
navbar::set_menu_manager_class(MenuManager::class);
}
protected function overrideSetup(IPage $page): void {
$plugins =& $this->config["plugins"];
foreach ($this->components as $c) {
if ($c instanceof IComponent) {
self::ensure_preparec($c, true);
self::ensure_setupc($c, true);
}
if ($c instanceof IPlugin) $plugins[] = $c;
}
# Si la page courante est un plugin, l'ajouter aussi
if ($page instanceof IPlugin) $plugins[] = $page;
foreach ($plugins as &$plugin) {
if (is_string($plugin)) $plugin = new $plugin();
elseif (is_array($plugin)) $plugin = func::cons(...$plugin);
}; unset($plugin);
}
protected function overridePrint(IPage $page): void {
if ($page->haveContent()) {
$this->doResolveConfig();
$this->haveOutput = true;
$this->printStartHtml();
$this->printStartHead();
$this->printCssLinks();
$this->printCss();
$this->printJsLinks();
$this->printJs();
$this->printScript();
$this->printHeadTitle();
$this->printEndHead();
$this->printStartBody();
$this->printContent();
$this->printEndBody();
$this->printEndHtml();
}
}
const JQUERY_MIN_JS = "nur-base/jquery/jquery.min.js";
const JQUERY_JS = "nur-base/jquery/jquery.js";
protected $haveCss = [];
protected function setHaveCss(string $name, bool $haveCss=true): void {
$this->haveCss[$name] = $haveCss;
}
protected function haveCss(string $name): bool {
return boolval(A::get($this->haveCss, $name));
}
protected $haveJs = [];
protected function setHaveJs(string $name, bool $haveJs=true): void {
$this->haveJs[$name] = $haveJs;
}
protected function haveJs(string $name): bool {
return boolval(A::get($this->haveJs, $name));
}
/** @var string[] */
protected $cssUrls;
/** @var string[] */
protected $jsUrls;
/** @var bool */
protected $needsJquery;
function doResolveConfig(): void {
$cssUrls = $this->getCssUrls();
$jsUrls = $this->getJsUrls();
$this->needsJquery = config::is_fact(config::FACT_NEEDS_JQUERY);
$plugins = $this->getPlugins();
foreach ($plugins as $plugin) {
if ($plugin instanceof IPlugin) {
$this->needsJquery |= $plugin->haveJquery();
$urls = A::with($plugin->getCss());
if ($plugin->isDynamicCss()) {
A::merge($cssUrls, $urls);
} else {
$index = 0;
foreach ($urls as $key => $url) {
if (!$url) continue;
if ($key === $index) {
if (in_array($url, $cssUrls)) continue;
$cssUrls[] = $url;
} else {
if ($this->haveCss($key)) continue;
if (in_array($url, $cssUrls)) continue;
$cssUrls[$key] = $url;
$this->setHaveCss($key);
}
$index++;
}
}
$urls = A::with($plugin->getJs());
if ($plugin->isDynamicJs()) {
A::merge($jsUrls, $urls);
} else {
$index = 0;
foreach ($urls as $key => $url) {
if (!$url) continue;
if (array_key_exists($key, $jsUrls)) continue;
if ($key === $index) {
if (in_array($url, $jsUrls)) continue;
$jsUrls[] = $url;
} else {
if ($this->haveJs($key)) continue;
if (in_array($url, $jsUrls)) continue;
$jsUrls[$key] = $url;
$this->setHaveJs($key);
}
$index++;
}
}
} else {
throw ValueException::unexpected_type(IPlugin::class, $plugin);
}
}
if ($this->needsJquery && !$this->haveJs("jquery")) {
# toujours mettre jquery en premier
$prevJsUrls = $jsUrls;
$jsUrls = ["jquery" => self::JQUERY_MIN_JS];
A::merge($jsUrls, $prevJsUrls);
}
$this->cssUrls = $cssUrls;
$this->jsUrls = $jsUrls;
}
function printStartHtml(): void {
?>
<!DOCTYPE html>
<html lang="fr" xmlns="http://www.w3.org/1999/xhtml">
<?php
}
function printStartHead(): void {
$prefix = $this->getSelfRelativePrefix();
?>
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="<?=$prefix?>nur-base/base.css" rel="stylesheet"/>
<?php
}
function printCssLinks(): void {
$prefix = $this->getSelfRelativePrefix();
foreach ($this->cssUrls as $url) {
$url = prefix::add($url, $prefix);
?>
<link href="<?=$url?>" rel="stylesheet"/>
<?php
}
}
function printCss(): void {
foreach ($this->getPlugins() as $plugin) {
$plugin->printCss();
}
}
function printJsLinks(): void {
$prefix = $this->getSelfRelativePrefix();
foreach ($this->jsUrls as $url) {
$url = prefix::add($url, $prefix);
?>
<script src="<?=$url?>" type="text/javascript"></script>
<?php
}
}
function printJs(): void {
foreach ($this->getPlugins() as $plugin) {
$plugin->printJs();
}
}
protected function beforeCapture(): void {
ob_start(null, 0, PHP_OUTPUT_HANDLER_STDFLAGS ^ PHP_OUTPUT_HANDLER_FLUSHABLE);
}
private static function strip_lines(array &$lines): void {
while (count($lines) > 0 && !$lines[0]) {
# enlever les lignes vides au début
array_shift($lines);
}
while (($count = count($lines)) > 0 && !$lines[$count - 1]) {
# enlever les lignes vides à la fin
array_pop($lines);
}
}
const RE_START_SCRIPT = '/^\s*<script\s+type="(?:text\/)?javascript">\s*(.*)/';
const RE_END_SCRIPT = '/(.*?)\s*<\/script>\s*$/';
private static function unwrap_script(array &$lines): void {
$count = count($lines);
if ($count >= 2) {
$first = $lines[0];
$last = $lines[$count - 1];
if (preg_match(self::RE_START_SCRIPT, $first)
&& preg_match(self::RE_END_SCRIPT, $last)) {
$last = preg_replace(self::RE_END_SCRIPT, '$1', $last);
if ($last) $lines[$count - 1] = $last;
else $lines = array_slice($lines, 0, $count - 1);
$first = preg_replace(self::RE_START_SCRIPT, '$1', $first);
if ($first) $lines[0] = $first;
else $lines = array_slice($lines, 1);
}
}
}
protected $scripts = [];
protected function captureScript(): void {
$lines = trim(ob_get_clean());
if ($lines) {
$lines = str::split_nl($lines);
self::strip_lines($lines);
self::unwrap_script($lines);
$this->scripts[] = implode("\n", $lines);
}
}
const RE_START_JQUERY = '/^\s*jQuery(?:.noConflict\(\))?\(function\(\$\) {\s*(.*)/';
const RE_END_JQUERY = '/(.*?)\s*}\);\s*$/';
private static function unwrap_jquery(array &$lines): void {
$count = count($lines);
if ($count >= 2) {
$first = $lines[0];
$last = $lines[$count - 1];
if (preg_match(self::RE_START_JQUERY, $first)
&& preg_match(self::RE_END_JQUERY, $last)) {
$last = preg_replace(self::RE_END_JQUERY, '$1', $last);
if ($last) $lines[$count - 1] = $last;
else $lines = array_slice($lines, 0, $count - 1);
$first = preg_replace(self::RE_START_JQUERY, '$1', $first);
if ($first) $lines[0] = $first;
else $lines = array_slice($lines, 1);
}
}
}
protected $jqueries = [];
protected function captureJquery(): void {
$lines = trim(ob_get_clean());
if ($lines) {
$lines = str::split_nl($lines);
self::strip_lines($lines);
self::unwrap_script($lines);
self::unwrap_jquery($lines);
$this->jqueries[] = implode("\n", $lines);
}
}
protected function resolvePluginsScripts(): void {
foreach ($this->getPlugins() as $plugin) {
if ($plugin->haveScript()) {
$this->beforeCapture();
$plugin->printScript();
$this->captureScript();
}
if ($plugin->haveJquery()) {
$this->beforeCapture();
$plugin->printJquery();
$this->captureJquery();
}
}
}
protected function printMergedScripts(): void {
$scripts = $this->scripts;
$jqueries = $this->jqueries;
if ($scripts || $jqueries) {
?>
<script type="text/javascript">
<?php
foreach ($scripts as $script) {
echo "$script\n";
}
}
if ($jqueries) {
?>
jQuery.noConflict()(function($) {
<?php
foreach ($jqueries as $jquery) {
echo "$jquery\n";
}
?>
});
<?php
}
if ($scripts || $jqueries) {
?>
</script>
<?php
}
}
function printScript(): void {
$this->resolvePluginsScripts();
$this->printMergedScripts();
}
function printHeadTitle(): void {
co::_print(v::tag("title", $this->getTitle()));
}
function printEndHead(): void {
?>
</head>
<?php
}
function printStartBody(): void {
?>
<body>
<?php
}
function printContent(): void {
co::_write([$this->page]);
ly::end();
}
function printEndBody(): void {
?>
</body>
<?php
}
function printEndHtml(): void {
?>
</html>
<?php
}
}