diff --git a/Changelog.md b/Changelog.md index 265d9581b..e254a2aa8 100644 --- a/Changelog.md +++ b/Changelog.md @@ -37,6 +37,7 @@ If so, please delete it since it will prevent the federation from working proper * Add support for mentions in comments to the front-end [#7386](https://github.com/diaspora/diaspora/pull/7386) * Support direct links to comments on mobile [#7508](https://github.com/diaspora/diaspora/pull/7508) * Add inviter first and last name in the invitation e-mail [#7484](https://github.com/diaspora/diaspora/pull/7484) +* Add markdown editor for comments and conversations [#7482](https://github.com/diaspora/diaspora/pull/7482) # 0.6.8.0 diff --git a/app/assets/javascripts/app/router.js b/app/assets/javascripts/app/router.js index b189cad86..287aef9a6 100644 --- a/app/assets/javascripts/app/router.js +++ b/app/assets/javascripts/app/router.js @@ -9,7 +9,7 @@ app.Router = Backbone.Router.extend({ "commented(/)": "stream", "community_spotlight(/)": "spotlight", "contacts(/)": "contacts", - "conversations(/)(:id)(/)": "conversations", + "conversations(/)(:id)(?conversation_id=:conversation_id)(/)": "conversations", "followed_tags(/)": "followed_tags", "getting_started(/)": "gettingStarted", "help(/)": "help", @@ -93,8 +93,8 @@ app.Router = Backbone.Router.extend({ app.page = new app.pages.Contacts({stream: stream}); }, - conversations: function(id) { - app.conversations = app.conversations || new app.views.ConversationsInbox(); + conversations: function(id, conversationId) { + app.conversations = app.conversations || new app.views.ConversationsInbox(conversationId); if (parseInt("" + id, 10)) { app.conversations.renderConversation(id); } diff --git a/app/assets/javascripts/app/views/comment_stream_view.js b/app/assets/javascripts/app/views/comment_stream_view.js index c6374a301..d0652e5da 100644 --- a/app/assets/javascripts/app/views/comment_stream_view.js +++ b/app/assets/javascripts/app/views/comment_stream_view.js @@ -9,8 +9,8 @@ app.views.CommentStream = app.views.Base.extend({ events: { "keydown .comment_box": "keyDownOnCommentBox", "submit form": "createComment", - "focus .comment_box": "commentTextareaFocused", - "click .toggle_post_comments": "expandComments" + "click .toggle_post_comments": "expandComments", + "click form": "openForm" }, initialize: function() { @@ -21,6 +21,7 @@ app.views.CommentStream = app.views.Base.extend({ setupBindings: function() { this.model.comments.bind("add", this.appendComment, this); this.model.comments.bind("remove", this.removeComment, this); + $(document.body).click(this.onFormBlur.bind(this)); }, postRenderTemplate : function() { @@ -28,6 +29,11 @@ app.views.CommentStream = app.views.Base.extend({ this.commentBox = this.$(".comment_box"); this.commentSubmitButton = this.$("input[name='commit']"); new app.views.CommentMention({el: this.$el, postId: this.model.get("id")}); + + this.mdEditor = new Diaspora.MarkdownEditor(this.$(".comment_box"), { + onPreview: Diaspora.MarkdownEditor.simplePreview, + onFocus: this.openForm.bind(this) + }); }, presenter: function(){ @@ -53,11 +59,14 @@ app.views.CommentStream = app.views.Base.extend({ success: function() { this.commentBox.val(""); this.enableCommentBox(); + this.mdEditor.hidePreview(); + this.closeForm(); autosize.update(this.commentBox); }.bind(this), error: function() { this.enableCommentBox(); - this.commentBox.focus(); + this.mdEditor.hidePreview(); + this.openForm(); }.bind(this) }); }, @@ -122,10 +131,6 @@ app.views.CommentStream = app.views.Base.extend({ this.$("#" + comment.get("guid")).closest(".comment.media").remove(); }, - commentTextareaFocused: function(){ - this.$("form").removeClass('hidden').addClass("open"); - }, - expandComments: function(evt){ this.$(".loading-comments").removeClass("hidden"); if(evt){ evt.preventDefault(); } @@ -135,6 +140,37 @@ app.views.CommentStream = app.views.Base.extend({ this.$(".loading-comments").addClass("hidden"); }.bind(this) }); + }, + + openForm: function() { + this.$("form").addClass("open"); + this.$(".md-editor").addClass("active"); + }, + + closeForm: function() { + this.$("form").removeClass("open"); + this.$(".md-editor").removeClass("active"); + this.commentBox.blur(); + autosize.update(this.commentBox); + }, + + isCloseAllowed: function() { + if (this.mdEditor === undefined) { + return true; + } + return !this.mdEditor.isPreviewMode() && this.mdEditor.userInputEmpty(); + }, + + onFormBlur: function(evt) { + if (!this.isCloseAllowed()) { + return; + } + + var $target = $(evt.target); + var isForm = $target.hasClass("new-comment") || $target.parents(".new-comment").length !== 0; + if (!isForm && !$target.hasClass("focus_comment_textarea")) { + this.closeForm(); + } } }); // @license-end diff --git a/app/assets/javascripts/app/views/conversations_form_view.js b/app/assets/javascripts/app/views/conversations_form_view.js index e3b553b7a..df156b0a7 100644 --- a/app/assets/javascripts/app/views/conversations_form_view.js +++ b/app/assets/javascripts/app/views/conversations_form_view.js @@ -24,6 +24,8 @@ app.views.ConversationsForm = app.views.Base.extend({ remoteRoute: {url: "/contacts", extraParameters: "mutual=true"} }); + this.newConversationMdEditor = this.renderMarkdownEditor("#new-message-text"); + this.bindTypeaheadEvents(); this.tagListElement.empty(); @@ -31,10 +33,16 @@ app.views.ConversationsForm = app.views.Base.extend({ this.prefill(opts.prefill); } - this.$("form#new-conversation").on("ajax:success", this.conversationCreateSuccess); + this.$("form#new-conversation").on("ajax:success", this.conversationCreateSuccess.bind(this)); this.$("form#new-conversation").on("ajax:error", this.conversationCreateError); }, + renderMarkdownEditor: function(element) { + return new Diaspora.MarkdownEditor($(element), { + onPreview: Diaspora.MarkdownEditor.simplePreview + }); + }, + addRecipient: function(person) { this.conversationRecipients.push(person); this.updateContactIdsListInput(); @@ -84,6 +92,7 @@ app.views.ConversationsForm = app.views.Base.extend({ }, conversationCreateSuccess: function(evt, data) { + this.newConversationMdEditor.hidePreview(); app._changeLocation(Routes.conversation(data.id)); }, diff --git a/app/assets/javascripts/app/views/conversations_inbox_view.js b/app/assets/javascripts/app/views/conversations_inbox_view.js index 67292cc75..9dc556343 100644 --- a/app/assets/javascripts/app/views/conversations_inbox_view.js +++ b/app/assets/javascripts/app/views/conversations_inbox_view.js @@ -8,11 +8,21 @@ app.views.ConversationsInbox = app.views.Base.extend({ "click .new-conversation-btn": "displayNewConversation" }, - initialize: function() { - new app.views.ConversationsForm(); + initialize: function(conversationId) { + this.conversationForm = new app.views.ConversationsForm(); + + // Creates markdown editor in case of displaying preloaded conversation + if (conversationId != null) { + this.renderMarkdownEditor(); + } + this.setupConversation(); }, + renderMarkdownEditor: function() { + this.conversationForm.renderMarkdownEditor("#conversation-show .conversation-message-text"); + }, + renderConversation: function(conversationId) { var self = this; $.ajax({ @@ -23,6 +33,8 @@ app.views.ConversationsInbox = app.views.Base.extend({ self.$el.find("#conversation-show").removeClass("hidden").html(data); self.selectConversation(conversationId); self.setupConversation(); + self.renderMarkdownEditor(); + autosize(self.$("#conversation-show textarea")); } }); }, diff --git a/app/assets/javascripts/helpers/markdown_editor.js b/app/assets/javascripts/helpers/markdown_editor.js index 5706888a1..628643437 100644 --- a/app/assets/javascripts/helpers/markdown_editor.js +++ b/app/assets/javascripts/helpers/markdown_editor.js @@ -130,6 +130,14 @@ Diaspora.MarkdownEditor.prototype = { } }, + isPreviewMode: function() { + return this.instance !== undefined && this.instance.$editor.find(".md-preview").length > 0; + }, + + userInputEmpty: function() { + return this.instance === undefined || this.instance.getContent().length === 0; + }, + localize: function() { var locale = Diaspora.I18n.language; @@ -160,3 +168,7 @@ Diaspora.MarkdownEditor.prototype = { return locale; } }; + +Diaspora.MarkdownEditor.simplePreview = function($mdInstance) { + return "
" + app.helpers.textFormatter($mdInstance.getContent()) + "
"; +}; diff --git a/app/assets/javascripts/mobile/mobile_comments.js b/app/assets/javascripts/mobile/mobile_comments.js index 49858bc1c..0dbfa662f 100644 --- a/app/assets/javascripts/mobile/mobile_comments.js +++ b/app/assets/javascripts/mobile/mobile_comments.js @@ -35,7 +35,7 @@ self.scrollToOffset(commentContainer); }); - this.stream().on("submit", ".new_comment", this.submitComment); + this.stream().on("submit", ".new-comment", this.submitComment); }, submitComment: function(evt){ diff --git a/app/assets/stylesheets/color_themes/_color_theme_override_dark.scss b/app/assets/stylesheets/color_themes/_color_theme_override_dark.scss index dd52eec0c..fe2f17f11 100644 --- a/app/assets/stylesheets/color_themes/_color_theme_override_dark.scss +++ b/app/assets/stylesheets/color_themes/_color_theme_override_dark.scss @@ -11,13 +11,15 @@ body { #publisher_textarea_wrapper { background-color: $gray; } .btn.btn-link.question_mark:hover .entypo-cog { color: $gray-light; } } - - .write-preview-tabs > li.active * { color: $text-color; } - .md-preview { background-color: $gray; } - .md-cancel:hover .entypo-cross { color: $gray-light; } .publisher-buttonbar .btn.btn-link:hover i { color: $gray-light; } } + .write-preview-tabs > li.active * { color: $text-color; } + .md-cancel:hover .entypo-cross { color: $gray-light; } + + .md-input, + .md-preview { background-color: $gray; } + .aspect_dropdown li a .text { color: $dropdown-link-color; } .info .tag { background-color: $gray-light; } @@ -95,6 +97,7 @@ body { #welcome-to-diaspora { background: $orange; } + .md-editor, .block-form fieldset .form-control:focus { border-color: $input-border; } &.page-registrations.action-new, diff --git a/app/assets/stylesheets/comments.scss b/app/assets/stylesheets/comments.scss index 4fae714a7..1c111d57f 100644 --- a/app/assets/stylesheets/comments.scss +++ b/app/assets/stylesheets/comments.scss @@ -52,7 +52,6 @@ float: right; } padding-left: 12px; - display: none; } .comment_box { height: 35px; @@ -60,8 +59,6 @@ } textarea.comment_box:focus, textarea.comment_box:valid, textarea.comment_box:active { border-color: $border-dark-grey; - ~ .submit-button { display: block; } - min-height: 35px; box-shadow: none; } @@ -73,3 +70,16 @@ // scss-lint:enable ImportantRule } } + +.new-comment { + &:not(.open) .submit-button, + &:not(.open) .md-header { + display: none; + } + + // The rule for .md-preview is required until we switch to the newer release of bootstrap-markdown with + // the following commit in: + // https://github.com/toopay/bootstrap-markdown/commit/14a21c3837140144b27efc19c795d1a37fad70fb + .md-preview, + &.open .md-editor textarea { min-height: 70px; } +} diff --git a/app/assets/stylesheets/conversations.scss b/app/assets/stylesheets/conversations.scss index 7c0bf90c5..f627e8059 100644 --- a/app/assets/stylesheets/conversations.scss +++ b/app/assets/stylesheets/conversations.scss @@ -238,3 +238,9 @@ } .new-conversation.form-horizontal .form-group:last-of-type { margin-bottom: 0; } + +// This rule is required until we switch to the newer release of bootstrap-markdown with +// the following commit in: https://github.com/toopay/bootstrap-markdown/commit/14a21c3837140144b27efc19c795d1a37fad70fb +.conversations-form-container .md-preview { + min-height: 105px; +} diff --git a/app/assets/stylesheets/markdown-editor.scss b/app/assets/stylesheets/markdown-editor.scss index b077a7b44..d2657f5ad 100644 --- a/app/assets/stylesheets/markdown-editor.scss +++ b/app/assets/stylesheets/markdown-editor.scss @@ -1,3 +1,18 @@ +.md-editor { + border: 1px solid $border-grey; + border-radius: $border-radius-small; + overflow: hidden; + + &.active { border: 1px solid $border-dark-grey; } + + textarea, + textarea:focus { + border: 0; + box-shadow: none; + margin: 0; + } +} + .md-footer, .md-header { background: $white; @@ -77,13 +92,11 @@ .md-preview { - background: $white; color: $text-color; // !important is needed to override the CSS rules dynamically added to the element // scss-lint:disable ImportantRule height: auto !important; // scss-lint:enable ImportantRule - min-height: 90px; overflow: auto; position: relative; // !important is needed to override the CSS rules dynamically added to the element @@ -91,6 +104,8 @@ width: 100% !important; // scss-lint:enable ImportantRule z-index: 10; + + .preview-content { padding: 10px; } } .md-controls { diff --git a/app/assets/stylesheets/publisher.scss b/app/assets/stylesheets/publisher.scss index 83be3b015..5887a76c4 100644 --- a/app/assets/stylesheets/publisher.scss +++ b/app/assets/stylesheets/publisher.scss @@ -78,9 +78,7 @@ textarea { background: transparent; border: 0 solid $light-grey; - box-shadow: none; height: 50px; - margin: 0; resize: none; } @@ -193,6 +191,16 @@ margin-bottom: 0; } } + + .md-editor, + .md-editor.active { + border: 0; + } + + // This rule is required until we switch to the newer release of bootstrap-markdown with + // the following commit in: + // https://github.com/toopay/bootstrap-markdown/commit/14a21c3837140144b27efc19c795d1a37fad70fb + .md-preview { min-height: 90px; } } .publisher-textarea-wrapper { diff --git a/app/assets/templates/comment-stream_tpl.jst.hbs b/app/assets/templates/comment-stream_tpl.jst.hbs index cf3bb4652..592cf408b 100644 --- a/app/assets/templates/comment-stream_tpl.jst.hbs +++ b/app/assets/templates/comment-stream_tpl.jst.hbs @@ -25,7 +25,8 @@ {{/with}}
-
+