Add Markdown preview to more forms

Enable Markdown previews when creating and editing issues, merge
requests, and milestones, and when editing notes.
This commit is contained in:
Vinnie Okada 2014-10-15 02:21:21 -05:00
parent a0a826ebdc
commit 5700842ba8
21 changed files with 260 additions and 141 deletions

View file

@ -24,6 +24,51 @@ $(document).ready ->
"opacity": 0
"display": "none"
# Preview button
$(document).off "click", ".js-md-preview-button"
$(document).on "click", ".js-md-preview-button", (e) ->
###
Shows the Markdown preview.
Lets the server render GFM into Html and displays it.
###
e.preventDefault()
form = $(this).closest("form")
# toggle tabs
form.find(".js-md-write-button").parent().removeClass "active"
form.find(".js-md-preview-button").parent().addClass "active"
# toggle content
form.find(".md-write-holder").hide()
form.find(".md-preview-holder").show()
preview = form.find(".js-md-preview")
mdText = form.find(".markdown-area").val()
if mdText.trim().length is 0
preview.text "Nothing to preview."
else
preview.text "Loading..."
$.post($(this).data("url"),
md_text: mdText
).success (previewData) ->
preview.html previewData
# Write button
$(document).off "click", ".js-md-write-button"
$(document).on "click", ".js-md-write-button", (e) ->
###
Shows the Markdown textarea.
###
e.preventDefault()
form = $(this).closest("form")
# toggle tabs
form.find(".js-md-write-button").parent().addClass "active"
form.find(".js-md-preview-button").parent().removeClass "active"
# toggle content
form.find(".md-write-holder").show()
form.find(".md-preview-holder").hide()
dropzone = $(".div-dropzone").dropzone(
url: project_image_path_upload
dictDefaultMessage: ""

View file

@ -36,12 +36,6 @@ class Notes
# delete note attachment
$(document).on "click", ".js-note-attachment-delete", @removeAttachment
# Preview button
$(document).on "click", ".js-note-preview-button", @previewNote
# Preview button
$(document).on "click", ".js-note-write-button", @writeNote
# reset main target form after submit
$(document).on "ajax:complete", ".js-main-target-form", @resetMainTargetForm
@ -77,8 +71,6 @@ class Notes
$(document).off "click", ".note-edit-cancel"
$(document).off "click", ".js-note-delete"
$(document).off "click", ".js-note-attachment-delete"
$(document).off "click", ".js-note-preview-button"
$(document).off "click", ".js-note-write-button"
$(document).off "ajax:complete", ".js-main-target-form"
$(document).off "click", ".js-choose-note-attachment-button"
$(document).off "click", ".js-discussion-reply-button"
@ -165,47 +157,6 @@ class Notes
# cleanup after successfully creating a diff/discussion note
@removeDiscussionNoteForm(form)
###
Shows write note textarea.
###
writeNote: (e) ->
e.preventDefault()
form = $(this).closest("form")
# toggle tabs
form.find(".js-note-write-button").parent().addClass "active"
form.find(".js-note-preview-button").parent().removeClass "active"
# toggle content
form.find(".note-write-holder").show()
form.find(".note-preview-holder").hide()
###
Shows the note preview.
Lets the server render GFM into Html and displays it.
###
previewNote: (e) ->
e.preventDefault()
form = $(this).closest("form")
# toggle tabs
form.find(".js-note-write-button").parent().removeClass "active"
form.find(".js-note-preview-button").parent().addClass "active"
# toggle content
form.find(".note-write-holder").hide()
form.find(".note-preview-holder").show()
preview = form.find(".js-note-preview")
noteText = form.find(".js-note-text").val()
if noteText.trim().length is 0
preview.text "Nothing to preview."
else
preview.text "Loading..."
$.post($(this).data("url"),
note: noteText
).success (previewData) ->
preview.html previewData
###
Called in response the main target form has been successfully submitted.
@ -220,7 +171,7 @@ class Notes
form.find(".js-errors").remove()
# reset text and preview
form.find(".js-note-write-button").click()
form.find(".js-md-write-button").click()
form.find(".js-note-text").val("").trigger "input"
###
@ -270,8 +221,8 @@ class Notes
form.removeClass "js-new-note-form"
# setup preview buttons
form.find(".js-note-write-button, .js-note-preview-button").tooltip placement: "left"
previewButton = form.find(".js-note-preview-button")
form.find(".js-md-write-button, .js-md-preview-button").tooltip placement: "left"
previewButton = form.find(".js-md-preview-button")
form.find(".js-note-text").on "input", ->
if $(this).val().trim() isnt ""
previewButton.removeClass("turn-off").addClass "turn-on"

View file

@ -50,3 +50,28 @@
margin-bottom: 0;
transition: opacity 200ms ease-in-out;
}
.md-preview-holder {
background: #FFF;
border: 1px solid #ddd;
min-height: 100px;
padding: 5px;
font-size: 14px;
box-shadow: none;
}
.new_note,
.edit_note,
.issuable-description,
.milestone-description,
.merge-request-form {
.nav-tabs {
margin-bottom: 0;
border: none;
li a,
li.active a {
border: 1px solid #DDD;
}
}
}

View file

@ -224,7 +224,6 @@ ul.notes {
margin-bottom: 0;
}
.note-preview-holder,
.note_text {
background: #FFF;
border: 1px solid #ddd;
@ -243,15 +242,6 @@ ul.notes {
.note_text {
width: 100%;
}
.nav-tabs {
margin-bottom: 0;
border: none;
li a,
li.active a {
border: 1px solid #DDD;
}
}
}
/* loading indicator */

View file

@ -61,10 +61,6 @@ class Projects::NotesController < Projects::ApplicationController
end
end
def preview
render text: view_context.markdown(params[:note])
end
private
def note

View file

@ -183,6 +183,10 @@ class ProjectsController < ApplicationController
render json: { star_count: @project.star_count }
end
def markdown_preview
render text: view_context.markdown(params[:md_text])
end
private
def upload_path

View file

@ -14,6 +14,8 @@
.form-group.issuable-description
= f.label :description, 'Description', class: 'control-label'
.col-sm-10
= render layout: 'projects/md_preview' do
= render 'projects/zen', f: f, attr: :description,
classes: 'description form-control'
.col-sm-12.hint
@ -23,6 +25,7 @@
.pull-right
Attach images (JPG, PNG, GIF) by dragging &amp; dropping
or #{link_to 'selecting them', '#', class: 'markdown-selector' }.
.clearfix
.error-alert
%hr

View file

@ -0,0 +1,12 @@
%ul.nav.nav-tabs
%li.active
= link_to '#md-write-holder', class: 'js-md-write-button' do
Write
%li
= link_to '#md-preview-holder', class: 'js-md-preview-button', data: { url: markdown_preview_project_path(@project) } do
Preview
%div
.md-write-holder
= yield
.md-preview-holder.hide
.js-md-preview

View file

@ -21,6 +21,7 @@
.form-group
.light
= f.label :description, "Description"
= render layout: 'projects/md_preview' do
= render 'projects/zen', f: f, attr: :description,
classes: 'description form-control'
.clearfix.hint

View file

@ -18,9 +18,10 @@
.col-sm-10
= f.text_field :title, maxlength: 255, class: "form-control"
%p.hint Required
.form-group
.form-group.milestone-description
= f.label :description, "Description", class: "control-label"
.col-sm-10
= render layout: 'projects/md_preview' do
= render 'projects/zen', f: f, attr: :description, classes: 'description form-control'
.hint
.pull-left Milestones are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"), target: '_blank'}.

View file

@ -5,23 +5,13 @@
= f.hidden_field :noteable_id
= f.hidden_field :noteable_type
%ul.nav.nav-tabs
%li.active
= link_to '#note-write-holder', class: 'js-note-write-button' do
Write
%li
= link_to '#note-preview-holder', class: 'js-note-preview-button', data: { url: preview_project_notes_path(@project) } do
Preview
%div
.note-write-holder
= render layout: 'projects/md_preview' do
= render 'projects/zen', f: f, attr: :note,
classes: 'note_text js-note-text'
.light.clearfix
.pull-left Comments are parsed with #{link_to "GitLab Flavored Markdown", help_page_path("markdown", "markdown"),{ target: '_blank', tabindex: -1 }}
.pull-right Attach images (JPG, PNG, GIF) by dragging &amp; dropping or #{link_to "selecting them", '#', class: 'markdown-selector', tabindex: -1 }.
.note-preview-holder.hide
.js-note-preview
.note-form-actions
.buttons

View file

@ -38,7 +38,8 @@
.note-edit-form
= form_for note, url: project_note_path(@project, note), method: :put, remote: true, authenticity_token: true do |f|
= f.text_area :note, class: 'note_text js-note-text js-gfm-input turn-on'
= render layout: 'projects/md_preview' do
= f.text_area :note, class: 'note_text js-note-text markdown-area js-gfm-input turn-on'
.form-actions.clearfix
= f.submit 'Save changes', class: "btn btn-primary btn-save js-comment-button"

View file

@ -186,6 +186,7 @@ Gitlab::Application.routes.draw do
post :unarchive
post :upload_image
post :toggle_star
post :markdown_preview
get :autocomplete_sources
get :import
put :retry_import
@ -328,10 +329,6 @@ Gitlab::Application.routes.draw do
member do
delete :delete_attachment
end
collection do
post :preview
end
end
end
end

View file

@ -159,3 +159,30 @@ Feature: Project Issues
Given project "Shop" has "Tasks-closed" closed issue with task markdown
When I visit issue page "Tasks-closed"
Then Task checkboxes should be disabled
# Issue description preview
@javascript
Scenario: I can't preview without text
Given I click link "New Issue"
And I haven't written any description text
Then I should not see the Markdown preview button
@javascript
Scenario: I can preview with text
Given I click link "New Issue"
And I write a description like "Nice"
Then I should see the Markdown preview button
@javascript
Scenario: I preview an issue description
Given I click link "New Issue"
And I preview a description text like "Bug fixed :smile:"
Then I should see the Markdown preview
And I should not see the Markdown text field
@javascript
Scenario: I can edit after preview
Given I click link "New Issue"
And I preview a description text like "Bug fixed :smile:"
Then I should see the Markdown edit button

View file

@ -187,3 +187,34 @@ Feature: Project Merge Requests
And I visit merge request page "MR-task-open"
And I click link "Close"
Then Task checkboxes should be disabled
# Description preview
@javascript
Scenario: I can't preview without text
Given I visit merge request page "Bug NS-04"
And I click link "Edit"
And I haven't written any description text
Then I should not see the Markdown preview button
@javascript
Scenario: I can preview with text
Given I visit merge request page "Bug NS-04"
And I click link "Edit"
And I write a description like "Nice"
Then I should see the Markdown preview button
@javascript
Scenario: I preview a merge request description
Given I visit merge request page "Bug NS-04"
And I click link "Edit"
And I preview a description text like "Bug fixed :smile:"
Then I should see the Markdown preview
And I should not see the Markdown text field
@javascript
Scenario: I can edit after preview
Given I visit merge request page "Bug NS-04"
And I click link "Edit"
And I preview a description text like "Bug fixed :smile:"
Then I should see the Markdown edit button

View file

@ -10,6 +10,10 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps
click_link "New Merge Request"
end
step 'I click link "Edit"' do
click_link 'Edit'
end
step 'I click link "Bug NS-04"' do
click_link "Bug NS-04"
end

View file

@ -32,7 +32,7 @@ module SharedDiffNote
click_diff_line(sample_commit.line_code)
within("#{diff_file_selector} form[rel$='#{sample_commit.line_code}']") do
fill_in "note[note]", with: "Should fix it :smile:"
find(".js-note-preview-button").trigger("click")
find('.js-md-preview-button').trigger('click')
end
end
@ -41,7 +41,7 @@ module SharedDiffNote
within("#{diff_file_selector} form[rel$='#{sample_commit.del_line_code}']") do
fill_in "note[note]", with: "DRY this up"
find(".js-note-preview-button").trigger("click")
find('.js-md-preview-button').trigger('click')
end
end
@ -73,7 +73,7 @@ module SharedDiffNote
step 'I should not see the diff comment preview button' do
within(diff_file_selector) do
page.should have_css(".js-note-preview-button", visible: false)
page.should have_css('.js-md-preview-button', visible: false)
end
end
@ -131,25 +131,25 @@ module SharedDiffNote
step 'I should see the diff comment preview' do
within("#{diff_file_selector} form") do
page.should have_css(".js-note-preview", visible: false)
page.should have_css('.js-md-preview', visible: false)
end
end
step 'I should see the diff comment edit button' do
within(diff_file_selector) do
page.should have_css(".js-note-write-button", visible: true)
page.should have_css('.js-md-write-button', visible: true)
end
end
step 'I should see the diff comment preview button' do
within(diff_file_selector) do
page.should have_css(".js-note-preview-button", visible: true)
page.should have_css('.js-md-preview-button', visible: true)
end
end
step 'I should see two separate previews' do
within(diff_file_selector) do
page.should have_css(".js-note-preview", visible: true, count: 2)
page.should have_css('.js-md-preview', visible: true, count: 2)
page.should have_content("Should fix it")
page.should have_content("DRY this up")
end

View file

@ -54,4 +54,43 @@ EOT
'div.description li.task-list-item input[type="checkbox"]:disabled'
)
end
step 'I should not see the Markdown preview' do
find('.gfm-form').should have_css('.js-md-preview', visible: false)
end
step 'I should not see the Markdown preview button' do
find('.gfm-form').should have_css('.js-md-preview-button', visible: false)
end
step 'I should not see the Markdown text field' do
find('.gfm-form').should have_css('textarea', visible: false)
end
step 'I should see the Markdown edit button' do
find('.gfm-form').should have_css('.js-md-write-button', visible: true)
end
step 'I should see the Markdown preview' do
find('.gfm-form').should have_css('.js-md-preview', visible: true)
end
step 'I should see the Markdown preview button' do
find('.gfm-form').should have_css('.js-md-preview-button', visible: true)
end
step 'I write a description like "Nice"' do
find('.gfm-form').fill_in 'Description', with: 'Nice'
end
step 'I preview a description text like "Bug fixed :smile:"' do
within('.gfm-form') do
fill_in 'Description', with: 'Bug fixed :smile:'
find('.js-md-preview-button').trigger('click')
end
end
step 'I haven\'t written any description text' do
find('.gfm-form').fill_in 'Description', with: ''
end
end

View file

@ -23,7 +23,7 @@ module SharedNote
step 'I preview a comment text like "Bug fixed :smile:"' do
within(".js-main-target-form") do
fill_in "note[note]", with: "Bug fixed :smile:"
find(".js-note-preview-button").trigger("click")
find('.js-md-preview-button').trigger('click')
end
end
@ -51,13 +51,13 @@ module SharedNote
step 'I should not see the comment preview' do
within(".js-main-target-form") do
page.should have_css(".js-note-preview", visible: false)
page.should have_css('.js-md-preview', visible: false)
end
end
step 'I should not see the comment preview button' do
within(".js-main-target-form") do
page.should have_css(".js-note-preview-button", visible: false)
page.should have_css('.js-md-preview-button', visible: false)
end
end
@ -81,19 +81,19 @@ module SharedNote
step 'I should see the comment edit button' do
within(".js-main-target-form") do
page.should have_css(".js-note-write-button", visible: true)
page.should have_css('.js-md-write-button', visible: true)
end
end
step 'I should see the comment preview' do
within(".js-main-target-form") do
page.should have_css(".js-note-preview", visible: true)
page.should have_css('.js-md-preview', visible: true)
end
end
step 'I should see the comment preview button' do
within(".js-main-target-form") do
page.should have_css(".js-note-preview-button", visible: true)
page.should have_css('.js-md-preview-button', visible: true)
end
end

View file

@ -20,7 +20,7 @@ describe 'Comments' do
should have_css(".js-main-target-form", visible: true, count: 1)
find(".js-main-target-form input[type=submit]").value.should == "Add Comment"
within(".js-main-target-form") { should_not have_link("Cancel") }
within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: false) }
within('.js-main-target-form') { should have_css('.js-md-preview-button', visible: false) }
end
describe "with text" do
@ -32,7 +32,7 @@ describe 'Comments' do
it 'should have enable submit button and preview button' do
within(".js-main-target-form") { should_not have_css(".js-comment-button[disabled]") }
within(".js-main-target-form") { should have_css(".js-note-preview-button", visible: true) }
within('.js-main-target-form') { should have_css('.js-md-preview-button', visible: true) }
end
end
end
@ -41,7 +41,7 @@ describe 'Comments' do
before do
within(".js-main-target-form") do
fill_in "note[note]", with: "This is awsome!"
find(".js-note-preview-button").trigger("click")
find('.js-md-preview-button').trigger('click')
click_button "Add Comment"
end
end
@ -49,7 +49,7 @@ describe 'Comments' do
it 'should be added and form reset' do
should have_content("This is awsome!")
within(".js-main-target-form") { should have_no_field("note[note]", with: "This is awesome!") }
within(".js-main-target-form") { should have_css(".js-note-preview", visible: false) }
within('.js-main-target-form') { should have_css('.js-md-preview', visible: false) }
within(".js-main-target-form") { should have_css(".js-note-text", visible: true) }
end
end
@ -172,11 +172,11 @@ describe 'Comments' do
# add two separate texts and trigger previews on both
within("tr[id='#{line_code}'] + .js-temp-notes-holder") do
fill_in "note[note]", with: "One comment on line 7"
find(".js-note-preview-button").trigger("click")
find('.js-md-preview-button').trigger('click')
end
within("tr[id='#{line_code_2}'] + .js-temp-notes-holder") do
fill_in "note[note]", with: "Another comment on line 10"
find(".js-note-preview-button").trigger("click")
find('.js-md-preview-button').trigger('click')
end
end
end

View file

@ -61,6 +61,7 @@ end
# project GET /:id(.:format) projects#show
# PUT /:id(.:format) projects#update
# DELETE /:id(.:format) projects#destroy
# markdown_preview_project POST /:id/markdown_preview(.:format) projects#markdown_preview
describe ProjectsController, "routing" do
it "to #create" do
post("/projects").should route_to('projects#create')
@ -93,6 +94,12 @@ describe ProjectsController, "routing" do
it "to #destroy" do
delete("/gitlab/gitlabhq").should route_to('projects#destroy', id: 'gitlab/gitlabhq')
end
it 'to #markdown_preview' do
post('/gitlab/gitlabhq/markdown_preview').should(
route_to('projects#markdown_preview', id: 'gitlab/gitlabhq')
)
end
end
# pages_project_wikis GET /:project_id/wikis/pages(.:format) projects/wikis#pages
@ -392,15 +399,10 @@ describe Projects::IssuesController, "routing" do
end
end
# preview_project_notes POST /:project_id/notes/preview(.:format) notes#preview
# project_notes GET /:project_id/notes(.:format) notes#index
# POST /:project_id/notes(.:format) notes#create
# project_note DELETE /:project_id/notes/:id(.:format) notes#destroy
describe Projects::NotesController, "routing" do
it "to #preview" do
post("/gitlab/gitlabhq/notes/preview").should route_to('projects/notes#preview', project_id: 'gitlab/gitlabhq')
end
it_behaves_like "RESTful project resources" do
let(:actions) { [:index, :create, :destroy] }
let(:controller) { 'notes' }