Locate this file: vendor\flarum\core\js\src\forum\components\DiscussionComposer.js
Update it to below
goto cd vendor/flarum/core/js
do npm install
npm run build
go to the root of your flarum and do php flarum cache:clear
| import app from '../../forum/app'; | |
| import ComposerBody from './ComposerBody'; | |
| import extractText from '../../common/utils/extractText'; | |
| import Stream from '../../common/utils/Stream'; | |
| function minimizeComposerIfFullScreen(e) { | |
| if (app.composer.isFullScreen()) { | |
| app.composer.minimize(); | |
| e.stopPropagation(); | |
| } | |
| } | |
| /** | |
| * The `DiscussionComposer` component displays the composer content for starting | |
| * a new discussion. It adds a text field as a header control so the user can | |
| * enter the title of their discussion. It also overrides the `submit` and | |
| * `willExit` actions to account for the title. | |
| * | |
| * ### Attrs | |
| * | |
| * - All of the attrs for ComposerBody | |
| * - `titlePlaceholder` | |
| */ | |
| export default class DiscussionComposer extends ComposerBody { | |
| static initAttrs(attrs) { | |
| super.initAttrs(attrs); | |
| attrs.placeholder = attrs.placeholder || extractText(app.translator.trans('core.forum.composer_discussion.body_placeholder')); | |
| attrs.submitLabel = attrs.submitLabel || app.translator.trans('core.forum.composer_discussion.submit_button'); | |
| attrs.confirmExit = attrs.confirmExit || extractText(app.translator.trans('core.forum.composer_discussion.discard_confirmation')); | |
| attrs.titlePlaceholder = attrs.titlePlaceholder || extractText(app.translator.trans('core.forum.composer_discussion.title_placeholder')); | |
| attrs.className = 'ComposerBody--discussion'; | |
| } | |
| oninit(vnode) { | |
| super.oninit(vnode); | |
| this.initialized = false; | |
| this.previewing = false; | |
| this.timer = null; | |
| this.composer.fields.title = this.composer.fields.title || Stream(''); | |
| /** | |
| * The value of the title input. | |
| * | |
| * @type {Function} | |
| */ | |
| this.title = this.composer.fields.title; | |
| } | |
| headerItems() { | |
| const items = super.headerItems(); | |
| items.add('title', <h3>{app.translator.trans('core.forum.composer_discussion.title')}</h3>, 100); | |
| items.add( | |
| 'discussionTitle', | |
| <h3> | |
| <input | |
| className="FormControl" | |
| bidi={this.title} | |
| placeholder={this.attrs.titlePlaceholder} | |
| disabled={!!this.attrs.disabled} | |
| onkeydown={this.onkeydown.bind(this)} | |
| /> | |
| </h3> | |
| ); | |
| return items; | |
| } | |
| /** | |
| * Jump to the preview when triggered by the text editor. | |
| */ | |
| jumpToPreview(e) { | |
| const snippetId = '#preview-discussion'; | |
| const snippet = ` | |
| <li id="preview-discussion" role="article" aria-setsize="-1" aria-posinset="19"> | |
| <div class="DiscussionListItem DiscussionListItem--sticky"> | |
| <div class="DiscussionListItem-content Slidable-content read"> | |
| <a href="/d/69-what-programming-language-to-learn-in-2024/8" class="DiscussionListItem-main"> | |
| <h2 class="DiscussionListItem-title" id="preview-snippet-title"></h2> | |
| <ul class="DiscussionListItem-info"> | |
| <li class="item-excerptM" id="preview-snippet-body"> | |
| </li> | |
| </ul> | |
| </a> | |
| </div> | |
| </div> | |
| </li>`; | |
| if ($(snippetId).length === 0) { | |
| $(".DiscussionList-discussions").append(snippet); | |
| } | |
| $('html, body').animate({ | |
| scrollTop: $('#preview-discussion').offset().top | |
| }, 1000); | |
| const mdTitle = $(".ComposerBody-content input.FormControl").val(); | |
| const mdText = $("textarea.TextEditor-editor").val(); | |
| s9e.TextFormatter.preview(mdText, $('#preview-snippet-body')[0]); | |
| $('#preview-snippet-title').html(mdTitle); | |
| } | |
| /** | |
| * Handle the title input's keydown event. When the return key is pressed, | |
| * move the focus to the start of the text editor. | |
| * | |
| * @param {KeyboardEvent} e | |
| */ | |
| onkeydown(e) { | |
| if (e.which === 13) { | |
| // Return | |
| e.preventDefault(); | |
| this.composer.editor.moveCursorTo(0); | |
| } | |
| e.redraw = false; | |
| } | |
| hasChanges() { | |
| return this.title() || this.composer.fields.content(); | |
| } | |
| /** | |
| * Get the data to submit to the server when the discussion is saved. | |
| * | |
| * @return {Record<string, unknown>} | |
| */ | |
| data() { | |
| return { | |
| title: this.title(), | |
| content: this.composer.fields.content(), | |
| }; | |
| } | |
| onsubmit() { | |
| this.loading = true; | |
| const data = this.data(); | |
| app.store | |
| .createRecord('discussions') | |
| .save(data) | |
| .then((discussion) => { | |
| this.composer.hide(); | |
| app.discussions.refresh(); | |
| m.route.set(app.route.discussion(discussion)); | |
| }, this.loaded.bind(this)); | |
| } | |
| } |