<?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 } }