Skip to content

Commit

Permalink
Merge branch 'master' of github.com:hicknhack-software/redmine_time_t…
Browse files Browse the repository at this point in the history
…racker
  • Loading branch information
Lars Beier committed Jun 19, 2014
2 parents 32d8ec5 + fc78289 commit 2cc0393
Show file tree
Hide file tree
Showing 18 changed files with 265 additions and 197 deletions.
56 changes: 56 additions & 0 deletions app/assets/javascripts/field_updater.js.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
@redmine_time_tracker ?= {}
class @redmine_time_tracker.FieldUpdater
@updateBookingHours: (name) ->
start = timeString2min($("#" + name + "_start_time").val())
stop = timeString2min($("#" + name + "_stop_time").val())

# if the stop-time is smaller than the start-time, we assume a booking over midnight
$("#" + name + "_spent_time").val min2timeString(stop + ((if stop < start then 1440 else 0)) - start)

@updateBookingStop: (name) ->
start = timeString2min($("#" + name + "_start_time").val())
spent_time = timeString2min($("#" + name + "_spent_time").val())
$("#" + name + "_stop_time").val min2parsedTimeString((start + spent_time) % 1440)

@updateBookingProject: (name) ->
issue_id_field = $("#" + name + "_issue_id")
project_id_field = $("#" + name + "_project_id")
project_id_select = $("#" + name + "_project_id_select")
issue_id = issue_id_field.val()

# check if the string is blank
if not issue_id or $.trim(issue_id) is ""
project_id_select.attr "disabled", false
issue_id_field.removeClass "invalid"
else
$.ajax
url: redmine_time_tracker.TimeTracker.base_url() + "issues/" + issue_id + ".json?key=" + current_user_api_key()
type: "GET"
success: (transport) =>
issue_id_field.removeClass "invalid"
issue = transport.issue
unless issue?
project_id_select.attr "disabled", false
else
project_id_select.attr "disabled", true
project_id_field.val issue.project.id
$("#" + project_id_select.attr("id"))
.val(issue.project.id)
.trigger('change')
@updateBookingActivity name

error: ->
project_id_select.attr "disabled", false
issue_id_field.addClass "invalid"

@updateBookingActivity: (name) ->
$.ajax
url: redmine_time_tracker.TimeTracker.base_url() + "tt_completer/get_activity.json?key=" + current_user_api_key() + "&project_id=" + $("#" + name + "_project_id").val()
type: "GET"
success: (activites) =>
activity_field = $("#" + name + "_activity_id_select")
selected_activity = activity_field.find("option:selected").text()
activity_field.find("option[value!=\"\"]").remove()
$.each activites, (i, activity) ->
activity_field.append "<option value=\"" + activity.id + "\">" + activity.name + "</option>"
activity_field.val activity.id if selected_activity is activity.name
26 changes: 26 additions & 0 deletions app/assets/javascripts/time_tracker2.js.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@redmine_time_tracker ?= {}
class @redmine_time_tracker.TimeTracker
@hideMultiFormButtons: (button_class) ->
last = $("input.#{button_class}").parent().parent().last().index()
$("input." + button_class).each ->
unless last is $(@).parent().parent().index()
$(this).hide()
else
$(this).show()

@base_url: ->
src = $("link[href*=\"time_tracker.css\"]")[0].href
src.substr 0, src.indexOf("plugin_assets")

$ ->
$(document).on "ajax:success", ".tt_stop, .tt_start, .tt_dialog_stop", (xhr, html, status) ->
$("#content .flash").remove()
$("#content").prepend html

$(document).on "ajax:success", ".tt_stop, .tt_start, .tt_dialog_stop", (xhr, html, status) ->
$("#content .flash").remove()
$("#content").prepend html

$(document).on "ajax:success", ".tt_stop, .tt_start, .tt_dialog_stop", (xhr, html, status) ->
$("#content .flash").remove()
$("#content").prepend html
105 changes: 105 additions & 0 deletions app/assets/javascripts/validators.js.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
@redmine_time_tracker ?= {}
class @redmine_time_tracker.FormValidator
constructor: (@form)->

validate: ->
@_clean_up()
@_do_validation()
@_update_submit_button_state()

_do_validation: ->
#do stuff

_clean_up: ->
@_invalid_form_inputs().removeClass 'invalid'

_validates_presence_of: (element) ->
@_validates element, element.val() isnt ''

_validates: (element, condition) ->
element.addClass 'invalid' unless condition

_form_is_invalid: ->
@_invalid_form_inputs().length > 0

_invalid_form_inputs: ->
@form.find(':input.invalid')

_update_submit_button_state: ->
@form.find(':submit').attr 'disabled', @_form_is_invalid()

class @redmine_time_tracker.ListInputValidator extends @redmine_time_tracker.FormValidator
constructor: (name)->
@start_field = $("#" + name + "_start_time")
@stop_field = $("#" + name + "_stop_time")
@spent_field = $("#" + name + "_spent_time")
super @start_field.closest "form"

_do_validation: ->
@_validates_presence_of @start_field
@_validates_presence_of @stop_field
@_validates_presence_of @spent_field
super

class @redmine_time_tracker.EditTimeLogValidator extends @redmine_time_tracker.ListInputValidator
constructor: (name) ->
@date_field = $("#" + name + "_tt_log_date")
super name

_do_validation: () ->
@_validates_presence_of @date_field
super

class @redmine_time_tracker.AddBookingValidator extends @redmine_time_tracker.ListInputValidator
constructor: (name) ->
@proj_id_field = $("#" + name + "_project_id")
@proj_select = $("#" + name + "_project_id_select")
@activity_select = $("#" + name + "_activity_id_select")
@max_time_field = $("#" + name + "_max_time")
@min_time_field = $("#" + name + "_min_time")
@max_spent_time_field = $("#" + name + "_max_spent_time")
super name

_do_validation: () ->
@_validates_presence_of @proj_select
@_validates_presence_of @activity_select

start = timeString2min(@start_field.val())
min_time = timeString2min(@min_time_field.val())
stop = timeString2min(@stop_field.val())
max_time = timeString2min(@max_time_field.val())
spent_time = timeString2min(@spent_field.val())
max_spent_time = timeString2min(@max_spent_time_field.val())

@_validates @spent_field, spent_time <= max_spent_time
if max_spent_time < 1440
if min_time > max_time
@_validates @start_field, not (max_time <= start < min_time)
@_validates @stop_field, not (max_time < stop <= min_time)
else
@_validates @start_field, min_time <= start < max_time
@_validates @stop_field, min_time < stop <= max_time
super

class @redmine_time_tracker.EditBookingValidator extends @redmine_time_tracker.AddBookingValidator
constructor: (name) ->
@date_field = $("#" + name + "_tt_booking_date")
@valid_dates = $("#" + name + "_valid_dates").val().split("|")
super name

_do_validation: () ->
@_validates_presence_of @date_field
@_validates @date_field, not ($.inArray(@date_field.val(), @valid_dates) is -1)
super

class @redmine_time_tracker.TimeTrackerFormValidator extends @redmine_time_tracker.FormValidator
constructor: ->
@proj_field = $('#time_tracker_project_id')
@activity_select = $('#time_tracker_activity_id')
super $('.time-tracker-form')

_do_validation: () ->
proj_id = @proj_field.val()
activity_id = @activity_select.val()
@_validates @activity_select, proj_id is "" or activity_id isnt ""
super
2 changes: 1 addition & 1 deletion app/controllers/time_logs_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def delete
if item.time_bookings.count == 0
item.destroy
else
raise StandardError, l(:tt_error_not_allowed_to_delete_logs)
raise StandardError, l(:tt_error_not_possible_to_delete_logs)
end
else
flash[:error] = l(:tt_error_not_allowed_to_delete_logs)
Expand Down
14 changes: 7 additions & 7 deletions app/views/time_bookings/_edit_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<div class="input_hint"><%= l(:field_tt_date) %></div>
<div class="task_form_input">
<%= hidden_field_tag "time_booking_edit_#{time_booking.id}_valid_dates", [time_booking.time_log.tt_log_date, time_booking.time_log.tt_log_stop_date].join('|') %>
<%= f.text_field :tt_booking_date, :size => "10", :placeholder => "date", :readonly => time_booking.permission_level < 2, :onchange => "validate_list_inputs('time_booking_edit_#{time_booking.id}');" %>
<%= f.text_field :tt_booking_date, :size => "10", :placeholder => "date", :readonly => time_booking.permission_level < 2%>
<% unless time_booking.permission_level < 2 %>
<%= javascript_tag("$(function() { $('#time_booking_edit_#{time_booking.id.to_s}_tt_booking_date').datepicker(locDatepickerOptions); });") %>
<% end %>
Expand All @@ -25,7 +25,7 @@
<div class="task_form_sub_fields">
<div class="input_hint"><%= l(:time_tracker_label_project) %></div>
<div class="task_form_input">
<%= select_tag "time_booking_edit_#{time_booking.id}_project_id_select", proj_list, :onchange => "$('#time_booking_edit_#{time_booking.id}_project_id').val(this.value); validate_list_inputs('time_booking_edit_#{time_booking.id}'); updateBookingActivity('#{User.current.api_key}', 'time_booking_edit_#{time_booking.id}')", :disabled => (time_booking.permission_level < 1 || time_booking.issue_id != l(:time_tracker_label_none)) %>
<%= select_tag "time_booking_edit_#{time_booking.id}_project_id_select", proj_list, data: {updater: 'updateBookingActivity'}, :onchange => "$('#time_booking_edit_#{time_booking.id}_project_id').val(this.value)", :disabled => (time_booking.permission_level < 1 || time_booking.issue_id != l(:time_tracker_label_none)) %>
</div>
<%= f.hidden_field :project_id %>
</div>
Expand All @@ -34,13 +34,13 @@
<div class="input_hint"><%= l(:time_tracker_label_activity) %></div>
<div class="task_form_input">
<% activities = get_activities time_booking.project_id %>
<%= select_tag "time_booking_edit_#{time_booking.id}_activity_id_select", options_from_collection_for_select(activities, :id, :name, time_booking.activity_id),:onchange => "validate_list_inputs('time_booking_edit_#{time_booking.id}');", :name=> "time_booking_edit[#{time_booking.id}][activity_id]", :include_blank => true%>
<%= select_tag "time_booking_edit_#{time_booking.id}_activity_id_select", options_from_collection_for_select(activities, :id, :name, time_booking.activity_id), :name=> "time_booking_edit[#{time_booking.id}][activity_id]", :include_blank => true%>
</div>
</div>

<div class="task_form_sub_fields">
<div class="input_hint"><%= l(:time_tracker_label_issue) %></div>
<div class="task_form_input"><%= f.text_field :issue_id, :size => "15", :placeholder => "issue", :onchange => "updateBookingProject('#{User.current.api_key}', 'time_booking_edit_#{time_booking.id}')", :readonly => time_booking.permission_level < 1 %></div>
<div class="task_form_input"><%= f.text_field :issue_id, :size => "15", :placeholder => "issue", data: {updater: 'updateBookingProject'}, :readonly => time_booking.permission_level < 1 %></div>
</div>

<div class="task_form_sub_fields">
Expand All @@ -52,23 +52,23 @@
<div class="input_hint"><%= l(:time_tracker_label_start_time) + " (min: #{time_booking.time_log.get_formatted_start_time})" %></div>
<div class="task_form_input">
<%= hidden_field_tag "time_booking_edit_#{time_booking.id}_min_time", time_booking.time_log.get_formatted_start_time %>
<%= f.text_field :start_time, :value => time_booking.get_formatted_start_time, :size => "10", :placeholder => "start", :onchange => "updateBookingHours('time_booking_edit_#{time_booking.id}')", :readonly => time_booking.permission_level < 2 %>
<%= f.text_field :start_time, :value => time_booking.get_formatted_start_time, :size => "10", :placeholder => "start", data: {updater: 'updateBookingHours'}, :readonly => time_booking.permission_level < 2 %>
</div>
</div>

<div class="task_form_sub_fields">
<div class="input_hint"><%= l(:time_tracker_label_stop_time) + " (max: #{time_booking.time_log.get_formatted_stop_time})" %></div>
<div class="task_form_input">
<%= hidden_field_tag "time_booking_edit_#{time_booking.id}_max_time", time_booking.time_log.get_formatted_stop_time %>
<%= f.text_field :stop_time, :value => time_booking.get_formatted_stop_time, :size => "10", :placeholder => "stop", :onchange => "updateBookingHours('time_booking_edit_#{time_booking.id}')", :readonly => time_booking.permission_level < 2 %>
<%= f.text_field :stop_time, :value => time_booking.get_formatted_stop_time, :size => "10", :placeholder => "stop", data: {updater: 'updateBookingHours'}, :readonly => time_booking.permission_level < 2 %>
</div>
</div>

<div class="task_form_sub_fields">
<div class="input_hint"><%= l(:time_tracker_label_time_spent) + " (max: #{help.time_dist2string(((time_booking.time_log.bookable_hours + time_booking.hours_spent) * 60).to_i)})" %></div>
<div class="task_form_input">
<%= hidden_field_tag "time_booking_edit_#{time_booking.id}_max_spent_time", help.time_dist2string(((time_booking.time_log.bookable_hours + time_booking.hours_spent) * 60).to_i) %>
<%= f.text_field :spent_time, :value => time_booking.get_formatted_time, :size => "12", :placeholder => "spent time", :onchange => "updateBookingStop('time_booking_edit_#{time_booking.id}')", :readonly => time_booking.permission_level < 2 %>
<%= f.text_field :spent_time, :value => time_booking.get_formatted_time, :size => "12", :placeholder => "spent time", data: {updater: 'updateBookingStop'}, :readonly => time_booking.permission_level < 2 %>
</div>
</div>

Expand Down
4 changes: 2 additions & 2 deletions app/views/time_bookings/_edit_form_autocomplete.js.erb
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ $(function () {
minLength:0,
select:function (event, ui) {
$('#time_booking_edit_<%= time_booking.id.to_s %>_issue_id').val(ui.item.value);
updateBookingProject('<%= key %>', 'time_booking_edit_<%= time_booking.id.to_s %>');
redmine_time_tracker.FieldUpdater.updateBookingProject('time_booking_edit_<%= time_booking.id.to_s %>');
}
});
});

$(document).ready(function() {
validate_list_inputs('time_booking_edit_<%= time_booking.id.to_s %>');
(new redmine_time_tracker.EditBookingValidator('time_booking_edit_<%= time_booking.id.to_s %>')).validate();
});
<% end %>
2 changes: 1 addition & 1 deletion app/views/time_bookings/get_list_entry.js.erb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
$('#<%= "booking-entry-" + @entry.id.to_s %>').html('<%= escape_javascript(render(:partial => 'time_bookings/list_entry', :locals => {:entry => @entry, :query => @query_bookings, :button => :book})) %>');
contextMenuHide();
contextMenuUnselectAll();
hideMultiFormButtons('tb_edit_form_update_button');
redmine_time_tracker.TimeTracker.hideMultiFormButtons('tb_edit_form_update_button');
19 changes: 14 additions & 5 deletions app/views/time_bookings/show_edit.js.erb
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
<% @time_bookings.each do |item| %>

$('#<%= "booking-entry-" + item.id.to_s %>').html('<%= escape_javascript(render(:partial => 'time_bookings/edit_form', :locals => {:time_booking => item})) %>');

<% @time_bookings.each do |time_booking| %>
var name = 'time_booking_edit_<%=time_booking.id%>';
var $entry = $('#<%="booking-entry-#{time_booking.id}"%>')
.html('<%=j render(:partial => 'time_bookings/edit_form', :locals => {:time_booking => time_booking})%>')
.removeClass('hascontextmenu');
var validator = new redmine_time_tracker.EditBookingValidator(name);
$entry.on('change', 'input, select', function () {
validator.validate();
var updater = $(this).data('updater');
if (updater != null && updater != '') {
redmine_time_tracker.FieldUpdater[updater](name)
}
});
<% end %>
contextMenuHide();
contextMenuUnselectAll();
hideMultiFormButtons('tb_edit_form_update_button');
redmine_time_tracker.TimeTracker.hideMultiFormButtons('tb_edit_form_update_button');

0 comments on commit 2cc0393

Please sign in to comment.