diff --git a/framework/core/src/Core/Users/User.php b/framework/core/src/Core/Users/User.php index fa45ff66a..7ced9ff8e 100755 --- a/framework/core/src/Core/Users/User.php +++ b/framework/core/src/Core/Users/User.php @@ -1,5 +1,6 @@ avatar_path ? app('Flarum\Http\UrlGeneratorInterface')->toAsset('assets/avatars/'.$this->avatar_path) : null; + $urlGenerator = app('Flarum\Http\UrlGeneratorInterface'); + + return $this->avatar_path ? $urlGenerator->toAsset('assets/avatars/'.$this->avatar_path) : null; + } + + /** + * Get the user's locale, falling back to the forum's default if they + * haven't set one. + * + * @param string $value + * @return string + */ + public function getLocaleAttribute($value) + { + return $value ?: Core::config('locale', 'en'); } /** diff --git a/framework/core/src/Forum/Actions/ClientAction.php b/framework/core/src/Forum/Actions/ClientAction.php index 06b3445d2..623e29169 100644 --- a/framework/core/src/Forum/Actions/ClientAction.php +++ b/framework/core/src/Forum/Actions/ClientAction.php @@ -1,134 +1,16 @@ apiClient = $apiClient; - $this->locales = $locales; - } - - /** - * @param Request $request - * @param array $routeParams - * @return \Flarum\Support\ClientView - */ - public function render(Request $request, array $routeParams = []) - { - $actor = app('flarum.actor'); - - $assets = $this->getAssets(); - $locale = $this->getLocaleCompiler($actor); - - $layout = 'flarum.forum::forum'; - - $view = new ClientView( - $request, - $actor, - $this->apiClient, - $layout, - $assets, - $locale - ); - - return $view; - } - - protected function getAssets() - { - $public = $this->getAssetDirectory(); - - $assets = new AssetManager( - new JsCompiler($public, 'forum.js'), - new LessCompiler($public, 'forum.css') - ); - - $root = __DIR__.'/../../..'; - $assets->addFile($root.'/js/forum/dist/app.js'); - $assets->addFile($root.'/less/forum/app.less'); - - foreach ($this->getLessVariables() as $name => $value) { - $assets->addLess("@$name: $value;"); - } - - $assets->addLess(Core::config('custom_less')); - - return $assets; - } - - protected function getLessVariables() - { - return [ - 'fl-primary-color' => Core::config('theme_primary_color', '#000'), - 'fl-secondary-color' => Core::config('theme_secondary_color', '#000'), - 'fl-dark-mode' => Core::config('theme_dark_mode') ? 'true' : 'false', - 'fl-colored-header' => Core::config('theme_colored_header') ? 'true' : 'false' - ]; - } - - protected function getLocaleCompiler(User $actor) - { - $locale = $actor->locale ?: Core::config('locale', 'en'); - -// $translations = $this->locales->getTranslations($locale); - $jsFiles = $this->locales->getJsFiles($locale); - - $compiler = new LocaleJsCompiler($this->getAssetDirectory(), 'locale-'.$locale.'.js'); -// $compiler->setTranslations(static::filterTranslations($translations)); - array_walk($jsFiles, [$compiler, 'addFile']); - - return $compiler; - } - - protected function getAssetDirectory() - { - return public_path().'/assets'; - } - - /** - * @param $translations - * @return array - */ -// protected static function filterTranslations($translations) -// { -// $filtered = []; -// -// foreach (static::$translations as $key) { -// $parts = explode('.', $key); -// $level = &$filtered; -// -// foreach ($parts as $part) { -// $level = &$level[$part]; -// } -// -// $level = array_get($translations, $key); -// } -// -// return $filtered; -// } + protected $layout = 'flarum.forum::forum'; } diff --git a/framework/core/src/Forum/Actions/DiscussionAction.php b/framework/core/src/Forum/Actions/DiscussionAction.php index 9a0d0e925..fff5a3b3b 100644 --- a/framework/core/src/Forum/Actions/DiscussionAction.php +++ b/framework/core/src/Forum/Actions/DiscussionAction.php @@ -4,18 +4,21 @@ use Psr\Http\Message\ServerRequestInterface as Request; class DiscussionAction extends ClientAction { + /** + * {@inheritdoc} + */ public function render(Request $request, array $routeParams = []) { $view = parent::render($request, $routeParams); - $actor = app('flarum.actor'); - $action = 'Flarum\Api\Actions\Discussions\ShowAction'; $params = [ - 'id' => $routeParams['id'], - 'page.near' => $routeParams['near'] + 'id' => array_get($routeParams, 'id'), + 'page.near' => array_get($routeParams, 'near') ]; - $document = $this->apiClient->send($actor, $action, $params)->getBody(); + // FIXME: make sure this is extensible. 404s, pagination. + + $document = $this->preload($params); $view->setTitle($document->data->attributes->title); $view->setDocument($document); @@ -23,4 +26,18 @@ class DiscussionAction extends ClientAction return $view; } + + /** + * Get the result of an API request to show a discussion. + * + * @param array $params + * @return object + */ + protected function preload(array $params) + { + $actor = app('flarum.actor'); + $action = 'Flarum\Api\Actions\Discussions\ShowAction'; + + return $this->apiClient->send($actor, $action, $params)->getBody(); + } } diff --git a/framework/core/src/Forum/Actions/IndexAction.php b/framework/core/src/Forum/Actions/IndexAction.php index 2195ec8ae..6e038ab4b 100644 --- a/framework/core/src/Forum/Actions/IndexAction.php +++ b/framework/core/src/Forum/Actions/IndexAction.php @@ -1,22 +1,23 @@ '-lastTime', + 'replies' => '-commentsCount', + 'newest' => '-startTime', + 'oldest' => '+startTime' + ]; + + /** + * {@inheritdoc} */ public function render(Request $request, array $routeParams = []) { @@ -24,18 +25,35 @@ class IndexAction extends ClientAction $queryParams = $request->getQueryParams(); - // Only preload data if we're viewing the default index with no filters, - // otherwise we have to do all kinds of crazy stuff - if (! count($queryParams) && $request->getUri()->getPath() === '/') { - $actor = app('flarum.actor'); - $action = 'Flarum\Api\Actions\Discussions\IndexAction'; + $sort = array_pull($queryParams, 'sort'); + $q = array_pull($queryParams, 'q'); - $document = $this->apiClient->send($actor, $action)->getBody(); + $params = [ + 'sort' => $sort ? $this->sortMap[$sort] : '', + 'q' => $q + ]; - $view->setDocument($document); - $view->setContent(app('view')->make('flarum.forum::index', compact('document'))); - } + // FIXME: make sure this is extensible. Support pagination. + + $document = $this->preload($params); + + $view->setDocument($document); + $view->setContent(app('view')->make('flarum.forum::index', compact('document'))); return $view; } + + /** + * Get the result of an API request to list discussions. + * + * @param array $params + * @return object + */ + protected function preload(array $params) + { + $actor = app('flarum.actor'); + $action = 'Flarum\Api\Actions\Discussions\IndexAction'; + + return $this->apiClient->send($actor, $action, $params)->getBody(); + } } diff --git a/framework/core/src/Locale/LocaleServiceProvider.php b/framework/core/src/Locale/LocaleServiceProvider.php index 4f0b5801d..ac339dca8 100644 --- a/framework/core/src/Locale/LocaleServiceProvider.php +++ b/framework/core/src/Locale/LocaleServiceProvider.php @@ -29,6 +29,8 @@ class LocaleServiceProvider extends ServiceProvider public function register() { - $this->app->singleton('flarum.localeManager', 'Flarum\Locale\LocaleManager'); + $this->app->singleton('Flarum\Locale\LocaleManager'); + + $this->app->alias('Flarum\Locale\LocaleManager', 'flarum.localeManager'); } } diff --git a/framework/core/src/Support/ClientAction.php b/framework/core/src/Support/ClientAction.php new file mode 100644 index 000000000..d75c1e744 --- /dev/null +++ b/framework/core/src/Support/ClientAction.php @@ -0,0 +1,231 @@ +apiClient = $apiClient; + $this->locales = $locales; + } + + /** + * {@inheritdoc} + * + * @return ClientView + */ + public function render(Request $request, array $routeParams = []) + { + $actor = app('flarum.actor'); + $assets = $this->getAssets(); + $locale = $this->getLocaleCompiler($actor); + + $view = new ClientView( + $this->apiClient, + $request, + $actor, + $assets, + $locale, + $this->layout + ); + + // Now that we've set up the ClientView instance, we can fire an event + // to give extensions the opportunity to add their own assets and + // translations. We will pass an array to the event which specifies + // which translations should be included in the locale file. Afterwards, + // we will filter all of the translations for the actor's locale and + // compile only the ones we need. + $translations = $this->locales->getTranslations($actor->locale); + $keys = $this->translationKeys; + + // TODO: event($this, $view, $keys) + + $translations = $this->filterTranslations($translations, $keys); + + $locale->setTranslations($translations); + + return $view; + } + + /** + * Set up the asset manager, preloaded with a JavaScript compiler and a LESS + * compiler. Automatically add the files necessary to boot a Flarum client, + * as well as any configured LESS customizations. + * + * @return AssetManager + */ + protected function getAssets() + { + $public = $this->getAssetDirectory(); + + $assets = new AssetManager( + new JsCompiler($public, "$this->clientName.js"), + new LessCompiler($public, "$this->clientName.css") + ); + + $this->addAssets($assets); + $this->addCustomizations($assets); + + return $assets; + } + + /** + * Add the assets necessary to boot a Flarum client, found within the + * directory specified by the $clientName property. + * + * @param AssetManager $assets + */ + protected function addAssets(AssetManager $assets) + { + $root = __DIR__.'/../..'; + + $assets->addFile("$root/js/$this->clientName/dist/app.js"); + $assets->addFile("$root/less/$this->clientName/app.less"); + } + + /** + * Add any configured JS/LESS customizations to the asset manager. + * + * @param AssetManager $assets + */ + protected function addCustomizations(AssetManager $assets) + { + foreach ($this->getLessVariables() as $name => $value) { + $assets->addLess("@$name: $value;"); + } + + $assets->addLess(Core::config('custom_less')); + } + + /** + * Get the values of any LESS variables to compile into the CSS, based on + * the forum's configuration. + * + * @return array + */ + protected function getLessVariables() + { + return [ + 'fl-primary-color' => Core::config('theme_primary_color', '#000'), + 'fl-secondary-color' => Core::config('theme_secondary_color', '#000'), + 'fl-dark-mode' => Core::config('theme_dark_mode') ? 'true' : 'false', + 'fl-colored-header' => Core::config('theme_colored_header') ? 'true' : 'false' + ]; + } + + /** + * Set up the locale compiler for the given user's locale. + * + * @param User $actor + * @return LocaleJsCompiler + */ + protected function getLocaleCompiler(User $actor) + { + $locale = $actor->locale; + + $compiler = new LocaleJsCompiler($this->getAssetDirectory(), "$this->clientName-$locale.js"); + + foreach ($this->locales->getJsFiles($locale) as $file) { + $compiler->addFile($file); + } + + return $compiler; + } + + /** + * Get the path to the directory where assets should be written. + * + * @return string + */ + protected function getAssetDirectory() + { + return public_path().'/assets'; + } + + /** + * Take a selection of keys from a collection of translations. + * + * @param array $translations + * @param array $keys + * @return array + */ + protected function filterTranslations(array $translations, array $keys) + { + $filtered = []; + + foreach ($keys as $key) { + $parts = explode('.', $key); + $level = &$filtered; + + foreach ($parts as $part) { + $level = &$level[$part]; + } + + $level = array_get($translations, $key); + } + + return $filtered; + } +} diff --git a/framework/core/src/Support/ClientView.php b/framework/core/src/Support/ClientView.php index 1b5832211..c36388c64 100644 --- a/framework/core/src/Support/ClientView.php +++ b/framework/core/src/Support/ClientView.php @@ -3,61 +3,174 @@ use Flarum\Api\Client; use Flarum\Assets\AssetManager; use Flarum\Core\Users\User; +use Illuminate\Contracts\Support\Renderable; use Psr\Http\Message\ServerRequestInterface as Request; use Flarum\Locale\JsCompiler; -class ClientView +/** + * This class represents a view which boots up Flarum's client. + */ +class ClientView implements Renderable { + /** + * The user who is using the client. + * + * @var User + */ protected $actor; - protected $apiClient; - + /** + * The title of the document, displayed in the