summaryrefslogtreecommitdiffstats
path: root/client/components
diff options
context:
space:
mode:
authorSam X. Chen <sam.xi.chen@gmail.com>2019-07-22 23:33:44 -0400
committerSam X. Chen <sam.xi.chen@gmail.com>2019-07-22 23:33:44 -0400
commit3632f4c8ab9b7ba6a6c1f191e41ad26232471a3a (patch)
tree965a8149debb265150f1bd3b3fe9ee56681d1c76 /client/components
parent0291bcde17669e0dd6141a4f114aa3b3caf54338 (diff)
downloadwekan-3632f4c8ab9b7ba6a6c1f191e41ad26232471a3a.tar.gz
wekan-3632f4c8ab9b7ba6a6c1f191e41ad26232471a3a.tar.bz2
wekan-3632f4c8ab9b7ba6a6c1f191e41ad26232471a3a.zip
Add Feature: Comments can be richer (can support some safe HTML tags)
Diffstat (limited to 'client/components')
-rw-r--r--client/components/activities/comments.js2
-rw-r--r--client/components/cards/cardDetails.styl2
-rwxr-xr-xclient/components/main/editor.js154
3 files changed, 96 insertions, 62 deletions
diff --git a/client/components/activities/comments.js b/client/components/activities/comments.js
index 3fc5770c..8289b628 100644
--- a/client/components/activities/comments.js
+++ b/client/components/activities/comments.js
@@ -54,7 +54,7 @@ BlazeComponent.extendComponent({
// XXX This should be a static method of the `commentForm` component
function resetCommentInput(input) {
- input.val('');
+ input.val('').trigger('input'); // without manually trigger, input event won't be fired
input.blur();
commentFormIsOpen.set(false);
}
diff --git a/client/components/cards/cardDetails.styl b/client/components/cards/cardDetails.styl
index da0fe9f8..4bba2d4d 100644
--- a/client/components/cards/cardDetails.styl
+++ b/client/components/cards/cardDetails.styl
@@ -126,7 +126,7 @@ input[type="submit"].attachment-add-link-submit
@media screen and (max-width: 800px)
.card-details
- width: calc(100% - 40px)
+ width: calc(100% - 1px)
padding: 0px 20px 0px 20px
margin: 0px
transition: none
diff --git a/client/components/main/editor.js b/client/components/main/editor.js
index 400043f2..9c1ad7a8 100755
--- a/client/components/main/editor.js
+++ b/client/components/main/editor.js
@@ -26,15 +26,20 @@ Template.editor.onRendered(() => {
index: 1,
},
];
+ const enableTextarea = function() {
+ const $textarea = this.$(textareaSelector);
+ autosize($textarea);
+ $textarea.escapeableTextComplete(mentions);
+ };
if (!disableRicherEditor) {
const isSmall = Utils.isMiniScreen();
const toolbar = isSmall
? [
+ ['view', ['fullscreen']],
+ ['table', ['table']],
['font', ['bold', 'underline']],
- ['fontsize', ['fontsize']],
+ //['fontsize', ['fontsize']],
['color', ['color']],
- ['table', ['table']],
- ['view', ['fullscreen']],
]
: [
['style', ['style']],
@@ -45,7 +50,7 @@ Template.editor.onRendered(() => {
['para', ['ul', 'ol', 'paragraph']],
['table', ['table']],
//['insert', ['link', 'picture', 'video']], // iframe tag will be sanitized TODO if iframe[class=note-video-clip] can be added into safe list, insert video can be enabled
- ['insert', ['link', 'picture']],
+ //['insert', ['link', 'picture']], // modal popup has issue somehow :(
['view', ['fullscreen', 'help']],
];
const cleanPastedHTML = function(input) {
@@ -90,63 +95,92 @@ Template.editor.onRendered(() => {
`.js-new-comment-form ${editor}`,
`.js-edit-comment ${editor}`,
].join(','); // only new comment and edit comment
- $(selectors).summernote({
- callbacks: {
- onInit(object) {
- const jEditor = object && object.editor;
- const toolbar = object && object.toolbar;
- if (jEditor !== undefined) {
- jEditor.find('.note-editable').escapeableTextComplete(mentions);
- }
- if (toolbar !== undefined) {
- const fBtn = toolbar.find('.btn-fullscreen');
- fBtn.on('click', function() {
- const $this = $(this),
- isActive = $this.hasClass('active');
- $('.minicards').toggle(!isActive); // mini card is still showing when editor is in fullscreen mode, we hide here manually
- });
- }
- },
- onPaste() {
- // clear up unwanted tag info when user pasted in text
- const thisNote = $(this);
- const updatePastedText = function(someNote) {
- const original = someNote.summernote('code');
- const cleaned = cleanPastedHTML(original); //this is where to call whatever clean function you want. I have mine in a different file, called CleanPastedHTML.
- someNote.summernote('code', ''); //clear original
- someNote.summernote('pasteHTML', cleaned); //this sets the displayed content editor to the cleaned pasted code.
- };
- setTimeout(function() {
- //this kinda sucks, but if you don't do a setTimeout,
- //the function is called before the text is really pasted.
- updatePastedText(thisNote);
- }, 10);
- },
- },
- dialogsInBody: true,
- disableDragAndDrop: true,
- toolbar,
- popover: {
- image: [
- [
- 'image',
- ['resizeFull', 'resizeHalf', 'resizeQuarter', 'resizeNone'],
- ],
- ['float', ['floatLeft', 'floatRight', 'floatNone']],
- ['remove', ['removeMedia']],
- ],
- table: [
- ['add', ['addRowDown', 'addRowUp', 'addColLeft', 'addColRight']],
- ['delete', ['deleteRow', 'deleteCol', 'deleteTable']],
- ],
- air: [['color', ['color']], ['font', ['bold', 'underline', 'clear']]],
- },
- height: 200,
- });
+ const inputs = $(selectors);
+ if (inputs.length === 0) {
+ // only enable richereditor to new comment or edit comment no others
+ enableTextarea();
+ } else {
+ const placeholder = inputs.attr('placeholder') || '';
+ const mSummernotes = [];
+ const getSummernote = function(input) {
+ const idx = inputs.index(input);
+ if (idx > -1) {
+ return mSummernotes[idx];
+ }
+ return undefined;
+ };
+ inputs.each(function(idx, input) {
+ mSummernotes[idx] = $(input).summernote({
+ placeholder,
+ callbacks: {
+ onInit(object) {
+ const originalInput = this;
+ $(originalInput).on('input', function() {
+ // when comment is submitted, the original textarea will be set to '', so shall we
+ if (!this.value) {
+ const sn = getSummernote(this);
+ sn && sn.summernote('reset');
+ object && object.editingArea.find('.note-placeholder').show();
+ }
+ });
+ const jEditor = object && object.editable;
+ const toolbar = object && object.toolbar;
+ if (jEditor !== undefined) {
+ jEditor.escapeableTextComplete(mentions);
+ }
+ if (toolbar !== undefined) {
+ const fBtn = toolbar.find('.btn-fullscreen');
+ fBtn.on('click', function() {
+ const $this = $(this),
+ isActive = $this.hasClass('active');
+ $('.minicards').toggle(!isActive); // mini card is still showing when editor is in fullscreen mode, we hide here manually
+ });
+ }
+ },
+ onPaste() {
+ // clear up unwanted tag info when user pasted in text
+ const thisNote = this;
+ const updatePastedText = function(object) {
+ const someNote = getSummernote(object);
+ const original = someNote.summernote('code');
+ const cleaned = cleanPastedHTML(original); //this is where to call whatever clean function you want. I have mine in a different file, called CleanPastedHTML.
+ someNote.summernote('reset'); //clear original
+ someNote.summernote('pasteHTML', cleaned); //this sets the displayed content editor to the cleaned pasted code.
+ };
+ setTimeout(function() {
+ //this kinda sucks, but if you don't do a setTimeout,
+ //the function is called before the text is really pasted.
+ updatePastedText(thisNote);
+ }, 10);
+ },
+ },
+ dialogsInBody: true,
+ disableDragAndDrop: true,
+ toolbar,
+ popover: {
+ image: [
+ [
+ 'image',
+ ['resizeFull', 'resizeHalf', 'resizeQuarter', 'resizeNone'],
+ ],
+ ['float', ['floatLeft', 'floatRight', 'floatNone']],
+ ['remove', ['removeMedia']],
+ ],
+ table: [
+ ['add', ['addRowDown', 'addRowUp', 'addColLeft', 'addColRight']],
+ ['delete', ['deleteRow', 'deleteCol', 'deleteTable']],
+ ],
+ air: [
+ ['color', ['color']],
+ ['font', ['bold', 'underline', 'clear']],
+ ],
+ },
+ height: 200,
+ });
+ });
+ }
} else {
- const $textarea = this.$(textareaSelector);
- autosize($textarea);
- $textarea.escapeableTextComplete(mentions);
+ enableTextarea();
}
});