diff options
author | Sam X. Chen <sam.xi.chen@gmail.com> | 2019-07-22 23:33:44 -0400 |
---|---|---|
committer | Sam X. Chen <sam.xi.chen@gmail.com> | 2019-07-22 23:33:44 -0400 |
commit | 3632f4c8ab9b7ba6a6c1f191e41ad26232471a3a (patch) | |
tree | 965a8149debb265150f1bd3b3fe9ee56681d1c76 /client/components | |
parent | 0291bcde17669e0dd6141a4f114aa3b3caf54338 (diff) | |
download | wekan-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.js | 2 | ||||
-rw-r--r-- | client/components/cards/cardDetails.styl | 2 | ||||
-rwxr-xr-x | client/components/main/editor.js | 154 |
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(); } }); |