371 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			371 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?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\IBasicPage;
 | 
						|
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 (!$this->beforePrint($page)) return;
 | 
						|
    if ($page instanceof IPage) {
 | 
						|
      $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();
 | 
						|
    } else {
 | 
						|
      # si ce n'est pas une instance de IPage, l'imprimer tel quel
 | 
						|
      $this->haveOutput = true;
 | 
						|
      co::_write([$page]);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  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
 | 
						|
  }
 | 
						|
}
 |