1
0
mirror of https://github.com/flarum/core.git synced 2025-07-24 02:01:19 +02:00

Refactor frontend code to allow for extension of assets

- Simpler class naming:
    Frontend\CompilerFactory → Frontend\Assets
    Frontend\HtmlDocumentFactory → Frontend\Frontend
    Frontend\HtmlDocument → Frontend\Document

- Remove AssetInterface and simply collect callbacks in Frontend\Assets
  instead

- Remove ContentInterface because it serves no purpose (never type-
  hinted or type-checked)

- Commit and add asset URLs to the Document via a content callback
  instead of in the Document factory class itself

- Add translations and locale assets to Assets separate to the assets
  factory, as non-forum/admin asset bundles probably won't want them

- Update Frontend Extender to allow the creation of new asset bundles

- Make custom LESS validation listener a standalone class instead of
  extending RecompileFrontendAssets
This commit is contained in:
Toby Zerner
2018-11-16 13:54:13 +10:30
parent 59330d8fe6
commit 171f9184d9
34 changed files with 519 additions and 946 deletions

View File

@@ -0,0 +1,46 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Frontend;
use Flarum\Frontend\Compiler\Source\SourceCollector;
use Flarum\Locale\LocaleManager;
class AddLocaleAssets
{
/**
* @var LocaleManager
*/
protected $locales;
/**
* @param LocaleManager $locales
*/
public function __construct(LocaleManager $locales)
{
$this->locales = $locales;
}
public function to(Assets $assets)
{
$assets->localeJs(function (SourceCollector $sources, string $locale) {
foreach ($this->locales->getJsFiles($locale) as $file) {
$sources->addFile($file);
}
});
$assets->localeCss(function (SourceCollector $sources, string $locale) {
foreach ($this->locales->getCssFiles($locale) as $file) {
$sources->addFile($file);
}
});
}
}

View File

@@ -0,0 +1,64 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Frontend;
use Flarum\Frontend\Compiler\Source\SourceCollector;
use Flarum\Locale\LocaleManager;
class AddTranslations
{
/**
* @var LocaleManager
*/
protected $locales;
/**
* @var callable
*/
protected $filter;
public function __construct(LocaleManager $locales, callable $filter = null)
{
$this->locales = $locales;
$this->filter = $filter;
}
public function forFrontend(string $name)
{
$this->filter = function (string $id) use ($name) {
return preg_match('/^.+(?:\.|::)(?:'.$name.'|lib)\./', $id);
};
return $this;
}
public function to(Assets $assets)
{
$assets->localeJs(function (SourceCollector $sources, string $locale) {
$sources->addString(function () use ($locale) {
$translations = $this->getTranslations($locale);
return 'flarum.core.app.translator.addTranslations('.json_encode($translations).')';
});
});
}
private function getTranslations(string $locale)
{
$translations = $this->locales->getTranslator()->getCatalogue($locale)->all('messages');
return array_only(
$translations,
array_filter(array_keys($translations), $this->filter)
);
}
}

View File

@@ -1,39 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Frontend\Asset;
use Flarum\Frontend\Compiler\Source\SourceCollector;
interface AssetInterface
{
/**
* @param SourceCollector $sources
*/
public function js(SourceCollector $sources);
/**
* @param SourceCollector $sources
*/
public function css(SourceCollector $sources);
/**
* @param SourceCollector $sources
* @param string $locale
*/
public function localeJs(SourceCollector $sources, string $locale);
/**
* @param SourceCollector $sources
* @param string $locale
*/
public function localeCss(SourceCollector $sources, string $locale);
}

View File

@@ -1,48 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Frontend\Asset;
use Flarum\Frontend\Compiler\Source\SourceCollector;
class CoreAssets implements AssetInterface
{
/**
* @var string
*/
protected $name;
/**
* @param string $name
*/
public function __construct(string $name)
{
$this->name = $name;
}
public function js(SourceCollector $sources)
{
$sources->addFile(__DIR__."/../../../js/dist/$this->name.js");
}
public function css(SourceCollector $sources)
{
$sources->addFile(__DIR__."/../../../less/$this->name.less");
}
public function localeJs(SourceCollector $sources, string $locale)
{
}
public function localeCss(SourceCollector $sources, string $locale)
{
}
}

View File

@@ -1,82 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Frontend\Asset;
use Flarum\Frontend\Compiler\Source\SourceCollector;
class ExtensionAssets implements AssetInterface
{
/**
* @var string
*/
protected $moduleName;
/**
* @var array
*/
protected $css;
/**
* @var string|callable|null
*/
protected $js;
/**
* @param string $moduleName
* @param array $css
* @param string|callable|null $js
*/
public function __construct(string $moduleName, array $css, $js = null)
{
$this->moduleName = $moduleName;
$this->css = $css;
$this->js = $js;
}
public function js(SourceCollector $sources)
{
if ($this->js) {
$sources->addString(function () {
return 'var module={}';
});
if (is_callable($this->js)) {
$sources->addString($this->js);
} else {
$sources->addFile($this->js);
}
$sources->addString(function () {
return "flarum.extensions['$this->moduleName']=module.exports";
});
}
}
public function css(SourceCollector $sources)
{
foreach ($this->css as $asset) {
if (is_callable($asset)) {
$sources->addString($asset);
} else {
$sources->addFile($asset);
}
}
}
public function localeJs(SourceCollector $sources, string $locale)
{
}
public function localeCss(SourceCollector $sources, string $locale)
{
}
}

View File

@@ -1,65 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Frontend\Asset;
use Flarum\Frontend\Compiler\Source\SourceCollector;
use Flarum\Settings\SettingsRepositoryInterface;
class LessVariables implements AssetInterface
{
/**
* @var SettingsRepositoryInterface
*/
protected $settings;
/**
* @param SettingsRepositoryInterface $settings
*/
public function __construct(SettingsRepositoryInterface $settings)
{
$this->settings = $settings;
}
public function css(SourceCollector $sources)
{
$this->addLessVariables($sources);
}
public function localeCss(SourceCollector $sources, string $locale)
{
$this->addLessVariables($sources);
}
private function addLessVariables(SourceCollector $compiler)
{
$vars = [
'config-primary-color' => $this->settings->get('theme_primary_color', '#000'),
'config-secondary-color' => $this->settings->get('theme_secondary_color', '#000'),
'config-dark-mode' => $this->settings->get('theme_dark_mode') ? 'true' : 'false',
'config-colored-header' => $this->settings->get('theme_colored_header') ? 'true' : 'false'
];
$compiler->addString(function () use ($vars) {
return array_reduce(array_keys($vars), function ($string, $name) use ($vars) {
return $string."@$name: {$vars[$name]};";
}, '');
});
}
public function js(SourceCollector $sources)
{
}
public function localeJs(SourceCollector $sources, string $locale)
{
}
}

View File

@@ -1,53 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Frontend\Asset;
use Flarum\Frontend\Compiler\Source\SourceCollector;
use Flarum\Locale\LocaleManager;
class LocaleAssets implements AssetInterface
{
/**
* @var LocaleManager
*/
protected $locales;
/**
* @param LocaleManager $locales
*/
public function __construct(LocaleManager $locales)
{
$this->locales = $locales;
}
public function localeJs(SourceCollector $sources, string $locale)
{
foreach ($this->locales->getJsFiles($locale) as $file) {
$sources->addFile($file);
}
}
public function localeCss(SourceCollector $sources, string $locale)
{
foreach ($this->locales->getCssFiles($locale) as $file) {
$sources->addFile($file);
}
}
public function js(SourceCollector $sources)
{
}
public function css(SourceCollector $sources)
{
}
}

View File

@@ -1,87 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Frontend\Asset;
use Flarum\Frontend\Compiler\Source\SourceCollector;
use Flarum\Locale\LocaleManager;
class Translations implements AssetInterface
{
/**
* @var LocaleManager
*/
protected $locales;
/**
* @var callable
*/
protected $filter;
/**
* @param LocaleManager $locales
*/
public function __construct(LocaleManager $locales)
{
$this->locales = $locales;
$this->filter = function () {
return false;
};
}
public function localeJs(SourceCollector $sources, string $locale)
{
$sources->addString(function () use ($locale) {
$translations = $this->getTranslations($locale);
return 'flarum.core.app.translator.addTranslations('.json_encode($translations).')';
});
}
private function getTranslations(string $locale)
{
$translations = $this->locales->getTranslator()->getCatalogue($locale)->all('messages');
return array_only(
$translations,
array_filter(array_keys($translations), $this->filter)
);
}
/**
* @return callable
*/
public function getFilter(): callable
{
return $this->filter;
}
/**
* @param callable $filter
*/
public function setFilter(callable $filter)
{
$this->filter = $filter;
}
public function js(SourceCollector $sources)
{
}
public function css(SourceCollector $sources)
{
}
public function localeCss(SourceCollector $sources, string $locale)
{
}
}

View File

@@ -11,25 +11,34 @@
namespace Flarum\Frontend;
use Flarum\Frontend\Asset\AssetInterface;
use Flarum\Frontend\Compiler\CompilerInterface;
use Flarum\Frontend\Compiler\JsCompiler;
use Flarum\Frontend\Compiler\LessCompiler;
use Flarum\Frontend\Compiler\Source\SourceCollector;
use Illuminate\Filesystem\FilesystemAdapter;
use Illuminate\Contracts\Filesystem\Filesystem;
/**
* A factory class for creating frontend asset compilers.
*/
class CompilerFactory
class Assets
{
/**
* @var array
*/
public $sources = [
'js' => [],
'css' => [],
'localeJs' => [],
'localeCss' => []
];
/**
* @var string
*/
protected $name;
/**
* @var FilesystemAdapter
* @var Filesystem
*/
protected $assetsDir;
@@ -43,23 +52,7 @@ class CompilerFactory
*/
protected $lessImportDirs;
/**
* @var AssetInterface[]
*/
protected $assets = [];
/**
* @var callable[]
*/
protected $addCallbacks = [];
/**
* @param string $name
* @param FilesystemAdapter $assetsDir
* @param string $cacheDir
* @param array|null $lessImportDirs
*/
public function __construct(string $name, FilesystemAdapter $assetsDir, string $cacheDir = null, array $lessImportDirs = null)
public function __construct(string $name, Filesystem $assetsDir, string $cacheDir = null, array $lessImportDirs = null)
{
$this->name = $name;
$this->assetsDir = $assetsDir;
@@ -67,76 +60,84 @@ class CompilerFactory
$this->lessImportDirs = $lessImportDirs;
}
/**
* @param callable $callback
*/
public function add(callable $callback)
public function js($sources)
{
$this->addCallbacks[] = $callback;
$this->addSources('js', $sources);
return $this;
}
public function css($callback)
{
$this->addSources('css', $callback);
return $this;
}
public function localeJs($callback)
{
$this->addSources('localeJs', $callback);
return $this;
}
public function localeCss($callback)
{
$this->addSources('localeCss', $callback);
return $this;
}
private function addSources($type, $callback)
{
$this->sources[$type][] = $callback;
}
private function populate(CompilerInterface $compiler, string $type, string $locale = null)
{
$compiler->addSources(function (SourceCollector $sources) use ($type, $locale) {
foreach ($this->sources[$type] as $callback) {
$callback($sources, $locale);
}
});
}
/**
* @return JsCompiler
*/
public function makeJs(): JsCompiler
{
$compiler = new JsCompiler($this->assetsDir, $this->name.'.js');
$this->addSources($compiler, function (AssetInterface $asset, SourceCollector $sources) {
$asset->js($sources);
});
$this->populate($compiler, 'js');
return $compiler;
}
/**
* @return LessCompiler
*/
public function makeCss(): LessCompiler
{
$compiler = $this->makeLessCompiler($this->name.'.css');
$this->addSources($compiler, function (AssetInterface $asset, SourceCollector $sources) {
$asset->css($sources);
});
$this->populate($compiler, 'css');
return $compiler;
}
/**
* @param string $locale
* @return JsCompiler
*/
public function makeLocaleJs(string $locale): JsCompiler
{
$compiler = new JsCompiler($this->assetsDir, $this->name.'-'.$locale.'.js');
$this->addSources($compiler, function (AssetInterface $asset, SourceCollector $sources) use ($locale) {
$asset->localeJs($sources, $locale);
});
$this->populate($compiler, 'localeJs', $locale);
return $compiler;
}
/**
* @param string $locale
* @return LessCompiler
*/
public function makeLocaleCss(string $locale): LessCompiler
{
$compiler = $this->makeLessCompiler($this->name.'-'.$locale.'.css');
$this->addSources($compiler, function (AssetInterface $asset, SourceCollector $sources) use ($locale) {
$asset->localeCss($sources, $locale);
});
$this->populate($compiler, 'localeCss', $locale);
return $compiler;
}
/**
* @param string $filename
* @return LessCompiler
*/
protected function makeLessCompiler(string $filename): LessCompiler
{
$compiler = new LessCompiler($this->assetsDir, $filename);
@@ -152,86 +153,41 @@ class CompilerFactory
return $compiler;
}
protected function fireAddCallbacks()
{
foreach ($this->addCallbacks as $callback) {
$assets = $callback($this);
$this->assets = array_merge($this->assets, is_array($assets) ? $assets : [$assets]);
}
$this->addCallbacks = [];
}
private function addSources(CompilerInterface $compiler, callable $callback)
{
$compiler->addSources(function ($sources) use ($callback) {
$this->fireAddCallbacks();
foreach ($this->assets as $asset) {
$callback($asset, $sources);
}
});
}
/**
* @return string
*/
public function getName(): string
{
return $this->name;
}
/**
* @param string $name
*/
public function setName(string $name)
{
$this->name = $name;
}
/**
* @return FilesystemAdapter
*/
public function getAssetsDir(): FilesystemAdapter
public function getAssetsDir(): Filesystem
{
return $this->assetsDir;
}
/**
* @param FilesystemAdapter $assetsDir
*/
public function setAssetsDir(FilesystemAdapter $assetsDir)
public function setAssetsDir(Filesystem $assetsDir)
{
$this->assetsDir = $assetsDir;
}
/**
* @return string
*/
public function getCacheDir(): ?string
{
return $this->cacheDir;
}
/**
* @param string $cacheDir
*/
public function setCacheDir(?string $cacheDir)
{
$this->cacheDir = $cacheDir;
}
/**
* @return array
*/
public function getLessImportDirs(): array
{
return $this->lessImportDirs;
}
/**
* @param array $lessImportDirs
*/
public function setLessImportDirs(array $lessImportDirs)
{
$this->lessImportDirs = $lessImportDirs;

View File

@@ -59,7 +59,7 @@ class LessCompiler extends RevisionCompiler
}
/**
* {@inheritdoc}
* @throws \Less_Exception_Parser
*/
protected function compile(array $sources): string
{

View File

@@ -13,7 +13,7 @@ namespace Flarum\Frontend\Compiler;
use Flarum\Frontend\Compiler\Source\SourceCollector;
use Flarum\Frontend\Compiler\Source\SourceInterface;
use Illuminate\Filesystem\FilesystemAdapter;
use Illuminate\Contracts\Filesystem\Filesystem;
class RevisionCompiler implements CompilerInterface
{
@@ -22,7 +22,7 @@ class RevisionCompiler implements CompilerInterface
const EMPTY_REVISION = 'empty';
/**
* @var FilesystemAdapter
* @var Filesystem
*/
protected $assetsDir;
@@ -37,10 +37,10 @@ class RevisionCompiler implements CompilerInterface
protected $sourcesCallbacks = [];
/**
* @param FilesystemAdapter $assetsDir
* @param Filesystem $assetsDir
* @param string $filename
*/
public function __construct(FilesystemAdapter $assetsDir, string $filename)
public function __construct(Filesystem $assetsDir, string $filename)
{
$this->assetsDir = $assetsDir;
$this->filename = $filename;

View File

@@ -0,0 +1,74 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Frontend\Content;
use Flarum\Foundation\Application;
use Flarum\Frontend\Compiler\CompilerInterface;
use Flarum\Frontend\Document;
use Psr\Http\Message\ServerRequestInterface as Request;
class Assets
{
protected $app;
/**
* @var \Flarum\Frontend\Assets
*/
protected $assets;
public function __construct(Application $app)
{
$this->app = $app;
}
public function forFrontend(string $name)
{
$this->assets = $this->app->make('flarum.assets.'.$name);
return $this;
}
public function __invoke(Document $document, Request $request)
{
$locale = $request->getAttribute('locale');
$compilers = [
'js' => [$this->assets->makeJs(), $this->assets->makeLocaleJs($locale)],
'css' => [$this->assets->makeCss(), $this->assets->makeLocaleCss($locale)]
];
if ($this->app->inDebugMode()) {
$this->commit(array_flatten($compilers));
}
$document->js = array_merge($document->js, $this->getUrls($compilers['js']));
$document->css = array_merge($document->css, $this->getUrls($compilers['css']));
}
private function commit(array $compilers)
{
foreach ($compilers as $compiler) {
$compiler->commit();
}
}
/**
* @param CompilerInterface[] $compilers
* @return string[]
*/
private function getUrls(array $compilers)
{
return array_filter(array_map(function (CompilerInterface $compiler) {
return $compiler->getUrl();
}, $compilers));
}
}

View File

@@ -1,24 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Frontend\Content;
use Flarum\Frontend\HtmlDocument;
use Psr\Http\Message\ServerRequestInterface as Request;
interface ContentInterface
{
/**
* @param HtmlDocument $document
* @param Request $request
*/
public function __invoke(HtmlDocument $document, Request $request);
}

View File

@@ -13,13 +13,13 @@ namespace Flarum\Frontend\Content;
use Flarum\Api\Client;
use Flarum\Api\Controller\ShowUserController;
use Flarum\Frontend\HtmlDocument;
use Flarum\Frontend\Document;
use Flarum\Locale\LocaleManager;
use Flarum\User\User;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface as Request;
class CorePayload implements ContentInterface
class CorePayload
{
/**
* @var LocaleManager
@@ -41,7 +41,7 @@ class CorePayload implements ContentInterface
$this->api = $api;
}
public function __invoke(HtmlDocument $document, Request $request)
public function __invoke(Document $document, Request $request)
{
$document->payload = array_merge(
$document->payload,
@@ -49,7 +49,7 @@ class CorePayload implements ContentInterface
);
}
private function buildPayload(HtmlDocument $document, Request $request)
private function buildPayload(Document $document, Request $request)
{
$data = $this->getDataFromApiDocument($document->getForumApiDocument());

View File

@@ -1,36 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Frontend\Content;
use Flarum\Frontend\HtmlDocument;
use Psr\Http\Message\ServerRequestInterface as Request;
class Layout implements ContentInterface
{
/**
* @var string
*/
protected $layoutView;
/**
* @param string $layoutView
*/
public function __construct(string $layoutView)
{
$this->layoutView = $layoutView;
}
public function __invoke(HtmlDocument $document, Request $request)
{
$document->layoutView = $this->layoutView;
}
}

View File

@@ -11,18 +11,18 @@
namespace Flarum\Frontend\Content;
use Flarum\Frontend\HtmlDocument;
use Flarum\Frontend\Document;
use Psr\Http\Message\ServerRequestInterface as Request;
class Meta implements ContentInterface
class Meta
{
public function __invoke(HtmlDocument $document, Request $request)
public function __invoke(Document $document, Request $request)
{
$document->meta = array_merge($document->meta, $this->buildMeta($document));
$document->head = array_merge($document->head, $this->buildHead($document));
}
private function buildMeta(HtmlDocument $document)
private function buildMeta(Document $document)
{
$forumApiDocument = $document->getForumApiDocument();
@@ -35,7 +35,7 @@ class Meta implements ContentInterface
return $meta;
}
private function buildHead(HtmlDocument $document)
private function buildHead(Document $document)
{
$head = [];

View File

@@ -19,25 +19,19 @@ use Zend\Diactoros\Response\HtmlResponse;
class Controller implements RequestHandlerInterface
{
/**
* @var HtmlDocumentFactory
* @var Frontend
*/
protected $document;
protected $frontend;
/**
* @param HtmlDocumentFactory $document
*/
public function __construct(HtmlDocumentFactory $document)
public function __construct(Frontend $frontend)
{
$this->document = $document;
$this->frontend = $frontend;
}
/**
* {@inheritdoc}
*/
public function handle(Request $request): Response
{
return new HtmlResponse(
$this->document->make($request)->render()
$this->frontend->document($request)->render()
);
}
}

View File

@@ -18,7 +18,7 @@ use Illuminate\Contracts\View\View;
/**
* A view which renders a HTML skeleton for Flarum's frontend app.
*/
class HtmlDocument implements Renderable
class Document implements Renderable
{
/**
* The title of the document, displayed in the <title> tag.

View File

@@ -0,0 +1,84 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Frontend;
use Flarum\Api\Client;
use Flarum\Api\Controller\ShowForumController;
use Illuminate\Contracts\View\Factory;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
class Frontend
{
/**
* @var Factory
*/
protected $view;
/**
* @var Client
*/
protected $api;
/**
* @var callable[]
*/
protected $content = [];
public function __construct(Factory $view, Client $api)
{
$this->view = $view;
$this->api = $api;
}
/**
* @param callable $content
*/
public function content(callable $content)
{
$this->content[] = $content;
}
public function document(Request $request): Document
{
$forumDocument = $this->getForumDocument($request);
$document = new Document($this->view, $forumDocument);
$this->populate($document, $request);
return $document;
}
protected function populate(Document $document, Request $request)
{
foreach ($this->content as $content) {
$content($document, $request);
}
}
private function getForumDocument(Request $request): array
{
$actor = $request->getAttribute('actor');
$this->api->setErrorHandler(null);
return $this->getResponseBody(
$this->api->send(ShowForumController::class, $actor)
);
}
private function getResponseBody(Response $response): array
{
return json_decode($response->getBody(), true);
}
}

View File

@@ -12,21 +12,18 @@
namespace Flarum\Frontend;
use Flarum\Foundation\AbstractServiceProvider;
use Flarum\Frontend\Compiler\Source\SourceCollector;
use Flarum\Http\UrlGenerator;
use Flarum\Settings\SettingsRepositoryInterface;
use Illuminate\Contracts\View\Factory as ViewFactory;
class FrontendServiceProvider extends AbstractServiceProvider
{
public function register()
{
// Yo dawg, I heard you like factories, so I made you a factory to
// create your factory. We expose a couple of factory functions that
// will create frontend factories and configure them with some default
// settings common to both the forum and admin frontends.
$this->app->singleton('flarum.frontend.assets.defaults', function () {
$this->app->singleton('flarum.assets.factory', function () {
return function (string $name) {
$assets = new CompilerFactory(
$assets = new Assets(
$name,
$this->app->make('filesystem')->disk('flarum-assets'),
$this->app->storagePath()
@@ -36,35 +33,26 @@ class FrontendServiceProvider extends AbstractServiceProvider
$this->app->basePath().'/vendor/components/font-awesome/less' => ''
]);
$assets->add(function () use ($name) {
$translations = $this->app->make(Asset\Translations::class);
$translations->setFilter(function (string $id) use ($name) {
return preg_match('/^.+(?:\.|::)(?:'.$name.'|lib)\./', $id);
});
return [
new Asset\CoreAssets($name),
$this->app->make(Asset\LessVariables::class),
$translations,
$this->app->make(Asset\LocaleAssets::class)
];
});
$assets->css([$this, 'addLessVariables']);
$assets->localeCss([$this, 'addLessVariables']);
return $assets;
};
});
$this->app->singleton('flarum.frontend.view.defaults', function () {
$this->app->singleton('flarum.frontend.factory', function () {
return function (string $name) {
$view = $this->app->make(HtmlDocumentFactory::class);
$frontend = $this->app->make(Frontend::class);
$view->setCommitAssets($this->app->inDebugMode());
$frontend->content(function (Document $document) use ($name) {
$document->layoutView = 'flarum::frontend.'.$name;
});
$view->add(new Content\Layout('flarum::frontend.'.$name));
$view->add($this->app->make(Content\CorePayload::class));
$view->add($this->app->make(Content\Meta::class));
$frontend->content($this->app->make(Content\Assets::class)->forFrontend($name));
$frontend->content($this->app->make(Content\CorePayload::class));
$frontend->content($this->app->make(Content\Meta::class));
return $view;
return $frontend;
};
});
}
@@ -81,4 +69,22 @@ class FrontendServiceProvider extends AbstractServiceProvider
'url' => $this->app->make(UrlGenerator::class)
]);
}
public function addLessVariables(SourceCollector $sources)
{
$sources->addString(function () {
$settings = $this->app->make(SettingsRepositoryInterface::class);
$vars = [
'config-primary-color' => $settings->get('theme_primary_color', '#000'),
'config-secondary-color' => $settings->get('theme_secondary_color', '#000'),
'config-dark-mode' => $settings->get('theme_dark_mode') ? 'true' : 'false',
'config-colored-header' => $settings->get('theme_colored_header') ? 'true' : 'false'
];
return array_reduce(array_keys($vars), function ($string, $name) use ($vars) {
return $string."@$name: {$vars[$name]};";
}, '');
});
}
}

View File

@@ -1,182 +0,0 @@
<?php
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <toby.zerner@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flarum\Frontend;
use Flarum\Api\Client;
use Flarum\Api\Controller\ShowForumController;
use Flarum\Frontend\Compiler\CompilerInterface;
use Flarum\Frontend\Content\ContentInterface;
use Illuminate\Contracts\View\Factory;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
class HtmlDocumentFactory
{
/**
* @var Factory
*/
protected $view;
/**
* @var Client
*/
protected $api;
/**
* @var CompilerFactory
*/
protected $assets;
/**
* @var bool
*/
protected $commitAssets;
/**
* @var ContentInterface[]
*/
protected $content = [];
/**
* @param Factory $view
* @param Client $api
* @param CompilerFactory|null $assets
* @param bool $commitAssets
*/
public function __construct(Factory $view, Client $api, CompilerFactory $assets = null, bool $commitAssets = false)
{
$this->view = $view;
$this->api = $api;
$this->assets = $assets;
$this->commitAssets = $commitAssets;
}
/**
* @param ContentInterface|callable $content
*/
public function add($content)
{
$this->content[] = $content;
}
/**
* @param Request $request
* @return HtmlDocument
*/
public function make(Request $request): HtmlDocument
{
$forumDocument = $this->getForumDocument($request);
$view = new HtmlDocument($this->view, $forumDocument);
$locale = $request->getAttribute('locale');
$js = [$this->assets->makeJs(), $this->assets->makeLocaleJs($locale)];
$css = [$this->assets->makeCss(), $this->assets->makeLocaleCss($locale)];
$this->maybeCommitAssets(array_merge($js, $css));
$view->js = array_merge($view->js, $this->getUrls($js));
$view->css = array_merge($view->css, $this->getUrls($css));
$this->populate($view, $request);
return $view;
}
/**
* @return CompilerFactory
*/
public function getAssets(): CompilerFactory
{
return $this->assets;
}
/**
* @param CompilerFactory $assets
*/
public function setAssets(CompilerFactory $assets)
{
$this->assets = $assets;
}
/**
* @param HtmlDocument $view
* @param Request $request
*/
protected function populate(HtmlDocument $view, Request $request)
{
foreach ($this->content as $content) {
$content($view, $request);
}
}
/**
* @param Request $request
* @return array
*/
private function getForumDocument(Request $request): array
{
$actor = $request->getAttribute('actor');
$this->api->setErrorHandler(null);
return $this->getResponseBody(
$this->api->send(ShowForumController::class, $actor)
);
}
/**
* @param Response $response
* @return array
*/
private function getResponseBody(Response $response)
{
return json_decode($response->getBody(), true);
}
private function maybeCommitAssets(array $compilers)
{
if ($this->commitAssets) {
foreach ($compilers as $compiler) {
$compiler->commit();
}
}
}
/**
* @param CompilerInterface[] $compilers
* @return string[]
*/
private function getUrls(array $compilers)
{
return array_filter(array_map(function (CompilerInterface $compiler) {
return $compiler->getUrl();
}, $compilers));
}
/**
* @return bool
*/
public function getCommitAssets(): bool
{
return $this->commitAssets;
}
/**
* @param bool $commitAssets
*/
public function setCommitAssets(bool $commitAssets)
{
$this->commitAssets = $commitAssets;
}
}

View File

@@ -21,7 +21,7 @@ use Illuminate\Contracts\Events\Dispatcher;
class RecompileFrontendAssets
{
/**
* @var CompilerFactory
* @var Assets
*/
protected $assets;
@@ -31,10 +31,10 @@ class RecompileFrontendAssets
protected $locales;
/**
* @param CompilerFactory $assets
* @param Assets $assets
* @param LocaleManager $locales
*/
public function __construct(CompilerFactory $assets, LocaleManager $locales)
public function __construct(Assets $assets, LocaleManager $locales)
{
$this->assets = $assets;
$this->locales = $locales;