true, 'csrf-token' => true, ]; public function init() { parent::init(); $this->setTemplate('layout'); $this->tagsAttributes = [ 'html' => [ 'xmlns:og' => 'http://ogp.me/ns#', 'xmlns:fb' => 'http://www.facebook.com/2008/fbml', ], 'head' => [], 'body' => [], ]; } /** * Add attributes to HTML tag * @param string|array $key * @param mixed $value * @param bool $extend * @return void */ public function addHtmlAttribute($key, $value = '', $extend = true) { $this->addTagAttribute('html', $key, $value, $extend); } /** * Add attributes to HEAD tag * @param string|array $key * @param mixed $value * @param bool $extend * @return void */ public function addHeadAttribute($key, $value = '', $extend = true) { $this->addTagAttribute('head', $key, $value, $extend); } /** * Add content to HEAD * @param string|Closure $content * @return void */ public function addToHead($content) { $this->head[] = $content; } /** * Add content to the beginning of HEAD * @param string|Closure $content * @return void */ public function beforeHead($content) { $this->sectionExtend('head', function ($head) use ($content) { return $this->toString($content) . $head; }); } /** * Add content to the end of HEAD * @param string|Closure $content * @return void */ public function afterHead($content) { $this->sectionExtend('head', function ($head) use ($content) { return $head . $this->toString($content); }); } /** * Add attributes to BODY tag * @param string|array $key * @param mixed $value * @param bool $extend * @return void */ public function addBodyAttribute($key, $value = '', $extend = true) { $this->addTagAttribute('body', $key, $value, $extend); } /** * Add class to BODY tag * @param string|string[] $class * @param bool $extend * @return void */ public function addBodyClass($class, $extend = true) { $this->addTagAttribute('body', 'class', $class, $extend); } /** * Add content to BODY * @param string|Closure $content * @return void */ public function addToBody($content) { $this->body[] = $content; } /** * Add content to BODY * @param string|Closure $content * @param bool $only * @return static */ public function withBody($content, $only = false) { if ($only) { $this->body = [$content]; } else { $this->addToBody($content); } return $this; } /** * Add content to the beginning of BODY * @param string|Closure $content * @return void */ public function beforeBody($content) { $this->sectionExtend('body', function ($body) use ($content) { return $this->toString($content) . $body; }); } /** * Add content to the end of BODY * @param string|Closure $content * @return void */ public function afterBody($content) { $this->sectionExtend('body', function ($body) use ($content) { return $body . $this->toString($content); }); } /** * Set meta options * @param array $options * @param bool $extend * @return void */ public function setMetaOptions(array $options, $extend = true) { if ($extend) { $this->metaOptions = array_merge($this->metaOptions, $options); } else { $this->metaOptions = $options; } } public function gatherData() { parent::gatherData(); # Language RTL support if ($this->locale->isRTL()) { $this->addHtmlAttribute('dir', 'rtl'); $this->addBodyAttribute('class', 'rtl'); } /** * Body should be first to be able to register all the scripts/styles... */ $this->with('body', $this->toString($this->body)); # head $this->with('head', $this->toString($this->head)); # meta $this->beforeHead(SEO::metaRender($this->metaOptions)); # counters Site::i()->countersToLayout($this); # styles $this->with('styles', ( $this->view->render($this->data, 'css', null, ['this' => $this]) . # templates/css $this->view->stylesRender() )); # scripts $this->afterBody($this->view->render($this->data, 'js', null, ['this' => $this])); # templates/js if ($this->isDebug() && ($consoleLogs = bff::logger()->consoleLogs())) { $this->afterBody(''); } $this->with('jsData', $this->view->renderJsData()); $this->with('scripts', $this->view->scriptsRender()); $this->with('scriptsInlineHead', $this->view->scriptsInlineRender(View::POS_HEAD)); $this->with('scriptsInlineFoot', $this->view->scriptsInlineRender(View::POS_FOOT)); foreach ($this->tagsAttributes as $tag => $attributes) { $this->with($tag . 'Attributes', HTML::attributes($attributes)); } } /** * Convert any data (functions, arrays, objects) to string * @param mixed $data * @param string $separator * @return string */ protected function toString($data, $separator = '') { if (is_array($data)) { return join($separator, array_map(function ($content) { return $this->toString($content); }, $data)); } if ($data instanceof Closure) { $data = $data(); } if (is_null($data)) { return ''; } if (! is_scalar($data) && ! method_exists($data, '__toString')) { return ''; } return strval($data); } }