diff --git a/js/admin/dist/app.js b/js/admin/dist/app.js index 71e6886939..f1e6d0db19 100644 --- a/js/admin/dist/app.js +++ b/js/admin/dist/app.js @@ -16913,10 +16913,10 @@ System.register('flarum/app', ['flarum/App', 'flarum/initializers/store', 'flaru });; 'use strict'; -System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert', 'flarum/components/Button', 'flarum/components/RequestErrorModal', 'flarum/components/ConfirmPasswordModal', 'flarum/Translator', 'flarum/utils/extract', 'flarum/utils/patchMithril', 'flarum/utils/RequestError', 'flarum/extend'], function (_export, _context) { +System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert', 'flarum/components/Button', 'flarum/components/RequestErrorModal', 'flarum/components/ConfirmPasswordModal', 'flarum/Translator', 'flarum/utils/extract', 'flarum/utils/patchMithril', 'flarum/utils/RequestError', 'flarum/extend', 'flarum/utils/string'], function (_export, _context) { "use strict"; - var ItemList, Alert, Button, RequestErrorModal, ConfirmPasswordModal, Translator, extract, patchMithril, RequestError, extend, App; + var ItemList, Alert, Button, RequestErrorModal, ConfirmPasswordModal, Translator, extract, patchMithril, RequestError, extend, getPlainContent, truncate, App; return { setters: [function (_flarumUtilsItemList) { ItemList = _flarumUtilsItemList.default; @@ -16938,6 +16938,9 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert RequestError = _flarumUtilsRequestError.default; }, function (_flarumExtend) { extend = _flarumExtend.extend; + }, function (_flarumUtilsString) { + getPlainContent = _flarumUtilsString.getPlainContent; + truncate = _flarumUtilsString.truncate; }], execute: function () { App = function () { @@ -17029,6 +17032,8 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert this.title = ''; this.titleCount = 0; + + this.description = ''; } /** @@ -17080,6 +17085,18 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert value: function updateTitle() { document.title = (this.titleCount ? '(' + this.titleCount + ') ' : '') + (this.title ? this.title + ' - ' : '') + this.forum.attribute('title'); } + }, { + key: 'setDescription', + value: function setDescription(description) { + description = truncate(getPlainContent(description), 300, 0); + this.description = description; + this.updateDescription(); + } + }, { + key: 'updateDescription', + value: function updateDescription() { + document.head.querySelector('meta[name=description]').content = this.description ? this.description : this.forum.attribute('description'); + } }, { key: 'request', value: function request(originalOptions) { @@ -22375,6 +22392,7 @@ System.register('flarum/models/Discussion', ['flarum/Model', 'flarum/utils/compu babelHelpers.extends(Discussion.prototype, { title: Model.attribute('title'), slug: Model.attribute('slug'), + description: Model.attribute('description'), startTime: Model.attribute('startTime', Model.transformDate), startUser: Model.hasOne('startUser'), diff --git a/js/forum/dist/app.js b/js/forum/dist/app.js index 274ead6bf3..a1dc082aff 100644 --- a/js/forum/dist/app.js +++ b/js/forum/dist/app.js @@ -18246,10 +18246,10 @@ System.register('flarum/app', ['flarum/ForumApp', 'flarum/initializers/store', ' });; 'use strict'; -System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert', 'flarum/components/Button', 'flarum/components/RequestErrorModal', 'flarum/components/ConfirmPasswordModal', 'flarum/Translator', 'flarum/utils/extract', 'flarum/utils/patchMithril', 'flarum/utils/RequestError', 'flarum/extend'], function (_export, _context) { +System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert', 'flarum/components/Button', 'flarum/components/RequestErrorModal', 'flarum/components/ConfirmPasswordModal', 'flarum/Translator', 'flarum/utils/extract', 'flarum/utils/patchMithril', 'flarum/utils/RequestError', 'flarum/extend', 'flarum/utils/string'], function (_export, _context) { "use strict"; - var ItemList, Alert, Button, RequestErrorModal, ConfirmPasswordModal, Translator, extract, patchMithril, RequestError, extend, App; + var ItemList, Alert, Button, RequestErrorModal, ConfirmPasswordModal, Translator, extract, patchMithril, RequestError, extend, getPlainContent, truncate, App; return { setters: [function (_flarumUtilsItemList) { ItemList = _flarumUtilsItemList.default; @@ -18271,6 +18271,9 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert RequestError = _flarumUtilsRequestError.default; }, function (_flarumExtend) { extend = _flarumExtend.extend; + }, function (_flarumUtilsString) { + getPlainContent = _flarumUtilsString.getPlainContent; + truncate = _flarumUtilsString.truncate; }], execute: function () { App = function () { @@ -18362,6 +18365,8 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert this.title = ''; this.titleCount = 0; + + this.description = ''; } /** @@ -18413,6 +18418,18 @@ System.register('flarum/App', ['flarum/utils/ItemList', 'flarum/components/Alert value: function updateTitle() { document.title = (this.titleCount ? '(' + this.titleCount + ') ' : '') + (this.title ? this.title + ' - ' : '') + this.forum.attribute('title'); } + }, { + key: 'setDescription', + value: function setDescription(description) { + description = truncate(getPlainContent(description), 300, 0); + this.description = description; + this.updateDescription(); + } + }, { + key: 'updateDescription', + value: function updateDescription() { + document.head.querySelector('meta[name=description]').content = this.description ? this.description : this.forum.attribute('description'); + } }, { key: 'request', value: function request(originalOptions) { @@ -21161,6 +21178,9 @@ System.register('flarum/components/DiscussionPage', ['flarum/components/Page', ' app.setTitle(discussion.title()); app.setTitleCount(0); + var description = this.discussion.description() || this.discussion.startPost.content(); + app.setDescription(description); + // When the API responds with a discussion, it will also include a number of // posts. Some of these posts are included because they are on the first // page of posts we want to display (determined by the `near` parameter) – @@ -22649,6 +22669,7 @@ System.register('flarum/components/IndexPage', ['flarum/extend', 'flarum/compone app.setTitle(''); app.setTitleCount(0); + app.setDescription(''); // Work out the difference between the height of this hero and that of the // previous hero. Maintain the same scroll position relative to the bottom @@ -24950,7 +24971,7 @@ System.register('flarum/components/PostStream', ['flarum/Component', 'flarum/uti }, { key: 'update', value: function update() { - if (!this.viewingEnd) return; + if (!this.viewingEnd) return m.deferred().resolve().promise; this.visibleEnd = this.count(); @@ -27164,6 +27185,7 @@ System.register('flarum/components/SettingsPage', ['flarum/components/UserPage', this.show(app.session.user); app.setTitle(app.translator.trans('core.forum.settings.title')); + app.setDescription(''); } }, { key: 'content', @@ -27997,6 +28019,7 @@ System.register('flarum/components/UserPage', ['flarum/components/Page', 'flarum this.user = user; app.setTitle(user.displayName()); + app.setDescription(''); m.redraw(); } @@ -29427,6 +29450,7 @@ System.register('flarum/models/Discussion', ['flarum/Model', 'flarum/utils/compu babelHelpers.extends(Discussion.prototype, { title: Model.attribute('title'), slug: Model.attribute('slug'), + description: Model.attribute('description'), startTime: Model.attribute('startTime', Model.transformDate), startUser: Model.hasOne('startUser'), diff --git a/js/forum/src/components/DiscussionPage.js b/js/forum/src/components/DiscussionPage.js index fdb71dbce2..900b63c232 100644 --- a/js/forum/src/components/DiscussionPage.js +++ b/js/forum/src/components/DiscussionPage.js @@ -163,6 +163,9 @@ export default class DiscussionPage extends Page { app.setTitle(discussion.title()); app.setTitleCount(0); + let description = this.discussion.description() || this.discussion.startPost.content(); + app.setDescription(description); + // When the API responds with a discussion, it will also include a number of // posts. Some of these posts are included because they are on the first // page of posts we want to display (determined by the `near` parameter) – diff --git a/js/forum/src/components/IndexPage.js b/js/forum/src/components/IndexPage.js index 51dd89dd09..2e24f071cf 100644 --- a/js/forum/src/components/IndexPage.js +++ b/js/forum/src/components/IndexPage.js @@ -95,6 +95,7 @@ export default class IndexPage extends Page { app.setTitle(''); app.setTitleCount(0); + app.setDescription(''); // Work out the difference between the height of this hero and that of the // previous hero. Maintain the same scroll position relative to the bottom diff --git a/js/forum/src/components/SettingsPage.js b/js/forum/src/components/SettingsPage.js index 45cf881b0d..4a66411b35 100644 --- a/js/forum/src/components/SettingsPage.js +++ b/js/forum/src/components/SettingsPage.js @@ -18,6 +18,7 @@ export default class SettingsPage extends UserPage { this.show(app.session.user); app.setTitle(app.translator.trans('core.forum.settings.title')); + app.setDescription(''); } content() { diff --git a/js/forum/src/components/UserPage.js b/js/forum/src/components/UserPage.js index 298c241c41..3af1058f45 100644 --- a/js/forum/src/components/UserPage.js +++ b/js/forum/src/components/UserPage.js @@ -73,6 +73,7 @@ export default class UserPage extends Page { this.user = user; app.setTitle(user.displayName()); + app.setDescription(''); m.redraw(); } diff --git a/js/lib/App.js b/js/lib/App.js index aae82c4163..b081ecba99 100644 --- a/js/lib/App.js +++ b/js/lib/App.js @@ -8,6 +8,7 @@ import extract from 'flarum/utils/extract'; import patchMithril from 'flarum/utils/patchMithril'; import RequestError from 'flarum/utils/RequestError'; import { extend } from 'flarum/extend'; +import { getPlainContent, truncate } from 'flarum/utils/string'; /** * The `App` class provides a container for an application, as well as various @@ -100,6 +101,8 @@ export default class App { this.title = ''; this.titleCount = 0; + + this.description = ''; } /** @@ -159,6 +162,23 @@ export default class App { this.forum.attribute('title'); } + /** + * Set the of the page. + * + * @param {String} description + * @public + */ + setDescription(description) { + description = truncate(getPlainContent(description), 300, 0); + this.description = description; + this.updateDescription(); + } + + updateDescription() { + document.head.querySelector('meta[name=description]').content = + (this.description ? this.description : this.forum.attribute('description')); + } + /** * Make an AJAX request, handling any low-level errors that may occur. * diff --git a/js/lib/models/Discussion.js b/js/lib/models/Discussion.js index cbc428cca0..f7a8c4c1ad 100644 --- a/js/lib/models/Discussion.js +++ b/js/lib/models/Discussion.js @@ -8,6 +8,7 @@ export default class Discussion extends Model {} Object.assign(Discussion.prototype, { title: Model.attribute('title'), slug: Model.attribute('slug'), + description: Model.attribute('description'), startTime: Model.attribute('startTime', Model.transformDate), startUser: Model.hasOne('startUser'), diff --git a/migrations/2016_02_04_095452_add_slug_to_discussions.php b/migrations/2016_02_04_095452_add_slug_to_discussions.php index 54ec4e31c1..704c7f0a4d 100644 --- a/migrations/2016_02_04_095452_add_slug_to_discussions.php +++ b/migrations/2016_02_04_095452_add_slug_to_discussions.php @@ -9,9 +9,11 @@ * file that was distributed with this source code. */ -use Flarum\Util\Str; +use Flarum\Foundation\Application; +use Flarum\Settings\SettingsRepositoryInterface; use Illuminate\Database\Schema\Blueprint; use Illuminate\Database\Schema\Builder; +use Illuminate\Support\Str; return [ 'up' => function (Builder $schema) { @@ -19,11 +21,15 @@ $table->string('slug'); }); + $app = Application::getInstance(); + $settings = $app->make(SettingsRepositoryInterface::class); + $locale = $settings->get('default_locale') ?? 'en'; + // Store slugs for existing discussions - $schema->getConnection()->table('discussions')->chunkById(100, function ($discussions) use ($schema) { + $schema->getConnection()->table('discussions')->chunkById(100, function ($discussions) use ($schema, $locale) { foreach ($discussions as $discussion) { $schema->getConnection()->table('discussions')->where('id', $discussion->id)->update([ - 'slug' => Str::slug($discussion->title) + 'slug' => Str::slug($discussion->title, '-', $locale) ]); } }); diff --git a/migrations/2018_03_18_194500_add_description_to_discussions.php b/migrations/2018_03_18_194500_add_description_to_discussions.php new file mode 100644 index 0000000000..eb821e468a --- /dev/null +++ b/migrations/2018_03_18_194500_add_description_to_discussions.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Illuminate\Database\Schema\Blueprint; +use Illuminate\Database\Schema\Builder; + +return [ + 'up' => function (Builder $schema) { + $schema->table('discussions', function (Blueprint $table) { + $table->string('description')->after('title'); + }); + }, + + 'down' => function (Builder $schema) { + $schema->table('discussions', function (Blueprint $table) { + $table->dropColumn('description'); + }); + } +]; diff --git a/src/Api/Serializer/BasicDiscussionSerializer.php b/src/Api/Serializer/BasicDiscussionSerializer.php index 026082a23a..60c0b995b6 100644 --- a/src/Api/Serializer/BasicDiscussionSerializer.php +++ b/src/Api/Serializer/BasicDiscussionSerializer.php @@ -37,7 +37,8 @@ protected function getDefaultAttributes($discussion) return [ 'title' => $discussion->title, - 'slug' => $discussion->slug, + 'description' => $discussion->description, + 'slug' => $discussion->slug ]; } diff --git a/src/Discussion/Discussion.php b/src/Discussion/Discussion.php index 116f1484ce..db7d153473 100644 --- a/src/Discussion/Discussion.php +++ b/src/Discussion/Discussion.php @@ -19,17 +19,20 @@ use Flarum\Discussion\Event\Restored; use Flarum\Discussion\Event\Started; use Flarum\Event\GetModelIsPrivate; +use Flarum\Foundation\Application; use Flarum\Foundation\EventGeneratorTrait; use Flarum\Post\Event\Deleted as PostDeleted; use Flarum\Post\MergeableInterface; use Flarum\Post\Post; +use Flarum\Settings\SettingsRepositoryInterface; use Flarum\User\User; -use Flarum\Util\Str; +use Illuminate\Support\Str; /** * @property int $id * @property string $title * @property string $slug + * @property string $description * @property int $comments_count * @property int $participants_count * @property int $number_index @@ -461,6 +464,24 @@ public static function setStateUser(User $user) protected function setTitleAttribute($title) { $this->attributes['title'] = $title; - $this->slug = Str::slug($title); + $app = Application::getInstance(); + $settings = $app->make(SettingsRepositoryInterface::class); + $locale = $settings->get('default_locale') ?? 'en'; + $this->slug = Str::slug($title, '-', $locale); + } + + /** + * Get the description. + * + * Returns the stored description (if any) or generates one based on startPost´s content. + * + * @param string $description + * @return string + */ + protected function getDescriptionAttribute($description) + { + $description = ($description == null) ? $this->startPost->content : $description; + + return $description; } } diff --git a/src/Forum/Controller/DiscussionController.php b/src/Forum/Controller/DiscussionController.php index d39ec77c76..a6864033fc 100644 --- a/src/Forum/Controller/DiscussionController.php +++ b/src/Forum/Controller/DiscussionController.php @@ -86,6 +86,7 @@ protected function getView(Request $request) } $view->title = $document->data->attributes->title; + $view->description = $document->data->attributes->description; $view->document = $document; $view->content = app('view')->make('flarum.forum::frontend.content.discussion', compact('document', 'page', 'getResource', 'posts', 'url')); diff --git a/src/Frontend/FrontendView.php b/src/Frontend/FrontendView.php index 0063384d39..fd8a1aae59 100644 --- a/src/Frontend/FrontendView.php +++ b/src/Frontend/FrontendView.php @@ -17,6 +17,7 @@ use Flarum\Frontend\Asset\CompilerInterface; use Flarum\Frontend\Asset\LocaleJsCompiler; use Flarum\Locale\LocaleManager; +use Illuminate\Support\Str; use Illuminate\View\Factory; use Psr\Http\Message\ServerRequestInterface as Request; use Tobscure\JsonApi\Document; @@ -42,7 +43,7 @@ class FrontendView public $description; /** - * The language of the document, displayed as the value of the attribute `dir` in the tag. + * The language of the document, displayed as the value of the attribute `lang` in the tag. * * @var null|string */ @@ -290,7 +291,7 @@ public function render(Request $request) $view = $this->view->make('flarum.forum::frontend.app'); $view->title = $this->buildTitle(array_get($forum, 'data.attributes.title')); - $view->description = $this->description ?: array_get($forum, 'data.attributes.description'); + $view->description = $this->buildDescription($this->description, $forum); $view->language = $this->language ?: $this->locales->getLocale(); $view->direction = $this->direction ?: 'ltr'; @@ -314,6 +315,13 @@ protected function buildTitle($forumTitle) return ($this->title ? $this->title.' - ' : '').$forumTitle; } + protected function buildDescription($description, $forum) + { + $description = (($description == null) ? array_get($forum, 'data.attributes.description') : $description); + + return strip_tags(Str::limit($description, 300, '...')); + } + protected function buildPayload(Request $request, $forum) { $data = $this->getDataFromDocument($forum); diff --git a/src/Util/Str.php b/src/Util/Str.php deleted file mode 100644 index f8c7d6a676..0000000000 --- a/src/Util/Str.php +++ /dev/null @@ -1,33 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Flarum\Util; - -class Str -{ - /** - * Create a slug out of the given string. - * - * Non-alphanumeric characters are converted to hyphens. - * - * @param string $str - * @return string - */ - public static function slug($str) - { - $str = strtolower($str); - $str = preg_replace('/[^a-z0-9]/i', '-', $str); - $str = preg_replace('/-+/', '-', $str); - $str = preg_replace('/-$|^-/', '', $str); - - return $str; - } -}