From 4a6596af274c01036aaf9f49a5b38cd678716873 Mon Sep 17 00:00:00 2001 From: randx Date: Thu, 30 Aug 2012 21:31:55 +0300 Subject: [PATCH] Fixed bunch of js bugs with comments. Also added development tips --- README.md | 1 + app/assets/javascripts/application.js | 20 ++ app/assets/javascripts/note.js | 250 ++++++++++----------- app/assets/stylesheets/sections/notes.scss | 2 +- app/views/commits/show.html.haml | 10 +- app/views/notes/_create_common.js.haml | 11 +- app/views/notes/_create_line.js.haml | 2 +- app/views/notes/_form.html.haml | 67 +++--- app/views/notes/_per_line_form.html.haml | 51 ++--- doc/development.md | 45 ++++ gitlab | 7 +- resque_dev.sh | 3 +- 12 files changed, 269 insertions(+), 200 deletions(-) create mode 100644 doc/development.md diff --git a/README.md b/README.md index 26ed209ef87..122cd984b4a 100644 --- a/README.md +++ b/README.md @@ -39,5 +39,6 @@ Email ## Contribute +[Development Tips](https://github.com/gitlabhq/gitlabhq/blob/master/doc/development.md) Want to help - send a pull request. We'll accept good pull requests. diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 24d99a62ca5..f69fd6f9a44 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -128,3 +128,23 @@ function showDiff(link) { function ajaxGet(url) { $.ajax({type: "GET", url: url, dataType: "script"}); } + +/** + * Disable button if text field is empty + */ +function disableButtonIfEmtpyField(field_selector, button_selector) { + field = $(field_selector); + if(field.val() == "") { + field.closest("form").find(button_selector).attr("disabled", "disabled").addClass("disabled"); + } + + field.on('keyup', function(){ + var field = $(this); + var closest_submit = field.closest("form").find(button_selector); + if(field.val() == "") { + closest_submit.attr("disabled", "disabled").addClass("disabled"); + } else { + closest_submit.removeAttr("disabled").removeClass("disabled"); + } + }) +} diff --git a/app/assets/javascripts/note.js b/app/assets/javascripts/note.js index 212c203a855..9cd3e36e87b 100644 --- a/app/assets/javascripts/note.js +++ b/app/assets/javascripts/note.js @@ -1,174 +1,160 @@ var NoteList = { -notes_path: null, -target_params: null, -target_id: 0, -target_type: null, -first_id: 0, -last_id: 0, -disable:false, + notes_path: null, + target_params: null, + target_id: 0, + target_type: null, + first_id: 0, + last_id: 0, + disable:false, -init: - function(tid, tt, path) { - this.notes_path = path + ".js"; - this.target_id = tid; - this.target_type = tt; - this.target_params = "&target_type=" + this.target_type + "&target_id=" + this.target_id; + init: + function(tid, tt, path) { + this.notes_path = path + ".js"; + this.target_id = tid; + this.target_type = tt; + this.target_params = "&target_type=" + this.target_type + "&target_id=" + this.target_id; - // get notes - this.getContent(); + // get notes + this.getContent(); - // get new notes every n seconds - this.initRefresh(); + // get new notes every n seconds + this.initRefresh(); - $('.delete-note').live('ajax:success', function() { - $(this).closest('li').fadeOut(); }); + $('.delete-note').live('ajax:success', function() { + $(this).closest('li').fadeOut(); }); - $('#note_note').on('keyup', function(){ - var field = $(this); - var closest_submit = field.closest("form").find(".submit_note"); - if(field.val() == "") { - closest_submit.attr("disabled", "disabled").addClass("disabled"); - } else { - closest_submit.removeAttr("disabled").removeClass("disabled"); - } - }) + $(".note-form-holder").live("ajax:before", function(){ + $(".submit_note").attr("disabled", "disabled"); + }) - $("#new_note").live("ajax:before", function(){ - $(".submit_note").attr("disabled", "disabled"); - }) + $(".note-form-holder").live("ajax:complete", function(){ + $(".submit_note").removeAttr("disabled"); + }) - $("#new_note").live("ajax:complete", function(){ - $(".submit_note").removeAttr("disabled"); - }) + disableButtonIfEmtpyField(".note-text", ".submit_note"); - $("#note_note").live("focus", function(){ - $(this).css("height", "80px"); - $('.note_advanced_opts').show(); - if($(this).val() == "") { - $(this).closest("form").find(".submit_note").attr("disabled", "disabled").addClass("disabled"); - } - }); + $(".note-text").live("focus", function(){ + $(this).css("height", "80px"); + $('.note_advanced_opts').show(); + }); - $("#note_attachment").change(function(e){ + $("#note_attachment").change(function(e){ var val = $('.input-file').val(); var filename = val.replace(/^.*[\\\/]/, ''); $(".file_name").text(filename); - }); + }); - }, + }, -/** - * Load new notes to fresh list called 'new_notes_list': - * - Replace 'new_notes_list' with new list every n seconds - * - Append new notes to this list after submit - */ + /** + * Load new notes to fresh list called 'new_notes_list': + * - Replace 'new_notes_list' with new list every n seconds + * - Append new notes to this list after submit + */ -initRefresh: - function() { - // init timer - var intNew = setInterval("NoteList.getNew()", 10000); - }, + initRefresh: + function() { + // init timer + var intNew = setInterval("NoteList.getNew()", 10000); + }, -replace: - function(html) { - $("#new_notes_list").html(html); - }, + replace: + function(html) { + $("#new_notes_list").html(html); + }, -prepend: - function(id, html) { - if(id != this.last_id) { - $("#new_notes_list").prepend(html); - } - }, + prepend: + function(id, html) { + if(id != this.last_id) { + $("#new_notes_list").prepend(html); + } + }, -getNew: - function() { - // refersh notes list - $.ajax({ - type: "GET", + getNew: + function() { + // refersh notes list + $.ajax({ + type: "GET", url: this.notes_path, data: "last_id=" + this.last_id + this.target_params, dataType: "script"}); - }, + }, -refresh: - function() { - // refersh notes list - $.ajax({ - type: "GET", + refresh: + function() { + // refersh notes list + $.ajax({ + type: "GET", url: this.notes_path, data: "first_id=" + this.first_id + "&last_id=" + this.last_id + this.target_params, dataType: "script"}); - }, + }, -/** - * Init load of notes: - * 1. Get content with ajax call - * 2. Set content of notes list with loaded one - */ + /** + * Init load of notes: + * 1. Get content with ajax call + * 2. Set content of notes list with loaded one + */ -getContent: - function() { - $.ajax({ - type: "GET", + getContent: + function() { + $.ajax({ + type: "GET", url: this.notes_path, data: "?" + this.target_params, complete: function(){ $('.status').removeClass("loading")}, beforeSend: function() { $('.status').addClass("loading") }, dataType: "script"}); - }, + }, -setContent: - function(fid, lid, html) { + setContent: + function(fid, lid, html) { this.last_id = lid; this.first_id = fid; $("#notes-list").html(html); // Init infinite scrolling this.initLoadMore(); - }, + }, -/** - * Paging for old notes when scroll to bottom: - * 1. Init scroll events with 'initLoadMore' - * 2. Load onlder notes with 'getOld' method - * 3. append old notes to bottom of list with 'append' - * - */ + /** + * Paging for old notes when scroll to bottom: + * 1. Init scroll events with 'initLoadMore' + * 2. Load onlder notes with 'getOld' method + * 3. append old notes to bottom of list with 'append' + * + */ + getOld: + function() { + $('.loading').show(); + $.ajax({ + type: "GET", + url: this.notes_path, + data: "first_id=" + this.first_id + this.target_params, + complete: function(){ $('.status').removeClass("loading")}, + beforeSend: function() { $('.status').addClass("loading") }, + dataType: "script"}); + }, + append: + function(id, html) { + if(this.first_id == id) { + this.disable = true; + } else { + this.first_id = id; + $("#notes-list").append(html); + } + }, -getOld: - function() { - $('.loading').show(); - $.ajax({ - type: "GET", - url: this.notes_path, - data: "first_id=" + this.first_id + this.target_params, - complete: function(){ $('.status').removeClass("loading")}, - beforeSend: function() { $('.status').addClass("loading") }, - dataType: "script"}); - }, - -append: - function(id, html) { - if(this.first_id == id) { - this.disable = true; - } else { - this.first_id = id; - $("#notes-list").append(html); - } - }, - - -initLoadMore: - function() { - $(document).endlessScroll({ - bottomPixels: 400, + initLoadMore: + function() { + $(document).endlessScroll({ + bottomPixels: 400, fireDelay: 1000, fireOnce:true, ceaseFire: function() { @@ -177,6 +163,20 @@ initLoadMore: callback: function(i) { NoteList.getOld(); } - }); - } + }); + } +}; + +var PerLineNotes = { + init: + function() { + $(".line_note_link, .line_note_reply_link").live("click", function(e) { + var form = $(".per_line_form"); + $(this).closest("tr").after(form); + form.find("#note_line_code").val($(this).attr("line_code")); + form.show(); + return false; + }); + disableButtonIfEmtpyField(".line-note-text", ".submit_inline_note"); + } } diff --git a/app/assets/stylesheets/sections/notes.scss b/app/assets/stylesheets/sections/notes.scss index 6259939e6ef..21dff4cfe3c 100644 --- a/app/assets/stylesheets/sections/notes.scss +++ b/app/assets/stylesheets/sections/notes.scss @@ -30,7 +30,7 @@ } #new_note { - #note_note { + .note-text { height:25px; } .attach_holder { diff --git a/app/views/commits/show.html.haml b/app/views/commits/show.html.haml index 9a483aa2a9a..e01f8ea5878 100644 --- a/app/views/commits/show.html.haml +++ b/app/views/commits/show.html.haml @@ -5,12 +5,6 @@ :javascript - $(document).ready(function(){ - $(".line_note_link, .line_note_reply_link").live("click", function(e) { - var form = $(".per_line_form"); - $(this).parent().parent().after(form); - form.find("#note_line_code").val($(this).attr("line_code")); - form.show(); - return false; - }); + $(function(){ + PerLineNotes.init(); }); diff --git a/app/views/notes/_create_common.js.haml b/app/views/notes/_create_common.js.haml index e9538902754..e80eccb1b4c 100644 --- a/app/views/notes/_create_common.js.haml +++ b/app/views/notes/_create_common.js.haml @@ -1,11 +1,12 @@ - if note.valid? :plain - $("#new_note .error").remove(); - $('#new_note textarea').val(""); - $('#preview-link').text('Preview'); - $('#preview-note').hide(); $('#note_note').show(); + $(".note-form-holder .error").remove(); + $('.note-form-holder textarea').val(""); + $('.note-form-holder #preview-link').text('Preview'); + $('.note-form-holder #preview-note').hide(); + $('.note-form-holder').show(); NoteList.prepend(#{note.id}, "#{escape_javascript(render partial: "notes/show", locals: {note: note})}"); - else :plain - $("#new_note").replaceWith("#{escape_javascript(render('form'))}"); + $(".note-form-holder").replaceWith("#{escape_javascript(render('form'))}"); diff --git a/app/views/notes/_create_line.js.haml b/app/views/notes/_create_line.js.haml index 13809bec1b9..662909f7967 100644 --- a/app/views/notes/_create_line.js.haml +++ b/app/views/notes/_create_line.js.haml @@ -1,7 +1,7 @@ - if note.valid? :plain $(".per_line_form").hide(); - $('#new_note textarea').val(""); + $('.line-note-form-holder textarea').val(""); $("a.line_note_reply_link[line_code='#{note.line_code}']").closest("tr").remove(); var trEl = $(".#{note.line_code}").parent(); trEl.after("#{escape_javascript(render partial: "notes/per_line_show", locals: {note: note})}"); diff --git a/app/views/notes/_form.html.haml b/app/views/notes/_form.html.haml index 50829a97103..7211a0ae471 100644 --- a/app/views/notes/_form.html.haml +++ b/app/views/notes/_form.html.haml @@ -1,38 +1,39 @@ -= form_for [@project, @note], remote: "true", multipart: true do |f| - %h3.page_title Leave a comment - -if @note.errors.any? - .alert-message.block-message.error - - @note.errors.full_messages.each do |msg| - %div= msg +.note-form-holder + = form_for [@project, @note], remote: "true", multipart: true do |f| + %h3.page_title Leave a comment + -if @note.errors.any? + .alert-message.block-message.error + - @note.errors.full_messages.each do |msg| + %div= msg - = f.hidden_field :noteable_id - = f.hidden_field :noteable_type - = f.text_area :note, size: 255 - #preview-note.preview_note.hide - .hint - .right Comments are parsed with #{link_to "Gitlab Flavored Markdown", help_markdown_path, target: '_blank'}. - .clearfix + = f.hidden_field :noteable_id + = f.hidden_field :noteable_type + = f.text_area :note, size: 255, class: 'note-text' + #preview-note.preview_note.hide + .hint + .right Comments are parsed with #{link_to "Gitlab Flavored Markdown", help_markdown_path, target: '_blank'}. + .clearfix - .row.note_advanced_opts.hide - .span3 - = f.submit 'Add Comment', class: "btn success submit_note grouped", id: "submit_note" - = link_to 'Preview', preview_project_notes_path(@project), class: 'btn grouped', id: 'preview-link' - .span4.notify_opts - %h6.left Notify via email: - = label_tag :notify do - = check_box_tag :notify, 1, @note.noteable_type != "Commit" - %span Project team + .row.note_advanced_opts.hide + .span3 + = f.submit 'Add Comment', class: "btn success submit_note grouped", id: "submit_note" + = link_to 'Preview', preview_project_notes_path(@project), class: 'btn grouped', id: 'preview-link' + .span4.notify_opts + %h6.left Notify via email: + = label_tag :notify do + = check_box_tag :notify, 1, @note.noteable_type != "Commit" + %span Project team - - if @note.notify_only_author?(current_user) - = label_tag :notify_author do - = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit" - %span Commit author - .span5.attachments - %h6.left Attachment: - %span.file_name File name... + - if @note.notify_only_author?(current_user) + = label_tag :notify_author do + = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit" + %span Commit author + .span5.attachments + %h6.left Attachment: + %span.file_name File name... - .input.input_file - %a.file_upload.btn.small Upload File - = f.file_field :attachment, class: "input-file" - %span.hint Any file less than 10 MB + .input.input_file + %a.file_upload.btn.small Upload File + = f.file_field :attachment, class: "input-file" + %span.hint Any file less than 10 MB diff --git a/app/views/notes/_per_line_form.html.haml b/app/views/notes/_per_line_form.html.haml index afb0b30dca3..b6d34a0437f 100644 --- a/app/views/notes/_per_line_form.html.haml +++ b/app/views/notes/_per_line_form.html.haml @@ -1,33 +1,34 @@ %table{style: "display:none;"} %tr.per_line_form %td{colspan: 3 } - = form_for [@project, @note], remote: "true", multipart: true do |f| - %h3.page_title Leave a note - %div.span10 - -if @note.errors.any? - .alert-message.block-message.error - - @note.errors.full_messages.each do |msg| - %div= msg + .line-note-form-holder + = form_for [@project, @note], remote: "true", multipart: true do |f| + %h3.page_title Leave a note + %div.span10 + -if @note.errors.any? + .alert-message.block-message.error + - @note.errors.full_messages.each do |msg| + %div= msg - = f.hidden_field :noteable_id - = f.hidden_field :noteable_type - = f.hidden_field :line_code - = f.text_area :note, size: 255 - .note_actions - .buttons - = f.submit 'Add note', class: "btn primary submit_note", id: "submit_note" - = link_to "Cancel", "#", class: "btn hide-button" - .options - %h6.left Notify via email: - .labels - = label_tag :notify do - = check_box_tag :notify, 1, @note.noteable_type != "Commit" - %span Project team + = f.hidden_field :noteable_id + = f.hidden_field :noteable_type + = f.hidden_field :line_code + = f.text_area :note, size: 255, class: 'line-note-text' + .note_actions + .buttons + = f.submit 'Add note', class: "btn primary submit_note submit_inline_note", id: "submit_note" + = link_to "Cancel", "#", class: "btn hide-button" + .options + %h6.left Notify via email: + .labels + = label_tag :notify do + = check_box_tag :notify, 1, @note.noteable_type != "Commit" + %span Project team - - if @note.notify_only_author?(current_user) - = label_tag :notify_author do - = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit" - %span Commit author + - if @note.notify_only_author?(current_user) + = label_tag :notify_author do + = check_box_tag :notify_author, 1 , @note.noteable_type == "Commit" + %span Commit author :javascript $(function(){ diff --git a/doc/development.md b/doc/development.md new file mode 100644 index 00000000000..55be2bc32f2 --- /dev/null +++ b/doc/development.md @@ -0,0 +1,45 @@ +## Development tips: + +### Start application in development mode + +#### 1. Via foreman + + bundle exec foreman -p 3000 + +#### 2. Via gitlab cli + + ./gitlab start + +#### 3. Manually + + bundle exec rails s + bundle exec rake environment resque:work QUEUE=* VVERBOSE=1 + + +### Run tests: + +#### 1. Packages + + # ubuntu + sudo apt-get install libqt4-dev libqtwebkit-dev + sudo apt-get install xvfb + + # Mac + brew install qt + brew install xvfb + +#### 2. DB & seeds + + bundle exec rake db:setup RAILS_ENV=test + bundle exec rake db:seed_fu RAILS_ENV=test + +### 3. Run Tests + + # All in one + bundle exec gitlab:test + + # Rspec + bundle exec rake spec + + # Cucumber + bundle exec rake cucumber diff --git a/gitlab b/gitlab index 12cebd89891..acafb3f10c4 100755 --- a/gitlab +++ b/gitlab @@ -22,10 +22,11 @@ class GitlabCli case @mode when 'production'; system(unicorn_start_cmd) + system(resque_start_cmd) else system(rails_start_cmd) + system(resque_dev_start_cmd) end - system(resque_start_cmd) end def stop @@ -57,6 +58,10 @@ class GitlabCli "kill -QUIT `cat #{pid}`" end + def resque_dev_start_cmd + "./resque_dev.sh > /dev/null 2>&1" + end + def resque_start_cmd "./resque.sh > /dev/null 2>&1" end diff --git a/resque_dev.sh b/resque_dev.sh index b09cfd9e383..0f1d6edb41f 100755 --- a/resque_dev.sh +++ b/resque_dev.sh @@ -1 +1,2 @@ -bundle exec rake environment resque:work QUEUE=post_receive,mailer,system_hook VVERBOSE=1 +mkdir -p tmp/pids +bundle exec rake environment resque:work QUEUE=post_receive,mailer,system_hook VVERBOSE=1 PIDFILE=tmp/pids/resque_worker.pid RAILS_ENV=development BACKGROUND=yes