]> BookStack Code Mirror - bookstack/commitdiff
Comments: Added input wysiwyg for creating/updating comments
authorDan Brown <redacted>
Tue, 30 Jan 2024 14:27:09 +0000 (14:27 +0000)
committerDan Brown <redacted>
Tue, 30 Jan 2024 14:27:09 +0000 (14:27 +0000)
Not supporting old content, existing HTML or updating yet.

app/Activity/Tools/CommentTree.php
resources/js/components/page-comment.js
resources/js/components/page-comments.js
resources/js/components/wysiwyg-input.js
resources/sass/_tinymce.scss
resources/views/comments/comment.blade.php
resources/views/comments/comments.blade.php
resources/views/layouts/base.blade.php

index 3303add39b891ca69b6ef9694f5d5af102ea9dc7..16f6804ea4244358568c7a5bdc957953c6c93c2d 100644 (file)
@@ -41,6 +41,17 @@ class CommentTree
         return $this->tree;
     }
 
+    public function canUpdateAny(): bool
+    {
+        foreach ($this->comments as $comment) {
+            if (userCan('comment-update', $comment)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
     /**
      * @param Comment[] $comments
      */
index 8284d7f20d8b29dd5d060d5dc4c7485cae35963a..dc6ca82642559b936419f29c0f13a6e856716162 100644 (file)
@@ -1,5 +1,6 @@
 import {Component} from './component';
 import {getLoading, htmlToDom} from '../services/dom';
+import {buildForInput} from "../wysiwyg/config";
 
 export class PageComment extends Component {
 
@@ -11,7 +12,12 @@ export class PageComment extends Component {
         this.deletedText = this.$opts.deletedText;
         this.updatedText = this.$opts.updatedText;
 
-        // Element References
+        // Editor reference and text options
+        this.wysiwygEditor = null;
+        this.wysiwygLanguage = this.$opts.wysiwygLanguage;
+        this.wysiwygTextDirection = this.$opts.wysiwygTextDirection;
+
+        // Element references
         this.container = this.$el;
         this.contentContainer = this.$refs.contentContainer;
         this.form = this.$refs.form;
@@ -50,8 +56,23 @@ export class PageComment extends Component {
 
     startEdit() {
         this.toggleEditMode(true);
-        const lineCount = this.$refs.input.value.split('\n').length;
-        this.$refs.input.style.height = `${(lineCount * 20) + 40}px`;
+
+        if (this.wysiwygEditor) {
+            return;
+        }
+
+        const config = buildForInput({
+            language: this.wysiwygLanguage,
+            containerElement: this.input,
+            darkMode: document.documentElement.classList.contains('dark-mode'),
+            textDirection: this.wysiwygTextDirection,
+            translations: {},
+            translationMap: window.editor_translations,
+        });
+
+        window.tinymce.init(config).then(editors => {
+            this.wysiwygEditor = editors[0];
+        });
     }
 
     async update(event) {
index e2911afc6a0b649a9793cf2a5443c641f8a3c506..ebcc95f07f44467ec89fd85973f437bc6d7fd585 100644 (file)
@@ -1,5 +1,6 @@
 import {Component} from './component';
 import {getLoading, htmlToDom} from '../services/dom';
+import {buildForInput} from "../wysiwyg/config";
 
 export class PageComments extends Component {
 
@@ -21,6 +22,11 @@ export class PageComments extends Component {
         this.hideFormButton = this.$refs.hideFormButton;
         this.removeReplyToButton = this.$refs.removeReplyToButton;
 
+        // WYSIWYG options
+        this.wysiwygLanguage = this.$opts.wysiwygLanguage;
+        this.wysiwygTextDirection = this.$opts.wysiwygTextDirection;
+        this.wysiwygEditor = null;
+
         // Translations
         this.createdText = this.$opts.createdText;
         this.countText = this.$opts.countText;
@@ -96,9 +102,7 @@ export class PageComments extends Component {
         this.formContainer.toggleAttribute('hidden', false);
         this.addButtonContainer.toggleAttribute('hidden', true);
         this.formContainer.scrollIntoView({behavior: 'smooth', block: 'nearest'});
-        setTimeout(() => {
-            this.formInput.focus();
-        }, 100);
+        this.loadEditor();
     }
 
     hideForm() {
@@ -112,6 +116,26 @@ export class PageComments extends Component {
         this.addButtonContainer.toggleAttribute('hidden', false);
     }
 
+    loadEditor() {
+        if (this.wysiwygEditor) {
+            return;
+        }
+
+        const config = buildForInput({
+            language: this.wysiwygLanguage,
+            containerElement: this.formInput,
+            darkMode: document.documentElement.classList.contains('dark-mode'),
+            textDirection: this.wysiwygTextDirection,
+            translations: {},
+            translationMap: window.editor_translations,
+        });
+
+        window.tinymce.init(config).then(editors => {
+            this.wysiwygEditor = editors[0];
+            this.wysiwygEditor.focus();
+        });
+    }
+
     getCommentCount() {
         return this.container.querySelectorAll('[component="page-comment"]').length;
     }
index 88c06a334c6d8178a10290b0b9ee0c428f0082f3..ad964aed2c4656fbca7bd4e6bee57c0e344e127c 100644 (file)
@@ -10,11 +10,8 @@ export class WysiwygInput extends Component {
             language: this.$opts.language,
             containerElement: this.elem,
             darkMode: document.documentElement.classList.contains('dark-mode'),
-            textDirection: this.textDirection,
-            translations: {
-                imageUploadErrorText: this.$opts.imageUploadErrorText,
-                serverUploadLimitText: this.$opts.serverUploadLimitText,
-            },
+            textDirection: this.$opts.textDirection,
+            translations: {},
             translationMap: window.editor_translations,
         });
 
index c4336da7cb7efd02cdd3e96f171b8fe84181aa7f..fb5ea7e6ffe7fcabab90b0bc1f4485119ee2bc60 100644 (file)
   display: block;
 }
 
+.wysiwyg-input.mce-content-body:before {
+  padding: 1rem;
+  top: 4px;
+  font-style: italic;
+  color: rgba(34,47,62,.5)
+}
+
 // Default styles for our custom root nodes
 .page-content.mce-content-body doc-root {
   display: block;
index 1cb70916087cff719c21ee8671f0551b9cd0200a..4340cfdf5c45b8302c7d2277352a1b7aa3afe14c 100644 (file)
@@ -4,6 +4,8 @@
      option:page-comment:comment-parent-id="{{ $comment->parent_id }}"
      option:page-comment:updated-text="{{ trans('entities.comment_updated_success') }}"
      option:page-comment:deleted-text="{{ trans('entities.comment_deleted_success') }}"
+     option:page-comment:wysiwyg-language="{{ $locale->htmlLang() }}"
+     option:page-comment:wysiwyg-text-direction="{{ $locale->htmlDirection() }}"
      id="comment{{$comment->local_id}}"
      class="comment-box">
     <div class="header">
index 26d286290c28964686926cafa78bd55768dd8854..2c314864bc26a2e39164c2c791a8e02e8282a5eb 100644 (file)
@@ -2,6 +2,8 @@
          option:page-comments:page-id="{{ $page->id }}"
          option:page-comments:created-text="{{ trans('entities.comment_created_success') }}"
          option:page-comments:count-text="{{ trans('entities.comment_count') }}"
+         option:page-comments:wysiwyg-language="{{ $locale->htmlLang() }}"
+         option:page-comments:wysiwyg-text-direction="{{ $locale->htmlDirection() }}"
          class="comments-list"
          aria-label="{{ trans('entities.comments') }}">
 
@@ -24,7 +26,6 @@
 
     @if(userCan('comment-create-all'))
         @include('comments.create')
-
         @if (!$commentTree->empty())
             <div refs="page-comments@addButtonContainer" class="text-right">
                 <button type="button"
         @endif
     @endif
 
+    @if(userCan('comment-create-all') || $commentTree->canUpdateAny())
+        @push('post-app-scripts')
+            <script src="{{ versioned_asset('libs/tinymce/tinymce.min.js') }}" nonce="{{ $cspNonce }}"></script>
+            @include('form.editor-translations')
+        @endpush
+    @endif
+
 </section>
\ No newline at end of file
index cf15e5426b832cebec6feadaec380272c68a635a..43cca6b14c5a9350504a1214ab1a7b0a5256ffef 100644 (file)
     </div>
 
     @yield('bottom')
+
+
     @if($cspNonce ?? false)
         <script src="{{ versioned_asset('dist/app.js') }}" nonce="{{ $cspNonce }}"></script>
     @endif
     @yield('scripts')
+    @stack('post-app-scripts')
 
     @include('layouts.parts.base-body-end')
 </body>