370 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			370 lines
		
	
	
		
			9.7 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\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
 | |
|   }
 | |
| }
 |