Skip to content

Instantly share code, notes, and snippets.

@pavelgordon
Last active August 2, 2016 07:28
Show Gist options
  • Save pavelgordon/4ebebc81c8a8d63c02e4d3403f20e1dd to your computer and use it in GitHub Desktop.
Save pavelgordon/4ebebc81c8a8d63c02e4d3403f20e1dd to your computer and use it in GitHub Desktop.
#
# Main file.
# Contains entry point
#
# @nodoc
previously_selected = undefined
# @nodoc
columns = []
# @nodoc
commentsPlugin = undefined
# @nodoc
hot = undefined
# @nodoc
table_data = undefined
# @nodoc
pad = (str, max) ->
str = str.toString()
if str.length < max then pad('0' + str, max) else str
# @nodoc
# @nodoc
days = []
# @nodoc
widths = []
# @nodoc
cells = 35
# @nodoc
$("#year").change ->
window.location.href = window.location.href.replace(/calendars[/]\d{4}/, 'calendars/' + $("#year option:selected").val())
@log_table_data = ()->
console.log table_data
# @nodoc
i = 1
# @nodoc
while i <= lastDayOfMonth(currentMonth, currentYear)
day = new Date(currentYear, currentMonth - 1, i).getDay()
if day == 0 or day == 6
days.push '<strong style="color:#FF0000">' + i + '</strong>'
else
days.push i
widths.push cells
columns.push {data: i}
i++
columns.push {data: "total hours", editor: false}
days.push "hours"
widths.push 50
#
# Entry point
# Fetches data from server
#
$ ->
$('.nav-pills, .nav-tabs').tabdrop()
monthSelect = $('#month-select li:not(.dropdown)')
$.each monthSelect, (i) ->
$(this).click () ->
box = $('.box')
start_width = box.width()
$('#extra').slideUp 100, () ->
end_width = box.width() + 20
box.width start_width
box.animate {width: end_width},
duration: 60
monthSelect.filter('.active').removeClass 'active'
$(this).addClass 'active'
$('#filters').slideUp 50
$('#loading').fadeIn 200
table_data = new TableData []
init_metadata()
fetch_cells_data = ()->
$.ajax
type: 'GET',
dataType: "json",
url: '/calendars/data',
data: {
month: currentMonth,
year: currentYear
}
success: (projects_data) ->
table_data.load_from_json projects_data
console.log 'fetched_data:', projects_data
init_hot(projects_data)
init_filters()
# Set custom scroll and restore scroll position
scroll_pos = $.cookie 'lastCalendarsPosition'
if scroll_pos != undefined and scroll_pos > 0
$('.wtHolder').scrollTop(scroll_pos)
hot.updateSettings {height: tableHeightByLength(hot.getData().length)}
error: (q, status, err)->
document.getElementById("status-line").innerHTML = I18n.t('extra.error')
console.err 'Failed fetching cells data'
console.err q, status, err
init_metadata = (callback)->
$.ajax
type: 'GET',
dataType: "json",
url: '/calendars/metadata',
success: (metadata) ->
#console.log "metadata", metadata
Extradata.events = metadata['events']
Extradata.holidays = metadata['holidays'].map (x) -> x['day']
fetch_cells_data()
error: (q, status,err) ->
console.log q,status,err
#
# Init filters
#
emp_filt = ''
proj_filt = []
init_filters = () ->
$('#filter-form').submit (e) ->
false
# Init projects filetr
projects_filter = $('#projects-filter')
projects_filter.empty()
table_data.get_projects().forEach (project_name) ->
# removing <b> tag around <b>PRJNAME</b>
proj_filt.push project_name.substring(3, project_name.length - 4)
projects_filter.append('<option>' + project_name + '</option>')
filtrate_proj = () ->
proj_filt = $('#projects-filter option:selected').toArray().map((val) -> val.value)
deselected = $('#projects-filter option:not(:selected)').toArray().map((val) -> val.value)
$.cookie 'deselectedProj', JSON.stringify deselected, {path: '/'}
filtrate(emp_filt, proj_filt)
projects_filter.multiselect({
maxHeight: 300,
onDropdownHidden: (element, cheked) ->
filtrate_proj()
})
projects_filter.multiselect()
projects_filter.multiselect('selectAll', false)
if $.cookie('deselectedProj') == undefined
$.cookie 'deselectedProj', JSON.stringify [], {path: '/'}
deselected = $.cookie 'deselectedProj'
if deselected != undefined or deselected != []
deselected = JSON.parse deselected
deselected.forEach (elem) ->
projects_filter.multiselect('deselect', elem)
proj_filt = $('#projects-filter option:selected').toArray().map((val) ->
val.value)
projects_filter.multiselect('updateButtonText')
# Init employees filter
if $.cookie('filterQuery') == undefined
$.cookie 'filterQuery', '', {path: '/'}
search_field = $('#employee-filter')
emp_filt = $.cookie('filterQuery')
search_field.val(emp_filt)
search_field.keyup () ->
emp_filt = search_field.val()
sensitivity = 2
if emp_filt.length > sensitivity
filtrate(emp_filt, proj_filt)
else if $.cookie("filterQuery").length > sensitivity
filtrate('', proj_filt)
$.cookie "filterQuery", emp_filt, {path: '/'}
# If filters not empty show filter line
if emp_filt != '' or deselected.length > 0
filters_toggle()
filtrate(emp_filt, proj_filt)
# Init reset button
$('#reset-filter').click () ->
search_field.val ''
projects_filter.multiselect('selectAll', false)
projects_filter.multiselect('updateButtonText')
$.cookie 'filterQuery', '', {path: '/'}
filtrate_proj()
# Close filter panel button
$('#close-filter').click () ->
$('#filters').slideUp 100
#
# Update table size on window resize
#
$(window).resize ->
hot.updateSettings {
width: tableWidth()
height: tableHeightByLength(hot.getData().length)
}
#
# Magic calculations
#
# Height and width
tableHeightByLength = (rows_num) ->
maxTableHeight = $(window).height() - 235
filters_height = if $('#filters').is(':visible') then 44 else 0
hot_height = rows_num * 24 + 65
height = if hot_height + filters_height > maxTableHeight
hot_height - filters_height
else
hot_height
Math.min(height, maxTableHeight - filters_height)
tableHeight = () ->
tableHeightByLength(table_data.length())
tableWidth = () ->
window_width = $(window).width() - 50
Math.min(widths.length * cells + 199, window_width)
# Using to prevent callbacks from contextmenu on headers
prevent = (th) ->
$(th).contextmenu (e) ->
e.stopImmediatePropagation()
e.preventDefault()
e.stopPropagation()
return false
#
# Big init function
#
init_hot = (fetched_data)->
event_data = document.getElementById("extra")
# Need to set colWidths, width, colHeight, height manually because of slow scrolling bug
settings = {
data: table_data.to_json()
validator: hoursValidator
allowInvalid: false
columns: columns
colHeaders: days
rowHeaders: table_data.get_names()
comments: true
search: true
renderAllRows: true
fillHandle: false
width: tableWidth
height: tableHeight
colWidths: widths
colHeights: 30
maxRows: table_data.length()
cells: init_cell
customBorders: [{
range: {
from: {
row: 0,
col: columns.length - 1
},
to: {
row: table_data.length(),
col: columns.length - 1
}
},
left: {
width: 1,
color: 'black'
}
}]
beforeKeyDown: (e) ->
range = hot.getSelectedRange()
if range == undefined
return
selectedDays = range.getAll()
event_name = ""
selected_event = undefined
for event in Extradata.events
if event.hotkey.charCodeAt(0) - 32 == e.keyCode
selected_event = event # have to be stopped after finding first instance
break
if e.keyCode == 'q'.charCodeAt(0) - 32
e.isImmediatePropagationEnabled = false
e.cancelBubble = true
e.preventDefault()
console.log hot.getCell(selectedDays[0].row, selectedDays[0].col)
console.log hot.getCellMeta(selectedDays[0].row, selectedDays[0].col)
# console.log hot.getCellAtCoords([selectedDays[0].row, selectedDays[0].col])
console.log hot.getCellRenderer(selectedDays[0].row, selectedDays[0].col)
console.log hot.getCellValidator(selectedDays[0].row, selectedDays[0].col)
console.log hot.getCellEditor(selectedDays[0].row, selectedDays[0].col)
console.log hot.getDataAtCell(selectedDays[0].row, selectedDays[0].col)
console.log hot.getSourceDataAtCell(selectedDays[0].row, selectedDays[0].col)
return
if selected_event == undefined # no event for such letter
return
e.isImmediatePropagationEnabled = false
e.cancelBubble = true
e.preventDefault()
if selected_event.hotkey.charCodeAt(0) - 32 == 67 # it is clear event
deleteEvents selectedDays
else
setEvents selectedDays, selected_event.id
hot.render()
afterSelectionEnd: (r, c, r2, c2) ->
console.log('afterSelectionEnd');
resetOnCallDuty()
previously_selected = { r: r, c: c, r2: r2, c2: c2 }
updateSumSelected(r, c, r2, c2)
for row_index in [r..r2]
for column in [c..c2]
row = table_data.get_row_by_index(row_index)
day = row.get_day(column + 1)
# If day Event is not On Call Duty
if day == undefined || day.event_id != 3
console.log('miss')
continue
cell_meta = hot.getCellMeta row_index, column
cell_meta.validator = onCallValidator
hot.setDataAtCell row_index, column, "#{day.passive}:#{day.active}", 'donothing'
afterDeselect: () ->
console.log('afterDeselect')
resetOnCallDuty()
previously_selected = undefined
beforeRender: ()->
remove_week_numbers()
afterRender: ()->
append_week_numbers()
beforeChange: (changes, source) ->
console.log("before_changes", source)
if (!changes) || source == 'donothing'
return
for change in changes
console.log change
row_number = change[0]
day_number = change[1]
old_value = change[2] # previous hours in cell
new_value = change[3] # new hours in cell
if new_value == old_value
continue
# if old value and new value are empty
if (old_value == undefined or old_value == '' or old_value == null ) and (new_value == undefined or new_value == '' or new_value == null )
continue
document.getElementById("status-line").innerHTML = I18n.t('extra.saving')
row = table_data.get_row_by_index(row_number)
day = row.get_day day_number
#oncallduty
if day.event_id == 3
if new_value == '' or new_value == undefined
day.active = undefined
day.passive = undefined
else
arr = new_value.split ':'
day.active = parseInt arr[1]
day.passive = parseInt arr[0]
row.update_day_hours day, (day.active+day.passive)
updateSumSelected(row_number,day_number-1,row_number,day_number-1 )
$.ajax
type: 'POST'
url: '/calendars/save_on_call_duty_hours'
dataType: 'json',
data: {
update: JSON.stringify {
employee_project_id: row.id,
occurs: "#{currentYear}-#{currentMonth}-#{day_number}",
hours: new_value
}
}
success: (data) ->
document.getElementById("status-line").innerHTML = I18n.t('extra.all_saved')
failure: (errMsg) ->
alert errMsg
else
# setting hours empty
if isNaN(new_value) || new_value == ''
new_value = null
res = row.update_day_hours day
#changes[0][3] = res;
else
new_value = parseFloat new_value
res = row.update_day_hours day, new_value
changes[0][3] = res;
# Need this when cell hours is simply deleted by Del/Backspace
updateSumSelected(row_number,day_number-1,row_number,day_number-1 )
hot.render()
update = {
employee_project_id: row.id,
occurs: currentYear + "-" + currentMonth + "-" + day_number,
hours: new_value
}
console.log 'change hours'
#TODO if not success then change to old value
$.ajax
type: 'POST'
url: '/calendars/save_hours'
dataType: 'json',
data: {
update: JSON.stringify(update)
}
success: (data) ->
document.getElementById("status-line").innerHTML = I18n.t('extra.all_saved')
failure: (errMsg) ->
alert errMsg
afterSetCellMeta: (row_number, col_number, key, value)->
if key == 'comment'
addedit_comment row_number, col_number, value
afterGetRowHeader: (row, th) ->
prevent(th)
afterGetColHeader: (row, th) ->
prevent(th)
}
# This function restores previously changed by selecting data on
# 'On Call Duty' cells
resetOnCallDuty = () ->
console.log('resetOnCallDuty is called....')
if previously_selected == undefined
console.log('and returned cause of previously_selected undefined')
return
console.log('and continue')
for row_index in [previously_selected.r..previously_selected.r2]
for column in [previously_selected.c..previously_selected.c2]
row = table_data.get_row_by_index(row_index)
day = row.get_day(column + 1)
# If day Event is not On Call Duty
if day == undefined || day.event_id != 3 || day.active == undefined || day.passive == undefined
continue
# Update data if something is changed
cell_meta = hot.getCellMeta row_index, column
cell_meta.validator = undefined
hot.setDataAtCell row_index, column, "#{day.passive + day.active}", 'donothing'
hot = new Handsontable(event_data, settings )
hot.updateSettings
contextMenu:
callback: contextmenu_callback
items: createContextMenuItems()
for k in [0...table_data.rows.length]
row = table_data.get_row_by_index(k);
for j in [0...row.data.length]
cell = row.get_day(j + 1)
if (cell.activity)
draw_activity k, j, 'darkblue'
commentsPlugin = hot.getPlugin('comments');
box = $('.box')
end_width = box.width()
$('#extra').hide()
start_width = box.width() + 50
box.width start_width
box.animate {width: end_width},
complete: () ->
$('#loading').fadeOut 100
box.width 'auto'
$('#extra').slideDown 100
duration: 60
# Init with commentaries and events.
# Triggered when hot.render()
init_cell = (row_number, col_number, prop) ->
if row_number == undefined || col_number == undefined
return
day_number = col_number + 1
row = table_data.get_row_by_index row_number
if row == undefined
return
day = row.get_day day_number
cellProperties = {}
# if col_number is last column( with total hours)
if col_number == columns.length - 1
if row.type == 'project' #TODO replace by IS_PROJECT
cellProperties.renderer = Extra.projectHighlight.renderer
cellProperties.readOnly = true
else
cellProperties.renderer = Extra.totalHours.renderer table_data
return cellProperties
# possibly bug merge fired and maternity
if (row['end_day'] != undefined && col_number >= row['end_day']) ||
(row['start_day'] != undefined && col_number + 2 <= row['start_day'])
return {
renderer: Extra.fired.renderer
editor: false
readOnly: true
}
if row['maternity']['exists']
if (row['maternity']['start'] && (day['day'] in [row['maternity']['index']..lastDayOfMonth(currentMonth, currentYear)])) ||
(!row['maternity']['start'] && (day['day'] in [1..row['maternity']['index']]))
cellProperties.renderer = Extra.maternity.renderer
return cellProperties
cellProperties.comment = day.comment
cellProperties.renderer = switch day.event_id
when m_events.BUSINESS_TRIP then Extra.businesstrip.renderer
when m_events.ON_CALL_DUTY then Extra.oncallduty.renderer
when m_events.OVERTIME_WORK then Extra.overtimework.renderer
when m_events.SICK_LEAVE then Extra.sickleave.renderer
when m_events.VACATION then Extra.vacation.renderer
when m_events.UNPAID_LEAVE then Extra.unpaidleave.renderer
when m_events.HOME_OFFICE then Extra.homeoffice.renderer
if day.event_id == undefined || day.event_id == null
if day_number in getWeekends(currentYear, currentMonth)
cellProperties.renderer = Extra.highlightWeekends.renderer
if day_number in Extradata.holidays
cellProperties.renderer = Extra.highlightHolidays.renderer
if row.type == 'project' #TODO replace by IS_PROJECT
cellProperties.renderer = Extra.projectHighlight.renderer
cellProperties
# Set activity by means of drawing border for cell with given coordinates
# @param [Integer] row
# @param [Integer] column
# @param [String] color
draw_activity = (row, column, color) ->
customBorders = [ {
range:
from:
row: row
col: column
to:
row: row
col: column
top:
width: 1.5
color: color
left:
width: 1.5
color: color
bottom:
width: 1.5
color: color
right:
width: 1.5
color: color
} ]
getSettingIndex = (className) ->
k = 0
while k < hot.view.wt.selections.length
if hot.view.wt.selections[k].settings.className == className
return k
k++
-1
insertBorderIntoSettings = (border) ->
coordinates =
row: border.row
col: border.col
selection = new WalkontableSelection(border, new WalkontableCellRange(coordinates, coordinates, coordinates))
index = getSettingIndex(border.className)
if index >= 0
hot.view.wt.selections[index] = selection
else
hot.view.wt.selections.push selection
return
createSingleEmptyBorder = ->
{ hide: true }
createDefaultHtBorder = ->
{
width: 1
color: '#000'
cornerVisible: false
}
createEmptyBorders = (row, col) ->
{
className: 'border_row' + row + 'col' + col
border: createDefaultHtBorder()
row: row
col: col
top: createSingleEmptyBorder()
right: createSingleEmptyBorder()
bottom: createSingleEmptyBorder()
left: createSingleEmptyBorder()
}
prepareBorderFromCustomAddedRange = (rowObj) ->
range = rowObj.range
row = range.from.row
while row <= range.to.row
col = range.from.col
while col <= range.to.col
border = createEmptyBorders(row, col)
add = 0
if row == range.from.row
add++
if rowObj.hasOwnProperty('top')
border.top = rowObj.top
if row == range.to.row
add++
if rowObj.hasOwnProperty('bottom')
border.bottom = rowObj.bottom
if col == range.from.col
add++
if rowObj.hasOwnProperty('left')
border.left = rowObj.left
if col == range.to.col
add++
if rowObj.hasOwnProperty('right')
border.right = rowObj.right
if add > 0
@setCellMeta row, col, 'borders', border
insertBorderIntoSettings border
col++
row++
return
instance = hot
prepareBorderFromCustomAddedRange.call instance, customBorders[0]
instance.render()
instance.view.wt.draw true
instance.customBorders = customBorders
prepareBorderFromCustomAddedRange.call hot, customBorders[0]
hot.render()
hot.view.wt.draw true
hot.customBorders = customBorders
return
# Remove border for cell with empty activity list
# @param [Integer] row
# @param [Integer] column
remove_activity = (row, column) ->
removeAllBorders = (row, col) ->
borderClassName = 'border_row' + row + 'col' + col
removeBordersFromDom(borderClassName)
@removeCellMeta(row, col, 'borders')
return
removeBordersFromDom = (borderClassName) ->
borders = document.querySelectorAll('.' + borderClassName)
for k in [0..borders.length]
if (borders[k])
if (borders[k].nodeName != 'TD')
parent = borders[k].parentNode
if (parent.parentNode)
parent.parentNode.removeChild(parent);
return
removeAllBorders.call hot, row, column
hot.render()
hot.view.wt.draw true
return
Element::remove = ->
@parentElement.removeChild this
return
NodeList::remove =
HTMLCollection::remove = ->
k = @length - 1
while k >= 0
if @[k] and @[k].parentElement
@[k].parentElement.removeChild @[k]
k--
return
#
# Set color for cell with given coordinates
# @param [Integer] row
# @param [Integer] col
# @param [Integer] event_id
# @param [String] row_type type of row, can be "project" or "employee_project"
# accepts column (0..29)
@color = (row, col, event_id, row_type)->
cell = hot.getCellMeta(row, col)
day_number = col + 1
if event_id == undefined || event_id == null
if day_number in getWeekends(currentYear, currentMonth)
cell.renderer = Extra.highlightWeekends.renderer
if day_number in Extradata.holidays
cell.renderer = Extra.highlightHolidays.renderer
else
cell.renderer = switch event_id
when m_events.BUSINESS_TRIP then Extra.businesstrip.renderer
when m_events.ON_CALL_DUTY then Extra.oncallduty.renderer
when m_events.OVERTIME_WORK then Extra.overtimework.renderer
when m_events.SICK_LEAVE then Extra.sickleave.renderer
when m_events.VACATION then Extra.vacation.renderer
when m_events.UNPAID_LEAVE then Extra.unpaidleave.renderer
when m_events.HOME_OFFICE then Extra.homeoffice.renderer
if row_type == 'project' #TODO replace by IS_PROJECT
cell.renderer = Extra.projectHighlight.renderer
#
# Wrappers for using color function
#
colorize_cell_by_index = (row_index, col, event_id)->
row = table_data.get_row_by_index(row_index)
@color(row_index, col, event_id, row.type)
@colorize_cell = (row, col, event_id)->
t_row = table_data.get row
@color(row, col, event_id, t_row.type)
# Add or edit comment in cell with coordinates given
# @param [Integer] row_number
# @param [Integer] col_number
# @param [String] comment
addedit_comment = (row_number, col_number, comment)->
day_number = col_number + 1
day = table_data.get_day row_number, day_number
if comment == ''
day.comment = undefined
commentsPlugin.removeCommentAtCell(row_number, col_number);
else
day.comment = comment
update = {
employee_project_id: table_data.get_row_by_index(row_number).id,
occurs: currentYear + "-" + currentMonth + "-" + day_number
comment: comment
}
$.ajax
type: 'POST',
url: '/calendars/save_comment',
data: {
update: JSON.stringify(update)
}
success: (response)->
console.log response
error:(err)->
console.error err
#
# Delete comment in cell with coordinates given
# @param [Integer] row_number
# @param [Integer] col_number
@delete_comment = (row_number, col_number)->
log_comments "delete_comment", row_number, col_number
day_number = col_number + 1
day = table_data.get_day row_number, day_number
day.comment = null
commentsPlugin.removeCommentAtCell(row_number, col_number)
update = {
employee_project_id: table_data.get_row_by_index(row_number).id,
occurs: currentYear + "-" + currentMonth + "-" + day_number,
comment: ''
}
$.ajax
type: 'POST',
url: '/calendars/save_comment',
data: {
update: JSON.stringify(update)
}
success: (responce)->
console.log responce
error: (q, status, err)->
console.err q, status, err
# Set events to array of cells coordinates given
# @param [Array<WalkontableCellCoords>] selected_days - array of selected days
# @param event_id id of event to be set
setEvents = (selected_days, event_id) ->
update = {
event_id: event_id,
events: []
}
for selected_day in selected_days
unless validate_event(selected_day, event_id)
continue
current_row = table_data.get_row_by_index selected_day.row
if current_row.type == 'project'
continue
employee_project_id = current_row.id
day_number = selected_day.col + 1
if (current_row['end_day'] != undefined && day_number - 1 >= current_row['end_day']) ||
(current_row['start_day'] != undefined && day_number + 1 <= current_row['start_day'])
continue
if day_number < 10
day_number = '0' + day_number
# update total_hours and day hours
res = current_row.update_hours_by_event(day_number, event_id)
# set cell data
hot.setDataAtCell selected_day.row, selected_day.col, res
# update day event (and global)
table_data.set_event selected_day.row, selected_day.col, event_id, hot
month = currentMonth
if currentMonth < 10
month = '0' + currentMonth
occurs = currentYear + "-" + month + "-" + (day_number)
update.events.push [employee_project_id, occurs]
if update.events.length == 0
return
document.getElementById("status-line").innerHTML = I18n.t('extra.saving')
$.ajax
type: 'POST'
url: '/calendars/events'
data: {
data: JSON.stringify(update)
}
success: (responce) ->
document.getElementById("status-line").innerHTML = I18n.t('extra.all_saved')
error: (q, status, err)->
console.err q, status, err
document.getElementById("status-line").innerHTML = I18n.t('extra.error')
filtered_rows = table_data.filtrate emp_filt, proj_filt
hot.updateSettings
data: (new TableData filtered_rows).to_json()
# Check if event can be set on selected day
# @param [WalkontableCellCoords] selected_day
# @param [Integer] new_event_id
validate_event = (selected_day, new_event_id)->
row = table_data.get_row_by_index selected_day.row
day = row.get_day selected_day.col + 1
current_event_id = day.event_id
if current_event_id == new_event_id
return false
return true
deleteEvents = (selected_days)->
console.log 'deleteEvents'
employee_project_ids = []
min_day = 42
max_day = 0
for selected_day in selected_days
row = table_data.get_row_by_index(selected_day.row)
if row.type == 'project'
continue
employee_project_id = row.id
day_number = selected_day.col + 1
max_day = day_number if day_number > max_day
min_day = day_number if day_number < min_day
employee_project_ids.push employee_project_id
# update total_hours and day hours
res = row.update_hours_by_clear(day_number)
console.log('res', res)
# set cell data
table_data.clear_event selected_day.row, selected_day.col, hot
updateSumSelected(selected_day.row, selected_day.col,selected_day.row,selected_day.col)
day = row.get_day(day_number)
hot.render()
if employee_project_ids.length == 0
return
data = {
start_day: currentYear + "-" + currentMonth + "-" + min_day
end_day: currentYear + "-" + currentMonth + "-" + max_day
pe_ids: employee_project_ids
}
#TODO write changes to table_data
document.getElementById("status-line").innerHTML = I18n.t('extra.saving')
console.log data
$.ajax
type: 'DELETE'
url: '/calendars/events'
data: {
data: JSON.stringify(data)
}
success: (response) ->
document.getElementById("status-line").innerHTML = I18n.t('extra.all_saved')
error: (q, status, err)->
document.getElementById("status-line").innerHTML = I18n.t('extra.error')
console.err q, status, err
#
# Catch Ctrl+f and creates/removes search_field.
# While creating, keyup event is added.
#
$(window).keydown (e) ->
if (e.ctrlKey or e.metaKey) and e.keyCode == 70
e.preventDefault()
# alert 'ctrl+f pressed!'
filters_toggle()
sizeOfFilterFieldBox = 31
filters_toggle = () ->
filters = $("#filters")
filters.slideToggle 100, () ->
if filters.is(':visible')
hot.deselectCell()
setTimeout((() -> $('#employee-filter').focus()), 0)
hot.updateSettings {height: tableHeightByLength(hot.getData().length)}
filtrate = (emp_filt, proj_filt) ->
filtered_rows = table_data.filtrate emp_filt, proj_filt
console.log "new_length", tableHeightByLength(filtered_rows.length)
hot.updateSettings
data: (new TableData filtered_rows).to_json()
rowHeaders: filtered_rows.map (elem)->
elem.get_name()
height: tableHeightByLength(filtered_rows.length)
remove_week_numbers = ()->
$(".header-grouping").remove()
append_week_numbers = ()->
weeknumbers = @getWeekNumbers(currentYear, currentMonth)
#console.log "weeknumbers", weeknumbers
newHeaderRow = '<tr id="weeknumbers" class="header-grouping" style="' +
'height: 25px;width: ' + tableWidth() + 'px' +
'"><th></th>'
for w_number, d_count of weeknumbers
newHeaderRow += '<th colspan="' + d_count + '">' + w_number + '</th>'
i = 2
while i <= d_count
newHeaderRow += '<th class="hiddenHeader"/>'
i++
newHeaderRow += '<th>total<th>'
newHeaderRow += '</tr>'
$('#extra').find('thead').find('tr').before(newHeaderRow)
$('.header-grouping').each () ->
prevent(this)
cnt = 0
init_cnt = 0
act_show_row = 0
act_show_col = 0
$('#activity_show').on('hidden.bs.modal', ->
if (cnt > 0) && (init_cnt == 0)
draw_activity act_show_row, act_show_col, 'darkblue'
return
if (cnt == 0) && (init_cnt > 0)
remove_activity act_show_row, act_show_col
return
)
contextmenu_callback = (key, options) ->
col_number = options.start.col
row_number = options.start.row
selectedDays = hot.getSelectedRange().getAll()
event = Extradata.events.find (x, i,arr ) -> return x if x.name.replace(/\s+/g, '').toLocaleLowerCase() == key
switch key
when 'commentsAddEdit' then log_comments 'comments editing', key, options
when 'activities'
document.getElementById('act_body').innerHTML = ''
document.getElementById('act_show').innerHTML = ''
get_act =
employee_project_id: table_data.get_row_by_index(row_number).id
occurs: currentYear + '-' + currentMonth + '-' + (col_number + 1)
$.ajax
type: 'POST'
url: '/calendars/activities'
dataType: 'JSON'
data: 'get_act': JSON.stringify(get_act)
response: 'text'
success: (data) ->
# data - array of activities
# data[0] - types of activities
# data[cur][0] - type of current activity
# data[cur][1] - description of current activity
# data[cur][2] - cell_id
cnt = data.length - 1
init_cnt = data.length - 1
end = ''
if cnt == 1
end = 'y '
else
end = 'ies '
document.getElementById('act_show').innerHTML = cnt + ' activit' + end
body = document.createElement('div')
body.setAttribute 'style', 'max-height:300px; overflow: auto; '
add = document.createElement('button')
add.innerHTML = '+'
add.className = 'btn btn-small'
add.style.backgroundColor = '#ffffff'
add.style.fontSize = '20px'
add.style.fontWeight = 'bold'
add.style.color = '#1ab7ea'
body.appendChild add
body.appendChild document.createElement('br')
k = 1
while k <= cnt
tmp = document.createElement('div')
cross = document.createElement('span')
cross.className = 'glyphicon glyphicon-remove pull-right'
cross.id = k
cross.style.fontSize = '20px'
cross.style.color = '#f08080'
hr = document.createElement('hr')
br = document.createElement('br')
tmp.appendChild br
tmp.appendChild hr
tmp.appendChild cross
typeof_activity = document.createElement('p')
typeof_activity.innerHTML = data[k][0]
typeof_activity.setAttribute 'style', 'font-weight: bold; font-size: 22px; color: #1ab7ea;'
description_activity = document.createElement('p')
description_activity.innerHTML = data[k][1]
description_activity.setAttribute 'style', 'font-weight: bold; font-size: 16px; color: #000000;'
tmp.appendChild typeof_activity
tmp.appendChild description_activity
body.appendChild tmp
k++
open_add = false
body.onclick = (e) ->
target = e.target
if target.className == 'glyphicon glyphicon-remove pull-right'
if confirm('are you sure? ')
act_id = target.id
document.getElementById(act_id).parentNode.remove()
cnt = cnt - 1
if cnt == 1
end = 'y '
else
end = 'ies '
document.getElementById('act_show').innerHTML = cnt + ' activit' + end
destroy =
type: data[act_id][0]
description: data[act_id][1]
id: data[act_id][2]
$.ajax
type: 'POST'
url: '/calendars/activities'
dataType: 'JSON'
data: 'destroy': JSON.stringify(destroy)
return
return
if target.className == 'btn btn-small'
if open_add
if target.id == 'hide'
open_add = false
document.getElementById('body_add').remove()
document.getElementById('hide').remove()
add.innerHTML = '+'
add.style.fontSize = '20px'
add.style.width = 'auto'
return
else
row = table_data.get_row_by_index(row_number)
day_number = col_number + 1
type_id = document.getElementById('type_added')
description = document.getElementById('description')
if type_id.value == '0'
alert 'Select the type of activity, please'
else
if !(description.value == '' and !confirm('Description is empty. Are you sure?'))
$.ajax
type: 'POST'
url: '/calendars/activities'
data:
employee_project_id: row.id
occurs: currentYear + '-' + currentMonth + '-' + day_number
type: type_id.value
description: description.value
dataType: 'json'
success: (cell_id) ->
if cell_id == null
open_add = false
document.getElementById('body_add').remove()
document.getElementById('hide').remove()
add.innerHTML = '+'
add.style.fontSize = '20px'
add.style.width = 'auto'
return
open_add = false
cnt = cnt + 1
if cnt == 1
end = 'y '
else
end = 'ies '
tmp = document.createElement('div')
cross = document.createElement('span')
cross.className = 'glyphicon glyphicon-remove pull-right'
cross.id = cnt
cross.style.fontSize = '20px'
cross.style.color = '#f08080'
hr = document.createElement('hr')
br = document.createElement('br')
tmp.appendChild br
tmp.appendChild hr
tmp.appendChild cross
typeof_activity = document.createElement('p')
typeof_activity.innerHTML = type_id.options[type_id.selectedIndex].text
typeof_activity.setAttribute 'style', 'font-weight: bold; font-size: 22px; color: #1ab7ea;'
description_activity = document.createElement('p')
description_activity.innerHTML = description.value
description_activity.setAttribute 'style', 'font-weight: bold; font-size: 16px; color: #000000;'
tmp.appendChild typeof_activity
tmp.appendChild description_activity
body.appendChild tmp
data.push [
type_id.options[type_id.selectedIndex].text
description.value
cell_id
]
document.getElementById('act_show').innerHTML = cnt + ' activit' + end
document.getElementById('body_add').remove()
document.getElementById('hide').remove()
add.innerHTML = '+'
add.style.fontSize = '20px'
add.style.width = 'auto'
row.get_day(col_number + 1).activity = true
return
return
else
open_add = true
hide_add = document.createElement('button')
hide_add.id = 'hide'
hide_add.innerHTML = 'Hide'
hide_add.className = 'btn btn-small'
hide_add.style.backgroundColor = '#ffffff'
hide_add.style.fontSize = '15px'
hide_add.style.color = '#1ab7ea'
hide_add.style.width = '50%'
hide_add.style.fontWeight = 'bold'
selector = document.createElement('select')
selector.style = 'height: 2em; width: 25em'
selector.id = 'type_added'
option = document.createElement('option')
option.value = 0
option.selected = true
option.text = '...'
selector.appendChild option
body_add = document.createElement('div')
body_add.id = 'body_add'
type = undefined
type = 0
while type < data[0].length
option = document.createElement('option')
option.value = data[0][type][1]
option.text = data[0][type][0]
selector.appendChild option
type++
selector.style.color = 'black'
act_t = document.createElement('p')
act_t.innerHTML = 'Activity type: '
act_t.style.fontWeight = 'bold'
act_t.style.fontSize = '20px'
act_t.style.color = 'black'
body_add.appendChild act_t
body_add.appendChild selector
body_add.appendChild document.createElement('br')
body_add.appendChild document.createElement('br')
body_add.appendChild document.createElement('br')
desc = document.createElement('p')
desc.innerHTML = 'Description: '
desc.style.color = 'black'
desc.style.fontWeight = 'bold'
desc.style.fontSize = '20px'
body_add.appendChild desc
description = document.createElement('textarea')
description.cols = 5
description.rows = 5
description.id = 'description'
description.style = 'width: 25em;'
description.style.color = 'black'
description.placeholder = 'Type the description here'
body_add.appendChild description
add.style.width = '50%'
add.style.fontSize = '15px'
add.innerHTML = 'Add'
add.parentNode.insertBefore hide_add, add.nextSibling
hide_add.parentNode.insertBefore body_add, hide_add.nextSibling
return
return
document.getElementById('act_body').appendChild body
act_show_row = row_number
act_show_col = col_number
$('#activity_show').modal('show')
return
when 'comments_remove'
setTimeout (->
@delete_comment row_number, col_number
), 100
when "clearevent" then deleteEvents( selectedDays)
else setEvents selectedDays, event.id
createContextMenuItems = () ->
items = {}
items['commentsAddEdit'] = {
disabled: ()->
contextmenu_forbidden(hot.getSelected())
}
items['comments_remove'] = {
name: 'Delete comments'
# Disable 'delete comment' option if there is no comment in that day
disabled: ()->
contextmenu_forbidden(hot.getSelected())
}
items['hsep'] = {name: "---------"}
clearevent = Extradata.events.find (x, i,arr ) -> return x if x.name == "Clear Event"
items['clearevent'] = {
name: createContextMenuItem(clearevent.color, updateLabel(clearevent.name, clearevent.hotkey))
}
for event in Extradata.events
name = event.name.replace(/\s+/g, '').toLocaleLowerCase();
items[name] = {
'name': createContextMenuItem(event.color, updateLabel(event.name, event.hotkey))
disabled: ()->
contextmenu_forbidden(hot.getSelected())
}
items['activity_separator'] = {
'name': "---------"
};
items['activities'] = {
'name': 'Activities'
disabled: ()->
contextmenu_forbidden(hot.getSelected())
}
items
contextmenu_forbidden = (on_selected) ->
row_number = on_selected[0]
col = on_selected[1]
row = table_data.get_row_by_index(row_number)
project = (row.type == 'project')
maternity = false
if row['maternity']['exists']
maternity = ((col + 1) in [row['maternity']['index']..lastDayOfMonth(currentMonth, currentYear)] && row['maternity']['start']) ||
(!row['maternity']['start'] && (col + 1) in [1..row['maternity']['index']])
total = false
if col == columns.length - 1
total = !project
fired = (row.end_day != undefined && col >= row.end_day) || (row.start_day != undefined && col + 2 <= row.start_day)
project || maternity || fired || total
updateSumSelected = (begin_row, begin_column, end_row, end_column)->
sum = 0
for row_index in [begin_row..end_row]
for column in [begin_column..end_column]
row = table_data.get_row_by_index(row_index)
day = row.get_day(column + 1)
# selected cell is not a day, e.g. it is total_hours
if day == undefined
return
if (row.workload == undefined || row.workload == null) ||
type_of_day(day.day) != DayTypes.WORKDAY ||
(row['end_day'] != undefined || column >= row['end_day']) ||
(row['start_day'] != undefined && column + 2 <= row['start_day'])
workload = 0
else
workload = row.workload * 8 / 100
if !(isNaN(day.hours) || day.hours == null || day.hours == undefined)
hours = day.hours
else if day.event_id == 5 || day.event_id == 6 || day.event_id == 7
hours = 0
else
hours = workload
sum += parseFloat hours
if isFloat sum # check if is float. @see Number.isInteger in ES6 will be implemented in future
sum = sum.toFixed(1)
$("#selected_sum").html("<b>SUM: " + sum + "</b>")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment